Skip to content

Commit af50420

Browse files
cleverca22behlendorf
authored andcommitted
expose free space histograms in /proc
example output: ``` [root@nixos:~]# cat /proc/spl/kstat/zfs/vm/fragmentation_normal 9 19 10 49 11 24 12 38 13 21 14 17 15 12 16 2 17 2 27 15 ``` this allows graphing `zdb -MM` without any performance costs Signed-off-by: Michael Bishop <cleverca22@gmail.com>
1 parent e73ada7 commit af50420

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

include/sys/spa.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,7 @@ typedef struct spa_stats {
944944
spa_history_kstat_t state; /* pool state */
945945
spa_history_kstat_t guid; /* pool guid */
946946
spa_history_kstat_t iostats;
947+
spa_history_kstat_t fragmentation[6];
947948
} spa_stats_t;
948949

949950
typedef enum txg_state {

module/zfs/spa_stats.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <sys/vdev_impl.h>
2626
#include <sys/spa.h>
2727
#include <zfs_comutil.h>
28+
#include <sys/metaslab_impl.h>
2829

2930
/*
3031
* Keeps stats on last N reads per spa_t, disabled by default.
@@ -303,6 +304,107 @@ spa_txg_history_init(spa_t *spa)
303304
offsetof(spa_txg_history_t, sth_node));
304305
}
305306

307+
typedef struct {
308+
spa_t *spa;
309+
int metaclass;
310+
} freespace_histogram_stat_t;
311+
312+
static void *
313+
spa_frag_addr(kstat_t *ksp, loff_t n)
314+
{
315+
if (n == 0) {
316+
freespace_histogram_stat_t *stat = ksp->ks_private;
317+
switch (stat->metaclass) {
318+
case 0:
319+
return (spa_normal_class(stat->spa));
320+
case 1:
321+
return (spa_log_class(stat->spa));
322+
case 2:
323+
return (spa_embedded_log_class(stat->spa));
324+
case 3:
325+
return (spa_special_class(stat->spa));
326+
case 4:
327+
return (spa_dedup_class(stat->spa));
328+
case 5:
329+
return (spa_special_embedded_log_class(stat->spa));
330+
}
331+
}
332+
return (NULL);
333+
}
334+
335+
static int
336+
spa_frag_data(char *buf, size_t size, void *data)
337+
{
338+
metaslab_class_t *mc = data;
339+
size_t offset = 0;
340+
snprintf(buf+offset, size-offset, "bucket count\n");
341+
offset = strlen(buf);
342+
343+
mutex_enter(&mc->mc_lock);
344+
for (int i = 0; i < ZFS_RANGE_TREE_HISTOGRAM_SIZE; i++) {
345+
if (mc->mc_histogram[i] > 0) {
346+
snprintf(buf + offset, size - offset, "%d %llu\n", i,
347+
(u_longlong_t)mc->mc_histogram[i]);
348+
offset = strlen(buf);
349+
}
350+
}
351+
mutex_exit(&mc->mc_lock);
352+
353+
return (0);
354+
}
355+
356+
static void
357+
spa_fragmentation_init(spa_t *spa)
358+
{
359+
char *dirname;
360+
const char *statnames[] = {
361+
"class_normal_free_histogram",
362+
"class_log_free_histogram",
363+
"class_elog_free_histogram",
364+
"class_special_free_histogram",
365+
"class_dedup_free_histogram",
366+
"class_special_elog_free_histogram"
367+
};
368+
for (int i = 0; i < 6; i++) {
369+
spa_history_kstat_t *shk = &spa->spa_stats.fragmentation[i];
370+
kstat_t *ksp;
371+
372+
dirname = kmem_asprintf("zfs/%s", spa_name(spa));
373+
ksp = kstat_create(dirname, 0, statnames[i], "misc",
374+
KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
375+
kmem_strfree(dirname);
376+
377+
shk->kstat = ksp;
378+
if (ksp) {
379+
freespace_histogram_stat_t *stat = kmem_zalloc(
380+
sizeof (freespace_histogram_stat_t), KM_SLEEP);
381+
stat->spa = spa;
382+
stat->metaclass = i;
383+
ksp->ks_private = stat;
384+
ksp->ks_flags |= KSTAT_FLAG_NO_HEADERS;
385+
kstat_set_raw_ops(ksp, NULL, spa_frag_data,
386+
spa_frag_addr);
387+
kstat_install(ksp);
388+
}
389+
}
390+
}
391+
392+
static void
393+
spa_fragmentation_destroy(spa_t *spa)
394+
{
395+
for (int i = 0; i < 6; i++) {
396+
spa_history_kstat_t *shk = &spa->spa_stats.fragmentation[i];
397+
kstat_t *ksp = shk->kstat;
398+
if (ksp) {
399+
if (ksp->ks_private) {
400+
kmem_free(ksp->ks_private,
401+
sizeof (freespace_histogram_stat_t));
402+
}
403+
kstat_delete(ksp);
404+
}
405+
}
406+
}
407+
306408
static void
307409
spa_txg_history_destroy(spa_t *spa)
308410
{
@@ -1047,11 +1149,13 @@ spa_stats_init(spa_t *spa)
10471149
spa_state_init(spa);
10481150
spa_guid_init(spa);
10491151
spa_iostats_init(spa);
1152+
spa_fragmentation_init(spa);
10501153
}
10511154

10521155
void
10531156
spa_stats_destroy(spa_t *spa)
10541157
{
1158+
spa_fragmentation_destroy(spa);
10551159
spa_iostats_destroy(spa);
10561160
spa_health_destroy(spa);
10571161
spa_tx_assign_destroy(spa);

0 commit comments

Comments
 (0)