aboutsummaryrefslogtreecommitdiffstats
path: root/module/os
diff options
context:
space:
mode:
authorAlexander Motin <[email protected]>2023-11-07 14:35:40 -0500
committerBrian Behlendorf <[email protected]>2024-01-08 16:11:39 -0800
commitf13593619b074dff63f6940d32033d2f147166e3 (patch)
treeb000340fed3f6b3b179d6d98a00df87336bcf938 /module/os
parentc34fe8dcbcb710081d8927b76bab06dd43c20c8c (diff)
FreeBSD: Optimize large kstat outputs
- Use sbuf_new_for_sysctl() to reduce double-buffering on sysctl output. - Use much faster sbuf_cat() instead of sbuf_printf("%s"). Together it reduces `sysctl kstat.zfs.misc.dbufs` time from minutes to seconds, making dbufstat almost usable. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Sponsored by: iXsystems, Inc. Closes #15495
Diffstat (limited to 'module/os')
-rw-r--r--module/os/freebsd/spl/spl_kstat.c38
1 files changed, 16 insertions, 22 deletions
diff --git a/module/os/freebsd/spl/spl_kstat.c b/module/os/freebsd/spl/spl_kstat.c
index 9f5f92e19..43cd4da02 100644
--- a/module/os/freebsd/spl/spl_kstat.c
+++ b/module/os/freebsd/spl/spl_kstat.c
@@ -187,19 +187,18 @@ kstat_sysctl_dataset_string(SYSCTL_HANDLER_ARGS)
static int
kstat_sysctl_io(SYSCTL_HANDLER_ARGS)
{
- struct sbuf *sb;
+ struct sbuf sb;
kstat_t *ksp = arg1;
kstat_io_t *kip = ksp->ks_data;
int rc;
- sb = sbuf_new_auto();
- if (sb == NULL)
- return (ENOMEM);
+ sbuf_new_for_sysctl(&sb, NULL, 0, req);
+
/* Update the aggsums before reading */
(void) ksp->ks_update(ksp, KSTAT_READ);
/* though wlentime & friends are signed, they will never be negative */
- sbuf_printf(sb,
+ sbuf_printf(&sb,
"%-8llu %-8llu %-8u %-8u %-8llu %-8llu "
"%-8llu %-8llu %-8llu %-8llu %-8u %-8u\n",
kip->nread, kip->nwritten,
@@ -207,25 +206,21 @@ kstat_sysctl_io(SYSCTL_HANDLER_ARGS)
kip->wtime, kip->wlentime, kip->wlastupdate,
kip->rtime, kip->rlentime, kip->rlastupdate,
kip->wcnt, kip->rcnt);
- rc = sbuf_finish(sb);
- if (rc == 0)
- rc = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb));
- sbuf_delete(sb);
+ rc = sbuf_finish(&sb);
+ sbuf_delete(&sb);
return (rc);
}
static int
kstat_sysctl_raw(SYSCTL_HANDLER_ARGS)
{
- struct sbuf *sb;
+ struct sbuf sb;
void *data;
kstat_t *ksp = arg1;
void *(*addr_op)(kstat_t *ksp, loff_t index);
int n, has_header, rc = 0;
- sb = sbuf_new_auto();
- if (sb == NULL)
- return (ENOMEM);
+ sbuf_new_for_sysctl(&sb, NULL, PAGE_SIZE, req);
if (ksp->ks_raw_ops.addr)
addr_op = ksp->ks_raw_ops.addr;
@@ -258,8 +253,10 @@ restart_headers:
if (has_header) {
if (rc == ENOMEM && !kstat_resize_raw(ksp))
goto restart_headers;
- if (rc == 0)
- sbuf_printf(sb, "\n%s", ksp->ks_raw_buf);
+ if (rc == 0) {
+ sbuf_cat(&sb, "\n");
+ sbuf_cat(&sb, ksp->ks_raw_buf);
+ }
}
while ((data = addr_op(ksp, n)) != NULL) {
@@ -270,22 +267,19 @@ restart:
if (rc == ENOMEM && !kstat_resize_raw(ksp))
goto restart;
if (rc == 0)
- sbuf_printf(sb, "%s", ksp->ks_raw_buf);
+ sbuf_cat(&sb, ksp->ks_raw_buf);
} else {
ASSERT3U(ksp->ks_ndata, ==, 1);
- sbuf_hexdump(sb, ksp->ks_data,
+ sbuf_hexdump(&sb, ksp->ks_data,
ksp->ks_data_size, NULL, 0);
}
n++;
}
free(ksp->ks_raw_buf, M_TEMP);
mutex_exit(ksp->ks_lock);
- sbuf_trim(sb);
- rc = sbuf_finish(sb);
- if (rc == 0)
- rc = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb));
- sbuf_delete(sb);
+ rc = sbuf_finish(&sb);
+ sbuf_delete(&sb);
return (rc);
}