diff --git a/include/jemalloc/internal/emitter.h b/include/jemalloc/internal/emitter.h index 359077e6..10082ec7 100644 --- a/include/jemalloc/internal/emitter.h +++ b/include/jemalloc/internal/emitter.h @@ -591,13 +591,12 @@ emitter_sparse_row(emitter_t *emitter, emitter_row_t *row, bool is_gap) { } /* - * Descriptor-driven column tables. A descriptor array defines table order; - * callers provide a separate index array when JSON requires a different - * subset or ordering. The getter lets one engine serve different row types - * while keeping derived values (rates, utilization, and so on) with the - * table-specific code. A column is active when all its required_flags are - * present in the active_flags supplied by the caller; the emitter assigns no - * domain-specific meaning to those bits. + * Descriptor-driven column tables. A descriptor array defines table and JSON + * order; columns with a NULL json_key are table-only. The getter lets one + * engine serve different row types while keeping derived values (rates, + * utilization, and so on) with the table-specific code. A column is active + * when all its required_flags are present in the active_flags supplied by the + * caller; the emitter assigns no domain-specific meaning to those bits. */ typedef struct emitter_col_desc_s emitter_col_desc_t; struct emitter_col_desc_s { @@ -666,17 +665,18 @@ emitter_col_table_fill(const emitter_col_desc_t *descs, size_t ndescs, static inline void emitter_col_table_emit_json(emitter_t *emitter, const emitter_col_desc_t *descs, size_t ndescs, unsigned active_flags, - emitter_col_t *cols, const unsigned *json_order, size_t json_order_len) { - for (size_t i = 0; i < json_order_len; i++) { - unsigned col_ind = json_order[i]; - assert(col_ind < ndescs); - const emitter_col_desc_t *desc = &descs[col_ind]; + emitter_col_t *cols) { + for (size_t i = 0; i < ndescs; i++) { + const emitter_col_desc_t *desc = &descs[i]; if (!emitter_col_desc_active(desc, active_flags)) { continue; } - assert(desc->json_key != NULL); - emitter_json_kv(emitter, desc->json_key, cols[col_ind].type, - (const void *)&cols[col_ind].bool_val); + if (desc->json_key != NULL) { + emitter_type_t json_type = cols[i].type == emitter_type_title + ? emitter_type_string : cols[i].type; + emitter_json_kv(emitter, desc->json_key, json_type, + (const void *)&cols[i].bool_val); + } } } diff --git a/src/stats.c b/src/stats.c index 8ae8ca94..876f7ec8 100644 --- a/src/stats.c +++ b/src/stats.c @@ -782,54 +782,27 @@ stats_bin_col_get_util(const void *vrow, emitter_col_t *col) { col->str_val = row->util; } -enum { - BIN_COL_SIZE, - BIN_COL_IND, - BIN_COL_ALLOCATED, - BIN_COL_NMALLOC, - BIN_COL_NMALLOC_PS, - BIN_COL_NDALLOC, - BIN_COL_NDALLOC_PS, - BIN_COL_NREQUESTS, - BIN_COL_NREQUESTS_PS, - BIN_COL_PROF_LIVE_REQUESTED, - BIN_COL_PROF_LIVE_COUNT, - BIN_COL_PROF_ACCUM_REQUESTED, - BIN_COL_PROF_ACCUM_COUNT, - BIN_COL_NSHARDS, - BIN_COL_CURREGS, - BIN_COL_CURSLABS, - BIN_COL_NONFULL_SLABS, - BIN_COL_REGS, - BIN_COL_PGS, - BIN_COL_SPACER, - BIN_COL_UTIL, - BIN_COL_NFILLS, - BIN_COL_NFILLS_PS, - BIN_COL_NFLUSHES, - BIN_COL_NFLUSHES_PS, - BIN_COL_NSLABS, - BIN_COL_NRESLABS, - BIN_COL_NRESLABS_PS, - BIN_COL_COUNT -}; +#define BIN_COL_SIZE 0 #define BIN_DESC(key, label, width, type, flags, name) \ {key, label, emitter_justify_right, width, emitter_type_##type, flags, \ stats_bin_col_get_##name} static const emitter_col_desc_t stats_bin_cols[] = { - BIN_DESC(NULL, "size", 20, size, STATS_COL_FLAG_NONE, size), - BIN_DESC(NULL, "ind", 4, unsigned, STATS_COL_FLAG_NONE, ind), - BIN_DESC(NULL, "allocated", 14, size, STATS_COL_FLAG_NONE, allocated), + BIN_DESC("size", "size", 20, size, STATS_COL_FLAG_NONE, size), + BIN_DESC("ind", "ind", 4, unsigned, STATS_COL_FLAG_NONE, ind), + BIN_DESC("allocated", "allocated", 14, size, STATS_COL_FLAG_NONE, + allocated), BIN_DESC("nmalloc", "nmalloc", 14, uint64, STATS_COL_FLAG_NONE, nmalloc), - BIN_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, nmalloc_ps), + BIN_DESC("nmalloc_ps", "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, + nmalloc_ps), BIN_DESC("ndalloc", "ndalloc", 14, uint64, STATS_COL_FLAG_NONE, ndalloc), - BIN_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, ndalloc_ps), + BIN_DESC("ndalloc_ps", "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, + ndalloc_ps), BIN_DESC("nrequests", "nrequests", 15, uint64, STATS_COL_FLAG_NONE, nrequests), - BIN_DESC(NULL, "(#/sec)", 10, uint64, STATS_COL_FLAG_NONE, + BIN_DESC("nrequests_ps", "(#/sec)", 10, uint64, STATS_COL_FLAG_NONE, nrequests_ps), BIN_DESC("prof_live_requested", "prof_live_requested", 21, uint64, STATS_COL_FLAG_PROF, prof_live_requested), @@ -839,48 +812,33 @@ static const emitter_col_desc_t stats_bin_cols[] = { STATS_COL_FLAG_PROF, prof_accum_requested), BIN_DESC("prof_accum_count", "prof_accum_count", 17, uint64, STATS_COL_FLAG_PROF, prof_accum_count), - BIN_DESC(NULL, "nshards", 9, unsigned, STATS_COL_FLAG_NONE, nshards), + BIN_DESC("nshards", "nshards", 9, unsigned, STATS_COL_FLAG_NONE, + nshards), BIN_DESC("curregs", "curregs", 13, size, STATS_COL_FLAG_NONE, curregs), BIN_DESC("curslabs", "curslabs", 13, size, STATS_COL_FLAG_NONE, curslabs), BIN_DESC("nonfull_slabs", "nonfull_slabs", 15, size, STATS_COL_FLAG_NONE, nonfull_slabs), - BIN_DESC(NULL, "regs", 5, unsigned, STATS_COL_FLAG_NONE, regs), - BIN_DESC(NULL, "pgs", 4, size, STATS_COL_FLAG_NONE, pgs), + BIN_DESC("regs", "regs", 5, unsigned, STATS_COL_FLAG_NONE, regs), + BIN_DESC("pgs", "pgs", 4, size, STATS_COL_FLAG_NONE, pgs), BIN_DESC(NULL, " ", 1, title, STATS_COL_FLAG_NONE, spacer), - BIN_DESC(NULL, "util", 6, title, STATS_COL_FLAG_NONE, util), + BIN_DESC("util", "util", 6, title, STATS_COL_FLAG_NONE, util), BIN_DESC("nfills", "nfills", 13, uint64, STATS_COL_FLAG_NONE, nfills), - BIN_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, nfills_ps), + BIN_DESC("nfills_ps", "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, + nfills_ps), BIN_DESC("nflushes", "nflushes", 13, uint64, STATS_COL_FLAG_NONE, nflushes), - BIN_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, + BIN_DESC("nflushes_ps", "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, nflushes_ps), - BIN_DESC(NULL, "nslabs", 13, uint64, STATS_COL_FLAG_NONE, nslabs), + BIN_DESC("nslabs", "nslabs", 13, uint64, STATS_COL_FLAG_NONE, nslabs), BIN_DESC("nreslabs", "nreslabs", 13, uint64, STATS_COL_FLAG_NONE, nreslabs), - BIN_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, + BIN_DESC("nreslabs_ps", "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, nreslabs_ps), }; #undef BIN_DESC -_Static_assert(sizeof(stats_bin_cols) / sizeof(stats_bin_cols[0]) == - BIN_COL_COUNT, "stats_bin_cols must match BIN_COL_COUNT"); - -static const unsigned stats_bin_json_order[] = { - BIN_COL_NMALLOC, - BIN_COL_NDALLOC, - BIN_COL_CURREGS, - BIN_COL_NREQUESTS, - BIN_COL_PROF_LIVE_REQUESTED, - BIN_COL_PROF_LIVE_COUNT, - BIN_COL_PROF_ACCUM_REQUESTED, - BIN_COL_PROF_ACCUM_COUNT, - BIN_COL_NFILLS, - BIN_COL_NFLUSHES, - BIN_COL_NRESLABS, - BIN_COL_CURSLABS, - BIN_COL_NONFULL_SLABS, -}; +#define BIN_COL_COUNT (sizeof(stats_bin_cols) / sizeof(stats_bin_cols[0])) static void stats_emit_arena_bin_row(emitter_t *emitter, emitter_row_t *table_row, @@ -892,8 +850,7 @@ stats_emit_arena_bin_row(emitter_t *emitter, emitter_row_t *table_row, stats_bin_cols, BIN_COL_COUNT, active_flags, cols, row); emitter_json_object_begin(emitter); emitter_col_table_emit_json(emitter, stats_bin_cols, BIN_COL_COUNT, - active_flags, cols, stats_bin_json_order, - sizeof(stats_bin_json_order) / sizeof(stats_bin_json_order[0])); + active_flags, cols); if (mutex) { emitter_json_object_kv_begin(emitter, "mutex"); mutex_stats_emit(emitter, NULL, mutex64, mutex32); @@ -1068,41 +1025,29 @@ stats_lextent_col_get_allocated(const void *vrow, emitter_col_t *col) { col->size_val = row->lextent->curlextents * row->lextent->lextent_size; } -enum { - LEXTENT_COL_SIZE, - LEXTENT_COL_IND, - LEXTENT_COL_ALLOCATED, - LEXTENT_COL_NMALLOC, - LEXTENT_COL_NMALLOC_PS, - LEXTENT_COL_NDALLOC, - LEXTENT_COL_NDALLOC_PS, - LEXTENT_COL_NREQUESTS, - LEXTENT_COL_NREQUESTS_PS, - LEXTENT_COL_PROF_LIVE_REQUESTED, - LEXTENT_COL_PROF_LIVE_COUNT, - LEXTENT_COL_PROF_ACCUM_REQUESTED, - LEXTENT_COL_PROF_ACCUM_COUNT, - LEXTENT_COL_CURLEXTENTS, - LEXTENT_COL_COUNT -}; +#define LEXTENT_COL_SIZE 0 #define LEXTENT_DESC(key, label, width, type, flags, name) \ {key, label, emitter_justify_right, width, emitter_type_##type, flags, \ stats_lextent_col_get_##name} static const emitter_col_desc_t stats_lextent_cols[] = { - LEXTENT_DESC(NULL, "size", 20, size, STATS_COL_FLAG_NONE, size), - LEXTENT_DESC(NULL, "ind", 4, unsigned, STATS_COL_FLAG_NONE, ind), - LEXTENT_DESC(NULL, "allocated", 13, size, STATS_COL_FLAG_NONE, + LEXTENT_DESC("size", "size", 20, size, STATS_COL_FLAG_NONE, size), + LEXTENT_DESC("ind", "ind", 4, unsigned, STATS_COL_FLAG_NONE, ind), + LEXTENT_DESC("allocated", "allocated", 13, size, STATS_COL_FLAG_NONE, allocated), - LEXTENT_DESC(NULL, "nmalloc", 13, uint64, STATS_COL_FLAG_NONE, nmalloc), - LEXTENT_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, + LEXTENT_DESC("nmalloc", "nmalloc", 13, uint64, STATS_COL_FLAG_NONE, + nmalloc), + LEXTENT_DESC("nmalloc_ps", "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, nmalloc_ps), - LEXTENT_DESC(NULL, "ndalloc", 13, uint64, STATS_COL_FLAG_NONE, ndalloc), - LEXTENT_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, + LEXTENT_DESC("ndalloc", "ndalloc", 13, uint64, STATS_COL_FLAG_NONE, + ndalloc), + LEXTENT_DESC("ndalloc_ps", "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, ndalloc_ps), - LEXTENT_DESC(NULL, "nrequests", 13, uint64, STATS_COL_FLAG_NONE, + LEXTENT_DESC("nrequests", "nrequests", 13, uint64, + STATS_COL_FLAG_NONE, nrequests), - LEXTENT_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE, + LEXTENT_DESC("nrequests_ps", "(#/sec)", 8, uint64, + STATS_COL_FLAG_NONE, nrequests_ps), LEXTENT_DESC("prof_live_requested", "prof_live_requested", 21, uint64, STATS_COL_FLAG_PROF, prof_live_requested), @@ -1116,16 +1061,8 @@ static const emitter_col_desc_t stats_lextent_cols[] = { STATS_COL_FLAG_NONE, curlextents), }; #undef LEXTENT_DESC -_Static_assert(sizeof(stats_lextent_cols) / sizeof(stats_lextent_cols[0]) == - LEXTENT_COL_COUNT, "stats_lextent_cols must match LEXTENT_COL_COUNT"); - -static const unsigned stats_lextent_json_order[] = { - LEXTENT_COL_PROF_LIVE_REQUESTED, - LEXTENT_COL_PROF_LIVE_COUNT, - LEXTENT_COL_PROF_ACCUM_REQUESTED, - LEXTENT_COL_PROF_ACCUM_COUNT, - LEXTENT_COL_CURLEXTENTS, -}; +#define LEXTENT_COL_COUNT \ + (sizeof(stats_lextent_cols) / sizeof(stats_lextent_cols[0])) static void stats_emit_arena_lextent_row(emitter_t *emitter, emitter_row_t *table_row, @@ -1134,16 +1071,14 @@ stats_emit_arena_lextent_row(emitter_t *emitter, emitter_row_t *table_row, unsigned active_flags = stats_col_active_flags(prof_stats_on); emitter_col_table_fill(stats_lextent_cols, LEXTENT_COL_COUNT, active_flags, cols, row); + emitter_json_object_begin(emitter); + emitter_col_table_emit_json(emitter, stats_lextent_cols, + LEXTENT_COL_COUNT, active_flags, cols); + emitter_json_object_end(emitter); char size_buf[48]; stats_size_col_set(&cols[LEXTENT_COL_SIZE], row->lextent->lextent_size, prev_size, size_buf, sizeof(size_buf)); - emitter_json_object_begin(emitter); - emitter_col_table_emit_json(emitter, stats_lextent_cols, - LEXTENT_COL_COUNT, active_flags, cols, stats_lextent_json_order, - sizeof(stats_lextent_json_order) / - sizeof(stats_lextent_json_order[0])); emitter_table_sparse_row(emitter, table_row, is_gap); - emitter_json_object_end(emitter); } JEMALLOC_COLD @@ -1241,29 +1176,15 @@ stats_extent_col_get_ind(const void *vrow, emitter_col_t *col) { col->unsigned_val = row->ind; } -enum { - EXTENT_COL_SIZE, - EXTENT_COL_IND, - EXTENT_COL_NDIRTY, - EXTENT_COL_DIRTY, - EXTENT_COL_NMUZZY, - EXTENT_COL_MUZZY, - EXTENT_COL_NRETAINED, - EXTENT_COL_RETAINED, - EXTENT_COL_NPINNED, - EXTENT_COL_PINNED, - EXTENT_COL_NTOTAL, - EXTENT_COL_TOTAL, - EXTENT_COL_COUNT -}; +#define EXTENT_COL_SIZE 0 #define EXTENT_DESC(key, label, name) \ {key, label, emitter_justify_right, 13, emitter_type_size, \ STATS_COL_FLAG_NONE, stats_extent_col_get_##name} static const emitter_col_desc_t stats_extent_cols[] = { - {NULL, "size", emitter_justify_right, 20, emitter_type_size, + {"size", "size", emitter_justify_right, 20, emitter_type_size, STATS_COL_FLAG_NONE, stats_extent_col_get_size}, - {NULL, "ind", emitter_justify_right, 4, emitter_type_unsigned, + {"ind", "ind", emitter_justify_right, 4, emitter_type_unsigned, STATS_COL_FLAG_NONE, stats_extent_col_get_ind}, EXTENT_DESC("ndirty", "ndirty", ndirty), EXTENT_DESC("dirty_bytes", "dirty", dirty), @@ -1273,23 +1194,12 @@ static const emitter_col_desc_t stats_extent_cols[] = { EXTENT_DESC("retained_bytes", "retained", retained), EXTENT_DESC("npinned", "npinned", npinned), EXTENT_DESC("pinned_bytes", "pinned", pinned), - EXTENT_DESC(NULL, "ntotal", ntotal), - EXTENT_DESC(NULL, "total", total), + EXTENT_DESC("ntotal", "ntotal", ntotal), + EXTENT_DESC("total_bytes", "total", total), }; #undef EXTENT_DESC -_Static_assert(sizeof(stats_extent_cols) / sizeof(stats_extent_cols[0]) == - EXTENT_COL_COUNT, "stats_extent_cols must match EXTENT_COL_COUNT"); - -static const unsigned stats_extent_json_order[] = { - EXTENT_COL_NDIRTY, - EXTENT_COL_NMUZZY, - EXTENT_COL_NRETAINED, - EXTENT_COL_NPINNED, - EXTENT_COL_DIRTY, - EXTENT_COL_MUZZY, - EXTENT_COL_RETAINED, - EXTENT_COL_PINNED, -}; +#define EXTENT_COL_COUNT \ + (sizeof(stats_extent_cols) / sizeof(stats_extent_cols[0])) static void stats_emit_arena_extent_row(emitter_t *emitter, emitter_row_t *table_row, @@ -1297,15 +1207,13 @@ stats_emit_arena_extent_row(emitter_t *emitter, emitter_row_t *table_row, size_t prev_size, bool is_gap) { emitter_col_table_fill(stats_extent_cols, EXTENT_COL_COUNT, STATS_COL_FLAG_NONE, cols, row); + emitter_json_object_begin(emitter); + emitter_col_table_emit_json(emitter, stats_extent_cols, EXTENT_COL_COUNT, + STATS_COL_FLAG_NONE, cols); + emitter_json_object_end(emitter); char size_buf[48]; stats_size_col_set(&cols[EXTENT_COL_SIZE], row->size, prev_size, size_buf, sizeof(size_buf)); - emitter_json_object_begin(emitter); - emitter_col_table_emit_json(emitter, stats_extent_cols, EXTENT_COL_COUNT, - STATS_COL_FLAG_NONE, cols, stats_extent_json_order, - sizeof(stats_extent_json_order) / - sizeof(stats_extent_json_order[0])); - emitter_json_object_end(emitter); emitter_table_sparse_row(emitter, table_row, is_gap); } @@ -1573,26 +1481,15 @@ stats_hpa_slab_col_get_ind(const void *vrow, emitter_col_t *col) { } } -enum { - HPA_SLAB_COL_SIZE, - HPA_SLAB_COL_IND, - HPA_SLAB_COL_NPAGESLABS_HUGE, - HPA_SLAB_COL_NACTIVE_HUGE, - HPA_SLAB_COL_NDIRTY_HUGE, - HPA_SLAB_COL_NPAGESLABS_NONHUGE, - HPA_SLAB_COL_NACTIVE_NONHUGE, - HPA_SLAB_COL_NDIRTY_NONHUGE, - HPA_SLAB_COL_NRETAINED_NONHUGE, - HPA_SLAB_COL_COUNT -}; +#define HPA_SLAB_COL_SIZE 0 #define HPA_SLAB_DESC(name, width) \ {#name, #name, emitter_justify_right, width, emitter_type_size, \ STATS_COL_FLAG_NONE, stats_hpa_slab_col_get_##name} static const emitter_col_desc_t stats_hpa_slab_cols[] = { - {NULL, "size", emitter_justify_right, 20, emitter_type_size, + {"size", "size", emitter_justify_right, 20, emitter_type_size, STATS_COL_FLAG_NONE, stats_hpa_slab_col_get_size}, - {NULL, "ind", emitter_justify_right, 4, emitter_type_unsigned, + {"ind", "ind", emitter_justify_right, 4, emitter_type_unsigned, STATS_COL_FLAG_NONE, stats_hpa_slab_col_get_ind}, HPA_SLAB_DESC(npageslabs_huge, 16), HPA_SLAB_DESC(nactive_huge, 16), @@ -1603,20 +1500,8 @@ static const emitter_col_desc_t stats_hpa_slab_cols[] = { HPA_SLAB_DESC(nretained_nonhuge, 20), }; #undef HPA_SLAB_DESC -_Static_assert( - sizeof(stats_hpa_slab_cols) / sizeof(stats_hpa_slab_cols[0]) == - HPA_SLAB_COL_COUNT, - "stats_hpa_slab_cols must match HPA_SLAB_COL_COUNT"); - -static const unsigned stats_hpa_slab_json_order[] = { - HPA_SLAB_COL_NPAGESLABS_HUGE, - HPA_SLAB_COL_NACTIVE_HUGE, - HPA_SLAB_COL_NDIRTY_HUGE, - HPA_SLAB_COL_NPAGESLABS_NONHUGE, - HPA_SLAB_COL_NACTIVE_NONHUGE, - HPA_SLAB_COL_NDIRTY_NONHUGE, - HPA_SLAB_COL_NRETAINED_NONHUGE, -}; +#define HPA_SLAB_COL_COUNT \ + (sizeof(stats_hpa_slab_cols) / sizeof(stats_hpa_slab_cols[0])) static void stats_emit_arena_hpa_slab_row(emitter_t *emitter, @@ -1625,22 +1510,19 @@ stats_emit_arena_hpa_slab_row(emitter_t *emitter, bool sparse, bool is_gap) { emitter_col_table_fill(stats_hpa_slab_cols, HPA_SLAB_COL_COUNT, STATS_COL_FLAG_NONE, cols, row); - char size_buf[48]; - if (row->size_title == NULL) { - stats_size_col_set(&cols[HPA_SLAB_COL_SIZE], row->size, - row->prev_size, size_buf, sizeof(size_buf)); - } if (json_key != NULL) { emitter_json_object_kv_begin(emitter, json_key); } else { emitter_json_object_begin(emitter); } emitter_col_table_emit_json(emitter, stats_hpa_slab_cols, - HPA_SLAB_COL_COUNT, STATS_COL_FLAG_NONE, cols, - stats_hpa_slab_json_order, - sizeof(stats_hpa_slab_json_order) / - sizeof(stats_hpa_slab_json_order[0])); + HPA_SLAB_COL_COUNT, STATS_COL_FLAG_NONE, cols); emitter_json_object_end(emitter); + char size_buf[48]; + if (row->size_title == NULL) { + stats_size_col_set(&cols[HPA_SLAB_COL_SIZE], row->size, + row->prev_size, size_buf, sizeof(size_buf)); + } if (sparse) { emitter_table_sparse_row(emitter, table_row, is_gap); } else { diff --git a/test/unit/emitter.c b/test/unit/emitter.c index e7728563..3cfcf5d5 100644 --- a/test/unit/emitter.c +++ b/test/unit/emitter.c @@ -669,10 +669,11 @@ static const char *sparse_row_table = " ---\n"; typedef struct { - size_t size; - uint64_t count; - uint64_t prof_count; - uint64_t requests; + size_t size; + uint64_t count; + uint64_t prof_count; + const char *label; + uint64_t requests; } col_table_test_row_t; #define COL_TABLE_TEST_GETTER(name, member, value_member) \ @@ -684,6 +685,7 @@ typedef struct { COL_TABLE_TEST_GETTER(size, size, size_val) COL_TABLE_TEST_GETTER(count, count, uint64_val) COL_TABLE_TEST_GETTER(prof_count, prof_count, uint64_val) +COL_TABLE_TEST_GETTER(label, label, str_val) COL_TABLE_TEST_GETTER(requests, requests, uint64_val) #undef COL_TABLE_TEST_GETTER @@ -691,6 +693,7 @@ enum { COL_TABLE_TEST_SIZE, COL_TABLE_TEST_COUNT, COL_TABLE_TEST_PROF_COUNT, + COL_TABLE_TEST_LABEL, COL_TABLE_TEST_REQUESTS, COL_TABLE_TEST_NCOLS }; @@ -704,6 +707,8 @@ static const emitter_col_desc_t col_table_test_descs[] = { 0, col_table_test_get_count}, {"prof_count", "prof", emitter_justify_right, 6, emitter_type_uint64, COL_TABLE_TEST_FLAG_PROF, col_table_test_get_prof_count}, + {"label", "label", emitter_justify_right, 7, emitter_type_title, 0, + col_table_test_get_label}, {"requests", "requests", emitter_justify_right, 10, emitter_type_uint64, 0, col_table_test_get_requests}, }; @@ -726,15 +731,9 @@ TEST_BEGIN(test_col_desc_flags) { } TEST_END -static const unsigned col_table_test_json_order[] = { - COL_TABLE_TEST_REQUESTS, - COL_TABLE_TEST_PROF_COUNT, - COL_TABLE_TEST_COUNT, -}; - static void emit_col_table(emitter_t *emitter) { - col_table_test_row_t value = {42, 7, 100, 9}; + col_table_test_row_t value = {42, 7, 100, "row", 9}; emitter_row_t row, header_row; emitter_col_t cols[COL_TABLE_TEST_NCOLS]; emitter_col_t header_cols[COL_TABLE_TEST_NCOLS]; @@ -748,9 +747,7 @@ emit_col_table(emitter_t *emitter) { COL_TABLE_TEST_FLAG_PROF, cols, &value); emitter_json_object_begin(emitter); emitter_col_table_emit_json(emitter, col_table_test_descs, - COL_TABLE_TEST_NCOLS, COL_TABLE_TEST_FLAG_PROF, cols, - col_table_test_json_order, sizeof(col_table_test_json_order) / - sizeof(col_table_test_json_order[0])); + COL_TABLE_TEST_NCOLS, COL_TABLE_TEST_FLAG_PROF, cols); emitter_json_object_end(emitter); emitter_table_row(emitter, &row); emitter_json_array_end(emitter); @@ -761,17 +758,19 @@ static const char *col_table_json = "{\n" "\t\"rows\": [\n" "\t\t{\n" - "\t\t\t\"requests\": 9,\n" + "\t\t\t\"count\": 7,\n" "\t\t\t\"prof_count\": 100,\n" - "\t\t\t\"count\": 7\n" + "\t\t\t\"label\": \"row\",\n" + "\t\t\t\"requests\": 9\n" "\t\t}\n" "\t]\n" "}\n"; static const char *col_table_json_compact = - "{\"rows\":[{\"requests\":9,\"prof_count\":100,\"count\":7}]}"; + "{\"rows\":[{\"count\":7,\"prof_count\":100,\"label\":\"row\"," + "\"requests\":9}]}"; static const char *col_table_table = - "mock:size count prof requests\n" - " 42 7 100 9\n"; + "mock:size count prof label requests\n" + " 42 7 100 row 9\n"; #define GENERATE_TEST(feature) \ TEST_BEGIN(test_##feature) { \ diff --git a/test/unit/json_stats.c b/test/unit/json_stats.c index 11b397d9..8a3ac621 100644 --- a/test/unit/json_stats.c +++ b/test/unit/json_stats.c @@ -288,6 +288,70 @@ json_find_named_array( return array_begin; } +static void +expect_json_keys_before(const char *begin, const char *end, + const char *const *keys, size_t nkeys, const char *section_name) { + for (size_t i = 0; i < nkeys; i++) { + char search_key[128]; + size_t written = malloc_snprintf( + search_key, sizeof(search_key), "\"%s\":", keys[i]); + expect_zu_lt(written, sizeof(search_key), "JSON key is too long"); + const char *found = strstr(begin, search_key); + expect_true(found != NULL && found < end, + "%s should contain %s", section_name, keys[i]); + } +} + +TEST_BEGIN(test_json_stats_table_columns) { + test_skip_if(!config_stats); + + uint64_t epoch = 1; + expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), + 0, "Unexpected mallctl() failure"); + + stats_buf_t sbuf; + stats_buf_init(&sbuf); + malloc_stats_print(stats_buf_write_cb, &sbuf, "Ja"); + + const char *bins_end = NULL; + const char *bins = json_find_named_array(sbuf.buf, "bins", &bins_end); + expect_ptr_not_null(bins, "JSON output should contain bins"); + const char *bin_keys[] = {"size", "ind", "allocated", "nmalloc_ps", + "nshards", "regs", "pgs", "util", "nslabs"}; + expect_json_keys_before(bins, bins_end, bin_keys, + sizeof(bin_keys) / sizeof(bin_keys[0]), "bins"); + + const char *lextents_end = NULL; + const char *lextents = json_find_named_array( + sbuf.buf, "lextents", &lextents_end); + expect_ptr_not_null(lextents, "JSON output should contain lextents"); + const char *lextent_keys[] = {"size", "ind", "allocated", "nmalloc", + "nmalloc_ps", "ndalloc", "ndalloc_ps", "nrequests", + "nrequests_ps"}; + expect_json_keys_before(lextents, lextents_end, lextent_keys, + sizeof(lextent_keys) / sizeof(lextent_keys[0]), "lextents"); + + const char *extents_end = NULL; + const char *extents = json_find_named_array( + sbuf.buf, "extents", &extents_end); + expect_ptr_not_null(extents, "JSON output should contain extents"); + const char *extent_keys[] = {"size", "ind", "ntotal", "total_bytes"}; + expect_json_keys_before(extents, extents_end, extent_keys, + sizeof(extent_keys) / sizeof(extent_keys[0]), "extents"); + + const char *full_slabs_end = NULL; + const char *full_slabs = json_find_named_object( + sbuf.buf, "full_slabs", &full_slabs_end); + expect_ptr_not_null( + full_slabs, "JSON output should contain full_slabs"); + const char *hpa_keys[] = {"size", "ind"}; + expect_json_keys_before(full_slabs, full_slabs_end, hpa_keys, + sizeof(hpa_keys) / sizeof(hpa_keys[0]), "full_slabs"); + + stats_buf_fini(&sbuf); +} +TEST_END + TEST_BEGIN(test_json_stats_mutexes) { test_skip_if(!config_stats); @@ -502,7 +566,8 @@ TEST_END int main(void) { - return test_no_reentrancy(test_json_stats_mutexes, + return test_no_reentrancy(test_json_stats_table_columns, + test_json_stats_mutexes, test_hpa_shard_json_ndirty_huge, test_hpa_shard_json_contains_sec_stats, test_hpa_shard_json_contains_retained_stats);