mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-07-22 04:03:11 +00:00
Expose stats table columns in JSON output and simplify code
This commit is contained in:
@@ -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;
|
* Descriptor-driven column tables. A descriptor array defines table and JSON
|
||||||
* callers provide a separate index array when JSON requires a different
|
* order; columns with a NULL json_key are table-only. The getter lets one
|
||||||
* subset or ordering. The getter lets one engine serve different row types
|
* engine serve different row types while keeping derived values (rates,
|
||||||
* while keeping derived values (rates, utilization, and so on) with the
|
* utilization, and so on) with the table-specific code. A column is active
|
||||||
* table-specific code. A column is active when all its required_flags are
|
* when all its required_flags are present in the active_flags supplied by the
|
||||||
* present in the active_flags supplied by the caller; the emitter assigns no
|
* caller; the emitter assigns no domain-specific meaning to those bits.
|
||||||
* domain-specific meaning to those bits.
|
|
||||||
*/
|
*/
|
||||||
typedef struct emitter_col_desc_s emitter_col_desc_t;
|
typedef struct emitter_col_desc_s emitter_col_desc_t;
|
||||||
struct emitter_col_desc_s {
|
struct emitter_col_desc_s {
|
||||||
@@ -666,20 +665,21 @@ emitter_col_table_fill(const emitter_col_desc_t *descs, size_t ndescs,
|
|||||||
static inline void
|
static inline void
|
||||||
emitter_col_table_emit_json(emitter_t *emitter,
|
emitter_col_table_emit_json(emitter_t *emitter,
|
||||||
const emitter_col_desc_t *descs, size_t ndescs, unsigned active_flags,
|
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) {
|
emitter_col_t *cols) {
|
||||||
if (!emitter_outputs_json(emitter)) {
|
if (!emitter_outputs_json(emitter)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < json_order_len; i++) {
|
for (size_t i = 0; i < ndescs; i++) {
|
||||||
unsigned col_ind = json_order[i];
|
const emitter_col_desc_t *desc = &descs[i];
|
||||||
assert(col_ind < ndescs);
|
|
||||||
const emitter_col_desc_t *desc = &descs[col_ind];
|
|
||||||
if (!emitter_col_desc_active(desc, active_flags)) {
|
if (!emitter_col_desc_active(desc, active_flags)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
assert(desc->json_key != NULL);
|
if (desc->json_key != NULL) {
|
||||||
emitter_json_kv(emitter, desc->json_key, cols[col_ind].type,
|
emitter_type_t json_type = cols[i].type == emitter_type_title
|
||||||
(const void *)&cols[col_ind].bool_val);
|
? emitter_type_string : cols[i].type;
|
||||||
|
emitter_json_kv(emitter, desc->json_key, json_type,
|
||||||
|
(const void *)&cols[i].bool_val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
242
src/stats.c
242
src/stats.c
@@ -782,54 +782,27 @@ stats_bin_col_get_util(const void *vrow, emitter_col_t *col) {
|
|||||||
col->str_val = row->util;
|
col->str_val = row->util;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
#define BIN_COL_SIZE 0
|
||||||
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_DESC(key, label, width, type, flags, name) \
|
#define BIN_DESC(key, label, width, type, flags, name) \
|
||||||
{key, label, emitter_justify_right, width, emitter_type_##type, flags, \
|
{key, label, emitter_justify_right, width, emitter_type_##type, flags, \
|
||||||
stats_bin_col_get_##name}
|
stats_bin_col_get_##name}
|
||||||
static const emitter_col_desc_t stats_bin_cols[] = {
|
static const emitter_col_desc_t stats_bin_cols[] = {
|
||||||
BIN_DESC(NULL, "size", 20, size, STATS_COL_FLAG_NONE, size),
|
BIN_DESC("size", "size", 20, size, STATS_COL_FLAG_NONE, size),
|
||||||
BIN_DESC(NULL, "ind", 4, unsigned, STATS_COL_FLAG_NONE, ind),
|
BIN_DESC("ind", "ind", 4, unsigned, STATS_COL_FLAG_NONE, ind),
|
||||||
BIN_DESC(NULL, "allocated", 14, size, STATS_COL_FLAG_NONE, allocated),
|
BIN_DESC("allocated", "allocated", 14, size, STATS_COL_FLAG_NONE,
|
||||||
|
allocated),
|
||||||
BIN_DESC("nmalloc", "nmalloc", 14, uint64, STATS_COL_FLAG_NONE,
|
BIN_DESC("nmalloc", "nmalloc", 14, uint64, STATS_COL_FLAG_NONE,
|
||||||
nmalloc),
|
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,
|
BIN_DESC("ndalloc", "ndalloc", 14, uint64, STATS_COL_FLAG_NONE,
|
||||||
ndalloc),
|
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,
|
BIN_DESC("nrequests", "nrequests", 15, uint64, STATS_COL_FLAG_NONE,
|
||||||
nrequests),
|
nrequests),
|
||||||
BIN_DESC(NULL, "(#/sec)", 10, uint64, STATS_COL_FLAG_NONE,
|
BIN_DESC("nrequests_ps", "(#/sec)", 10, uint64, STATS_COL_FLAG_NONE,
|
||||||
nrequests_ps),
|
nrequests_ps),
|
||||||
BIN_DESC("prof_live_requested", "prof_live_requested", 21, uint64,
|
BIN_DESC("prof_live_requested", "prof_live_requested", 21, uint64,
|
||||||
STATS_COL_FLAG_PROF, prof_live_requested),
|
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),
|
STATS_COL_FLAG_PROF, prof_accum_requested),
|
||||||
BIN_DESC("prof_accum_count", "prof_accum_count", 17, uint64,
|
BIN_DESC("prof_accum_count", "prof_accum_count", 17, uint64,
|
||||||
STATS_COL_FLAG_PROF, prof_accum_count),
|
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("curregs", "curregs", 13, size, STATS_COL_FLAG_NONE, curregs),
|
||||||
BIN_DESC("curslabs", "curslabs", 13, size, STATS_COL_FLAG_NONE,
|
BIN_DESC("curslabs", "curslabs", 13, size, STATS_COL_FLAG_NONE,
|
||||||
curslabs),
|
curslabs),
|
||||||
BIN_DESC("nonfull_slabs", "nonfull_slabs", 15, size,
|
BIN_DESC("nonfull_slabs", "nonfull_slabs", 15, size,
|
||||||
STATS_COL_FLAG_NONE,
|
STATS_COL_FLAG_NONE,
|
||||||
nonfull_slabs),
|
nonfull_slabs),
|
||||||
BIN_DESC(NULL, "regs", 5, unsigned, STATS_COL_FLAG_NONE, regs),
|
BIN_DESC("regs", "regs", 5, unsigned, STATS_COL_FLAG_NONE, regs),
|
||||||
BIN_DESC(NULL, "pgs", 4, size, STATS_COL_FLAG_NONE, pgs),
|
BIN_DESC("pgs", "pgs", 4, size, STATS_COL_FLAG_NONE, pgs),
|
||||||
BIN_DESC(NULL, " ", 1, title, STATS_COL_FLAG_NONE, spacer),
|
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("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,
|
BIN_DESC("nflushes", "nflushes", 13, uint64, STATS_COL_FLAG_NONE,
|
||||||
nflushes),
|
nflushes),
|
||||||
BIN_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE,
|
BIN_DESC("nflushes_ps", "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE,
|
||||||
nflushes_ps),
|
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,
|
BIN_DESC("nreslabs", "nreslabs", 13, uint64, STATS_COL_FLAG_NONE,
|
||||||
nreslabs),
|
nreslabs),
|
||||||
BIN_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE,
|
BIN_DESC("nreslabs_ps", "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE,
|
||||||
nreslabs_ps),
|
nreslabs_ps),
|
||||||
};
|
};
|
||||||
#undef BIN_DESC
|
#undef BIN_DESC
|
||||||
_Static_assert(sizeof(stats_bin_cols) / sizeof(stats_bin_cols[0]) ==
|
#define BIN_COL_COUNT (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,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stats_emit_arena_bin_row(emitter_t *emitter, emitter_row_t *table_row,
|
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);
|
stats_bin_cols, BIN_COL_COUNT, active_flags, cols, row);
|
||||||
emitter_json_object_begin(emitter);
|
emitter_json_object_begin(emitter);
|
||||||
emitter_col_table_emit_json(emitter, stats_bin_cols, BIN_COL_COUNT,
|
emitter_col_table_emit_json(emitter, stats_bin_cols, BIN_COL_COUNT,
|
||||||
active_flags, cols, stats_bin_json_order,
|
active_flags, cols);
|
||||||
sizeof(stats_bin_json_order) / sizeof(stats_bin_json_order[0]));
|
|
||||||
if (mutex) {
|
if (mutex) {
|
||||||
emitter_json_object_kv_begin(emitter, "mutex");
|
emitter_json_object_kv_begin(emitter, "mutex");
|
||||||
mutex_stats_emit(emitter, NULL, mutex64, mutex32);
|
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;
|
col->size_val = row->lextent->curlextents * row->lextent->lextent_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
#define LEXTENT_COL_SIZE 0
|
||||||
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_DESC(key, label, width, type, flags, name) \
|
#define LEXTENT_DESC(key, label, width, type, flags, name) \
|
||||||
{key, label, emitter_justify_right, width, emitter_type_##type, flags, \
|
{key, label, emitter_justify_right, width, emitter_type_##type, flags, \
|
||||||
stats_lextent_col_get_##name}
|
stats_lextent_col_get_##name}
|
||||||
static const emitter_col_desc_t stats_lextent_cols[] = {
|
static const emitter_col_desc_t stats_lextent_cols[] = {
|
||||||
LEXTENT_DESC(NULL, "size", 20, size, STATS_COL_FLAG_NONE, size),
|
LEXTENT_DESC("size", "size", 20, size, STATS_COL_FLAG_NONE, size),
|
||||||
LEXTENT_DESC(NULL, "ind", 4, unsigned, STATS_COL_FLAG_NONE, ind),
|
LEXTENT_DESC("ind", "ind", 4, unsigned, STATS_COL_FLAG_NONE, ind),
|
||||||
LEXTENT_DESC(NULL, "allocated", 13, size, STATS_COL_FLAG_NONE,
|
LEXTENT_DESC("allocated", "allocated", 13, size, STATS_COL_FLAG_NONE,
|
||||||
allocated),
|
allocated),
|
||||||
LEXTENT_DESC(NULL, "nmalloc", 13, uint64, STATS_COL_FLAG_NONE, nmalloc),
|
LEXTENT_DESC("nmalloc", "nmalloc", 13, uint64, STATS_COL_FLAG_NONE,
|
||||||
LEXTENT_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE,
|
nmalloc),
|
||||||
|
LEXTENT_DESC("nmalloc_ps", "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE,
|
||||||
nmalloc_ps),
|
nmalloc_ps),
|
||||||
LEXTENT_DESC(NULL, "ndalloc", 13, uint64, STATS_COL_FLAG_NONE, ndalloc),
|
LEXTENT_DESC("ndalloc", "ndalloc", 13, uint64, STATS_COL_FLAG_NONE,
|
||||||
LEXTENT_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE,
|
ndalloc),
|
||||||
|
LEXTENT_DESC("ndalloc_ps", "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE,
|
||||||
ndalloc_ps),
|
ndalloc_ps),
|
||||||
LEXTENT_DESC(NULL, "nrequests", 13, uint64, STATS_COL_FLAG_NONE,
|
LEXTENT_DESC("nrequests", "nrequests", 13, uint64,
|
||||||
|
STATS_COL_FLAG_NONE,
|
||||||
nrequests),
|
nrequests),
|
||||||
LEXTENT_DESC(NULL, "(#/sec)", 8, uint64, STATS_COL_FLAG_NONE,
|
LEXTENT_DESC("nrequests_ps", "(#/sec)", 8, uint64,
|
||||||
|
STATS_COL_FLAG_NONE,
|
||||||
nrequests_ps),
|
nrequests_ps),
|
||||||
LEXTENT_DESC("prof_live_requested", "prof_live_requested", 21, uint64,
|
LEXTENT_DESC("prof_live_requested", "prof_live_requested", 21, uint64,
|
||||||
STATS_COL_FLAG_PROF, prof_live_requested),
|
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),
|
STATS_COL_FLAG_NONE, curlextents),
|
||||||
};
|
};
|
||||||
#undef LEXTENT_DESC
|
#undef LEXTENT_DESC
|
||||||
_Static_assert(sizeof(stats_lextent_cols) / sizeof(stats_lextent_cols[0]) ==
|
#define LEXTENT_COL_COUNT \
|
||||||
LEXTENT_COL_COUNT, "stats_lextent_cols must match LEXTENT_COL_COUNT");
|
(sizeof(stats_lextent_cols) / sizeof(stats_lextent_cols[0]))
|
||||||
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stats_emit_arena_lextent_row(emitter_t *emitter, emitter_row_t *table_row,
|
stats_emit_arena_lextent_row(emitter_t *emitter, emitter_row_t *table_row,
|
||||||
@@ -1135,15 +1072,13 @@ stats_emit_arena_lextent_row(emitter_t *emitter, emitter_row_t *table_row,
|
|||||||
unsigned active_flags = stats_col_active_flags(prof_stats_on);
|
unsigned active_flags = stats_col_active_flags(prof_stats_on);
|
||||||
emitter_col_table_fill(stats_lextent_cols, LEXTENT_COL_COUNT,
|
emitter_col_table_fill(stats_lextent_cols, LEXTENT_COL_COUNT,
|
||||||
active_flags, cols, row);
|
active_flags, cols, row);
|
||||||
stats_size_col_set(&cols[LEXTENT_COL_SIZE], row->lextent->lextent_size,
|
|
||||||
prev_size, size_buf, size_buf_size);
|
|
||||||
emitter_json_object_begin(emitter);
|
emitter_json_object_begin(emitter);
|
||||||
emitter_col_table_emit_json(emitter, stats_lextent_cols,
|
emitter_col_table_emit_json(emitter, stats_lextent_cols,
|
||||||
LEXTENT_COL_COUNT, active_flags, cols, stats_lextent_json_order,
|
LEXTENT_COL_COUNT, active_flags, cols);
|
||||||
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);
|
emitter_json_object_end(emitter);
|
||||||
|
stats_size_col_set(&cols[LEXTENT_COL_SIZE], row->lextent->lextent_size,
|
||||||
|
prev_size, size_buf, size_buf_size);
|
||||||
|
emitter_table_sparse_row(emitter, table_row, is_gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_COLD
|
JEMALLOC_COLD
|
||||||
@@ -1242,29 +1177,15 @@ stats_extent_col_get_ind(const void *vrow, emitter_col_t *col) {
|
|||||||
col->unsigned_val = row->ind;
|
col->unsigned_val = row->ind;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
#define EXTENT_COL_SIZE 0
|
||||||
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_DESC(key, label, name) \
|
#define EXTENT_DESC(key, label, name) \
|
||||||
{key, label, emitter_justify_right, 13, emitter_type_size, \
|
{key, label, emitter_justify_right, 13, emitter_type_size, \
|
||||||
STATS_COL_FLAG_NONE, stats_extent_col_get_##name}
|
STATS_COL_FLAG_NONE, stats_extent_col_get_##name}
|
||||||
static const emitter_col_desc_t stats_extent_cols[] = {
|
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},
|
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},
|
STATS_COL_FLAG_NONE, stats_extent_col_get_ind},
|
||||||
EXTENT_DESC("ndirty", "ndirty", ndirty),
|
EXTENT_DESC("ndirty", "ndirty", ndirty),
|
||||||
EXTENT_DESC("dirty_bytes", "dirty", dirty),
|
EXTENT_DESC("dirty_bytes", "dirty", dirty),
|
||||||
@@ -1274,23 +1195,12 @@ static const emitter_col_desc_t stats_extent_cols[] = {
|
|||||||
EXTENT_DESC("retained_bytes", "retained", retained),
|
EXTENT_DESC("retained_bytes", "retained", retained),
|
||||||
EXTENT_DESC("npinned", "npinned", npinned),
|
EXTENT_DESC("npinned", "npinned", npinned),
|
||||||
EXTENT_DESC("pinned_bytes", "pinned", pinned),
|
EXTENT_DESC("pinned_bytes", "pinned", pinned),
|
||||||
EXTENT_DESC(NULL, "ntotal", ntotal),
|
EXTENT_DESC("ntotal", "ntotal", ntotal),
|
||||||
EXTENT_DESC(NULL, "total", total),
|
EXTENT_DESC("total_bytes", "total", total),
|
||||||
};
|
};
|
||||||
#undef EXTENT_DESC
|
#undef EXTENT_DESC
|
||||||
_Static_assert(sizeof(stats_extent_cols) / sizeof(stats_extent_cols[0]) ==
|
#define EXTENT_COL_COUNT \
|
||||||
EXTENT_COL_COUNT, "stats_extent_cols must match EXTENT_COL_COUNT");
|
(sizeof(stats_extent_cols) / sizeof(stats_extent_cols[0]))
|
||||||
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stats_emit_arena_extent_row(emitter_t *emitter, emitter_row_t *table_row,
|
stats_emit_arena_extent_row(emitter_t *emitter, emitter_row_t *table_row,
|
||||||
@@ -1298,14 +1208,12 @@ stats_emit_arena_extent_row(emitter_t *emitter, emitter_row_t *table_row,
|
|||||||
size_t prev_size, char *size_buf, size_t size_buf_size, bool is_gap) {
|
size_t prev_size, char *size_buf, size_t size_buf_size, bool is_gap) {
|
||||||
emitter_col_table_fill(stats_extent_cols, EXTENT_COL_COUNT,
|
emitter_col_table_fill(stats_extent_cols, EXTENT_COL_COUNT,
|
||||||
STATS_COL_FLAG_NONE, cols, row);
|
STATS_COL_FLAG_NONE, cols, row);
|
||||||
stats_size_col_set(&cols[EXTENT_COL_SIZE], row->size, prev_size,
|
|
||||||
size_buf, size_buf_size);
|
|
||||||
emitter_json_object_begin(emitter);
|
emitter_json_object_begin(emitter);
|
||||||
emitter_col_table_emit_json(emitter, stats_extent_cols, EXTENT_COL_COUNT,
|
emitter_col_table_emit_json(emitter, stats_extent_cols, EXTENT_COL_COUNT,
|
||||||
STATS_COL_FLAG_NONE, cols, stats_extent_json_order,
|
STATS_COL_FLAG_NONE, cols);
|
||||||
sizeof(stats_extent_json_order) /
|
|
||||||
sizeof(stats_extent_json_order[0]));
|
|
||||||
emitter_json_object_end(emitter);
|
emitter_json_object_end(emitter);
|
||||||
|
stats_size_col_set(&cols[EXTENT_COL_SIZE], row->size, prev_size,
|
||||||
|
size_buf, size_buf_size);
|
||||||
emitter_table_sparse_row(emitter, table_row, is_gap);
|
emitter_table_sparse_row(emitter, table_row, is_gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1575,26 +1483,15 @@ stats_hpa_slab_col_get_ind(const void *vrow, emitter_col_t *col) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
#define HPA_SLAB_COL_SIZE 0
|
||||||
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_DESC(name, width) \
|
#define HPA_SLAB_DESC(name, width) \
|
||||||
{#name, #name, emitter_justify_right, width, emitter_type_size, \
|
{#name, #name, emitter_justify_right, width, emitter_type_size, \
|
||||||
STATS_COL_FLAG_NONE, stats_hpa_slab_col_get_##name}
|
STATS_COL_FLAG_NONE, stats_hpa_slab_col_get_##name}
|
||||||
static const emitter_col_desc_t stats_hpa_slab_cols[] = {
|
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},
|
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},
|
STATS_COL_FLAG_NONE, stats_hpa_slab_col_get_ind},
|
||||||
HPA_SLAB_DESC(npageslabs_huge, 16),
|
HPA_SLAB_DESC(npageslabs_huge, 16),
|
||||||
HPA_SLAB_DESC(nactive_huge, 16),
|
HPA_SLAB_DESC(nactive_huge, 16),
|
||||||
@@ -1605,20 +1502,8 @@ static const emitter_col_desc_t stats_hpa_slab_cols[] = {
|
|||||||
HPA_SLAB_DESC(nretained_nonhuge, 20),
|
HPA_SLAB_DESC(nretained_nonhuge, 20),
|
||||||
};
|
};
|
||||||
#undef HPA_SLAB_DESC
|
#undef HPA_SLAB_DESC
|
||||||
_Static_assert(
|
#define HPA_SLAB_COL_COUNT \
|
||||||
sizeof(stats_hpa_slab_cols) / sizeof(stats_hpa_slab_cols[0]) ==
|
(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,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stats_emit_arena_hpa_slab_row(emitter_t *emitter,
|
stats_emit_arena_hpa_slab_row(emitter_t *emitter,
|
||||||
@@ -1627,21 +1512,18 @@ stats_emit_arena_hpa_slab_row(emitter_t *emitter,
|
|||||||
char *size_buf, size_t size_buf_size, bool sparse, bool is_gap) {
|
char *size_buf, size_t size_buf_size, bool sparse, bool is_gap) {
|
||||||
emitter_col_table_fill(stats_hpa_slab_cols, HPA_SLAB_COL_COUNT,
|
emitter_col_table_fill(stats_hpa_slab_cols, HPA_SLAB_COL_COUNT,
|
||||||
STATS_COL_FLAG_NONE, cols, row);
|
STATS_COL_FLAG_NONE, cols, row);
|
||||||
if (row->size_title == NULL) {
|
|
||||||
stats_size_col_set(&cols[HPA_SLAB_COL_SIZE], row->size,
|
|
||||||
row->prev_size, size_buf, size_buf_size);
|
|
||||||
}
|
|
||||||
if (json_key != NULL) {
|
if (json_key != NULL) {
|
||||||
emitter_json_object_kv_begin(emitter, json_key);
|
emitter_json_object_kv_begin(emitter, json_key);
|
||||||
} else {
|
} else {
|
||||||
emitter_json_object_begin(emitter);
|
emitter_json_object_begin(emitter);
|
||||||
}
|
}
|
||||||
emitter_col_table_emit_json(emitter, stats_hpa_slab_cols,
|
emitter_col_table_emit_json(emitter, stats_hpa_slab_cols,
|
||||||
HPA_SLAB_COL_COUNT, STATS_COL_FLAG_NONE, 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]));
|
|
||||||
emitter_json_object_end(emitter);
|
emitter_json_object_end(emitter);
|
||||||
|
if (row->size_title == NULL) {
|
||||||
|
stats_size_col_set(&cols[HPA_SLAB_COL_SIZE], row->size,
|
||||||
|
row->prev_size, size_buf, size_buf_size);
|
||||||
|
}
|
||||||
if (sparse) {
|
if (sparse) {
|
||||||
emitter_table_sparse_row(emitter, table_row, is_gap);
|
emitter_table_sparse_row(emitter, table_row, is_gap);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -669,10 +669,11 @@ static const char *sparse_row_table =
|
|||||||
" ---\n";
|
" ---\n";
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t size;
|
size_t size;
|
||||||
uint64_t count;
|
uint64_t count;
|
||||||
uint64_t prof_count;
|
uint64_t prof_count;
|
||||||
uint64_t requests;
|
const char *label;
|
||||||
|
uint64_t requests;
|
||||||
} col_table_test_row_t;
|
} col_table_test_row_t;
|
||||||
|
|
||||||
#define COL_TABLE_TEST_GETTER(name, member, value_member) \
|
#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(size, size, size_val)
|
||||||
COL_TABLE_TEST_GETTER(count, count, uint64_val)
|
COL_TABLE_TEST_GETTER(count, count, uint64_val)
|
||||||
COL_TABLE_TEST_GETTER(prof_count, prof_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)
|
COL_TABLE_TEST_GETTER(requests, requests, uint64_val)
|
||||||
#undef COL_TABLE_TEST_GETTER
|
#undef COL_TABLE_TEST_GETTER
|
||||||
|
|
||||||
@@ -691,6 +693,7 @@ enum {
|
|||||||
COL_TABLE_TEST_SIZE,
|
COL_TABLE_TEST_SIZE,
|
||||||
COL_TABLE_TEST_COUNT,
|
COL_TABLE_TEST_COUNT,
|
||||||
COL_TABLE_TEST_PROF_COUNT,
|
COL_TABLE_TEST_PROF_COUNT,
|
||||||
|
COL_TABLE_TEST_LABEL,
|
||||||
COL_TABLE_TEST_REQUESTS,
|
COL_TABLE_TEST_REQUESTS,
|
||||||
COL_TABLE_TEST_NCOLS
|
COL_TABLE_TEST_NCOLS
|
||||||
};
|
};
|
||||||
@@ -704,6 +707,8 @@ static const emitter_col_desc_t col_table_test_descs[] = {
|
|||||||
0, col_table_test_get_count},
|
0, col_table_test_get_count},
|
||||||
{"prof_count", "prof", emitter_justify_right, 6, emitter_type_uint64,
|
{"prof_count", "prof", emitter_justify_right, 6, emitter_type_uint64,
|
||||||
COL_TABLE_TEST_FLAG_PROF, col_table_test_get_prof_count},
|
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,
|
{"requests", "requests", emitter_justify_right, 10,
|
||||||
emitter_type_uint64, 0, col_table_test_get_requests},
|
emitter_type_uint64, 0, col_table_test_get_requests},
|
||||||
};
|
};
|
||||||
@@ -726,15 +731,9 @@ TEST_BEGIN(test_col_desc_flags) {
|
|||||||
}
|
}
|
||||||
TEST_END
|
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
|
static void
|
||||||
emit_col_table(emitter_t *emitter) {
|
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_row_t row, header_row;
|
||||||
emitter_col_t cols[COL_TABLE_TEST_NCOLS];
|
emitter_col_t cols[COL_TABLE_TEST_NCOLS];
|
||||||
emitter_col_t header_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);
|
COL_TABLE_TEST_FLAG_PROF, cols, &value);
|
||||||
emitter_json_object_begin(emitter);
|
emitter_json_object_begin(emitter);
|
||||||
emitter_col_table_emit_json(emitter, col_table_test_descs,
|
emitter_col_table_emit_json(emitter, col_table_test_descs,
|
||||||
COL_TABLE_TEST_NCOLS, COL_TABLE_TEST_FLAG_PROF, cols,
|
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]));
|
|
||||||
emitter_json_object_end(emitter);
|
emitter_json_object_end(emitter);
|
||||||
emitter_table_row(emitter, &row);
|
emitter_table_row(emitter, &row);
|
||||||
emitter_json_array_end(emitter);
|
emitter_json_array_end(emitter);
|
||||||
@@ -761,17 +758,19 @@ static const char *col_table_json =
|
|||||||
"{\n"
|
"{\n"
|
||||||
"\t\"rows\": [\n"
|
"\t\"rows\": [\n"
|
||||||
"\t\t{\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\"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\t}\n"
|
||||||
"\t]\n"
|
"\t]\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
static const char *col_table_json_compact =
|
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 =
|
static const char *col_table_table =
|
||||||
"mock:size count prof requests\n"
|
"mock:size count prof label requests\n"
|
||||||
" 42 7 100 9\n";
|
" 42 7 100 row 9\n";
|
||||||
|
|
||||||
#define GENERATE_TEST(feature) \
|
#define GENERATE_TEST(feature) \
|
||||||
TEST_BEGIN(test_##feature) { \
|
TEST_BEGIN(test_##feature) { \
|
||||||
|
|||||||
@@ -442,6 +442,95 @@ expect_json_uint_eq(json_fragment_t object, const char *key,
|
|||||||
key);
|
key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
expect_json_string_eq(json_fragment_t object, const char *key,
|
||||||
|
const char *expected, const char *name) {
|
||||||
|
json_fragment_t value;
|
||||||
|
bool missing = json_object_member(object, key, &value);
|
||||||
|
expect_false(missing, "%s is missing %s", name, key);
|
||||||
|
if (missing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
expect_true(json_fragment_string_eq(value, expected),
|
||||||
|
"%s.%s has an unexpected value", name, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
expected_rate(uint64_t value, uint64_t uptime_ns) {
|
||||||
|
const uint64_t billion = 1000000000;
|
||||||
|
if (uptime_ns == 0 || value == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return uptime_ns < billion ? value : value / (uptime_ns / billion);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
expected_utilization(size_t curregs, size_t availregs, char result[6]) {
|
||||||
|
if (availregs == 0) {
|
||||||
|
malloc_snprintf(result, 6, "1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert_zu_le(curregs, availregs, "Cached bin stats should be consistent");
|
||||||
|
unsigned n = (unsigned)(((uint64_t)curregs * 1000) / availregs);
|
||||||
|
if (n < 10) {
|
||||||
|
malloc_snprintf(result, 6, "0.00%u", n);
|
||||||
|
} else if (n < 100) {
|
||||||
|
malloc_snprintf(result, 6, "0.0%u", n);
|
||||||
|
} else if (n < 1000) {
|
||||||
|
malloc_snprintf(result, 6, "0.%u", n);
|
||||||
|
} else {
|
||||||
|
malloc_snprintf(result, 6, "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
read_size_ctl(const char *name) {
|
||||||
|
size_t value;
|
||||||
|
size_t sz = sizeof(value);
|
||||||
|
assert_d_eq(mallctl(name, &value, &sz, NULL, 0), 0,
|
||||||
|
"mallctl failed for %s", name);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
read_uint64_ctl(const char *name) {
|
||||||
|
uint64_t value;
|
||||||
|
size_t sz = sizeof(value);
|
||||||
|
assert_d_eq(mallctl(name, &value, &sz, NULL, 0), 0,
|
||||||
|
"mallctl failed for %s", name);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
read_uint32_ctl(const char *name) {
|
||||||
|
uint32_t value;
|
||||||
|
size_t sz = sizeof(value);
|
||||||
|
assert_d_eq(mallctl(name, &value, &sz, NULL, 0), 0,
|
||||||
|
"mallctl failed for %s", name);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
read_size_field(const char *prefix, const char *suffix) {
|
||||||
|
char name[192];
|
||||||
|
malloc_snprintf(name, sizeof(name), "%s.%s", prefix, suffix);
|
||||||
|
return read_size_ctl(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
read_uint64_field(const char *prefix, const char *suffix) {
|
||||||
|
char name[192];
|
||||||
|
malloc_snprintf(name, sizeof(name), "%s.%s", prefix, suffix);
|
||||||
|
return read_uint64_ctl(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
read_uint32_field(const char *prefix, const char *suffix) {
|
||||||
|
char name[192];
|
||||||
|
malloc_snprintf(name, sizeof(name), "%s.%s", prefix, suffix);
|
||||||
|
return read_uint32_ctl(name);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
stats_json_print_opts(stats_buf_t *sbuf, const char *opts,
|
stats_json_print_opts(stats_buf_t *sbuf, const char *opts,
|
||||||
json_fragment_t *jemalloc) {
|
json_fragment_t *jemalloc) {
|
||||||
@@ -886,12 +975,20 @@ static const ctl_field_t hpa_slab_fields[] = {
|
|||||||
static const char *const hpa_slab_keys[] = {"npageslabs_huge",
|
static const char *const hpa_slab_keys[] = {"npageslabs_huge",
|
||||||
"nactive_huge", "ndirty_huge", "npageslabs_nonhuge",
|
"nactive_huge", "ndirty_huge", "npageslabs_nonhuge",
|
||||||
"nactive_nonhuge", "ndirty_nonhuge", "nretained_nonhuge"};
|
"nactive_nonhuge", "ndirty_nonhuge", "nretained_nonhuge"};
|
||||||
|
static const char *const hpa_slab_row_keys[] = {"size", "ind"};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
expect_hpa_slab(json_fragment_t slab, const char *ctl_prefix,
|
expect_hpa_slab(json_fragment_t slab, const char *ctl_prefix,
|
||||||
const char *name) {
|
const char *name, bool table_row) {
|
||||||
expect_json_object_keys(
|
expect_zu_eq(json_object_size(slab), ARRAY_COUNT(hpa_slab_keys)
|
||||||
|
+ (table_row ? ARRAY_COUNT(hpa_slab_row_keys) : 0),
|
||||||
|
"%s has an unexpected number of keys", name);
|
||||||
|
expect_json_object_has_keys(
|
||||||
slab, hpa_slab_keys, ARRAY_COUNT(hpa_slab_keys), name);
|
slab, hpa_slab_keys, ARRAY_COUNT(hpa_slab_keys), name);
|
||||||
|
if (table_row) {
|
||||||
|
expect_json_object_has_keys(slab, hpa_slab_row_keys,
|
||||||
|
ARRAY_COUNT(hpa_slab_row_keys), name);
|
||||||
|
}
|
||||||
expect_json_ctl_fields(slab, ctl_prefix, hpa_slab_fields,
|
expect_json_ctl_fields(slab, ctl_prefix, hpa_slab_fields,
|
||||||
ARRAY_COUNT(hpa_slab_fields));
|
ARRAY_COUNT(hpa_slab_fields));
|
||||||
|
|
||||||
@@ -972,7 +1069,7 @@ TEST_BEGIN(test_json_stats_hpa) {
|
|||||||
char slab_prefix[128];
|
char slab_prefix[128];
|
||||||
malloc_snprintf(
|
malloc_snprintf(
|
||||||
slab_prefix, sizeof(slab_prefix), "%s.slabs", hpa_prefix);
|
slab_prefix, sizeof(slab_prefix), "%s.slabs", hpa_prefix);
|
||||||
expect_hpa_slab(slabs, slab_prefix, "hpa_shard.slabs");
|
expect_hpa_slab(slabs, slab_prefix, "hpa_shard.slabs", false);
|
||||||
|
|
||||||
const char *const summary_names[] = {"full_slabs", "empty_slabs"};
|
const char *const summary_names[] = {"full_slabs", "empty_slabs"};
|
||||||
for (size_t i = 0; i < ARRAY_COUNT(summary_names); i++) {
|
for (size_t i = 0; i < ARRAY_COUNT(summary_names); i++) {
|
||||||
@@ -981,7 +1078,10 @@ TEST_BEGIN(test_json_stats_hpa) {
|
|||||||
"hpa_shard is missing %s", summary_names[i]);
|
"hpa_shard is missing %s", summary_names[i]);
|
||||||
malloc_snprintf(slab_prefix, sizeof(slab_prefix), "%s.%s",
|
malloc_snprintf(slab_prefix, sizeof(slab_prefix), "%s.%s",
|
||||||
hpa_prefix, summary_names[i]);
|
hpa_prefix, summary_names[i]);
|
||||||
expect_hpa_slab(summary, slab_prefix, summary_names[i]);
|
expect_hpa_slab(summary, slab_prefix, summary_names[i], true);
|
||||||
|
expect_json_string_eq(
|
||||||
|
summary, "size", i == 0 ? "full" : "empty", summary_names[i]);
|
||||||
|
expect_json_string_eq(summary, "ind", "-", summary_names[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
json_fragment_t nonfull;
|
json_fragment_t nonfull;
|
||||||
@@ -1000,7 +1100,10 @@ TEST_BEGIN(test_json_stats_hpa) {
|
|||||||
char row_name[64];
|
char row_name[64];
|
||||||
malloc_snprintf(
|
malloc_snprintf(
|
||||||
row_name, sizeof(row_name), "nonfull_slabs[%zu]", i);
|
row_name, sizeof(row_name), "nonfull_slabs[%zu]", i);
|
||||||
expect_hpa_slab(slab, slab_prefix, row_name);
|
expect_hpa_slab(slab, slab_prefix, row_name, true);
|
||||||
|
expect_json_uint_eq(
|
||||||
|
slab, "size", sz_pind2sz((pszind_t)i), row_name);
|
||||||
|
expect_json_uint_eq(slab, "ind", i, row_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
json_fragment_t distribution;
|
json_fragment_t distribution;
|
||||||
@@ -1036,18 +1139,26 @@ static const ctl_field_t bin_fields[] = {
|
|||||||
{"nrequests", "nrequests", ctl_field_uint64},
|
{"nrequests", "nrequests", ctl_field_uint64},
|
||||||
{"nfills", "nfills", ctl_field_uint64},
|
{"nfills", "nfills", ctl_field_uint64},
|
||||||
{"nflushes", "nflushes", ctl_field_uint64},
|
{"nflushes", "nflushes", ctl_field_uint64},
|
||||||
|
{"nslabs", "nslabs", ctl_field_uint64},
|
||||||
{"nreslabs", "nreslabs", ctl_field_uint64},
|
{"nreslabs", "nreslabs", ctl_field_uint64},
|
||||||
{"curslabs", "curslabs", ctl_field_size},
|
{"curslabs", "curslabs", ctl_field_size},
|
||||||
{"nonfull_slabs", "nonfull_slabs", ctl_field_size},
|
{"nonfull_slabs", "nonfull_slabs", ctl_field_size},
|
||||||
};
|
};
|
||||||
static const char *const bin_keys[] = {"nmalloc", "ndalloc", "curregs",
|
static const char *const bin_keys[] = {"size", "ind", "allocated",
|
||||||
"nrequests", "nfills", "nflushes", "nreslabs", "curslabs",
|
"nmalloc", "nmalloc_ps", "ndalloc", "ndalloc_ps", "nrequests",
|
||||||
"nonfull_slabs", "mutex"};
|
"nrequests_ps", "nshards", "curregs", "curslabs", "nonfull_slabs",
|
||||||
|
"regs", "pgs", "util", "nfills", "nfills_ps", "nflushes",
|
||||||
|
"nflushes_ps", "nslabs", "nreslabs", "nreslabs_ps", "mutex"};
|
||||||
|
|
||||||
static const ctl_field_t lextent_fields[] = {
|
static const ctl_field_t lextent_fields[] = {
|
||||||
|
{"nmalloc", "nmalloc", ctl_field_uint64},
|
||||||
|
{"ndalloc", "ndalloc", ctl_field_uint64},
|
||||||
|
{"nrequests", "nrequests", ctl_field_uint64},
|
||||||
{"curlextents", "curlextents", ctl_field_size},
|
{"curlextents", "curlextents", ctl_field_size},
|
||||||
};
|
};
|
||||||
static const char *const lextent_keys[] = {"curlextents"};
|
static const char *const lextent_keys[] = {"size", "ind", "allocated",
|
||||||
|
"nmalloc", "nmalloc_ps", "ndalloc", "ndalloc_ps", "nrequests",
|
||||||
|
"nrequests_ps", "curlextents"};
|
||||||
|
|
||||||
static const ctl_field_t extent_fields[] = {
|
static const ctl_field_t extent_fields[] = {
|
||||||
{"ndirty", "ndirty", ctl_field_size},
|
{"ndirty", "ndirty", ctl_field_size},
|
||||||
@@ -1059,9 +1170,10 @@ static const ctl_field_t extent_fields[] = {
|
|||||||
{"retained_bytes", "retained_bytes", ctl_field_size},
|
{"retained_bytes", "retained_bytes", ctl_field_size},
|
||||||
{"pinned_bytes", "pinned_bytes", ctl_field_size},
|
{"pinned_bytes", "pinned_bytes", ctl_field_size},
|
||||||
};
|
};
|
||||||
static const char *const extent_keys[] = {"ndirty", "nmuzzy", "nretained",
|
static const char *const extent_keys[] = {"size", "ind", "ndirty",
|
||||||
"npinned", "dirty_bytes", "muzzy_bytes", "retained_bytes",
|
"dirty_bytes", "nmuzzy", "muzzy_bytes", "nretained",
|
||||||
"pinned_bytes"};
|
"retained_bytes", "npinned", "pinned_bytes", "ntotal",
|
||||||
|
"total_bytes"};
|
||||||
|
|
||||||
static const char *const prof_keys[] = {"prof_live_requested",
|
static const char *const prof_keys[] = {"prof_live_requested",
|
||||||
"prof_live_count", "prof_accum_requested", "prof_accum_count"};
|
"prof_live_count", "prof_accum_requested", "prof_accum_count"};
|
||||||
@@ -1109,6 +1221,10 @@ TEST_BEGIN(test_json_stats_arena_tables) {
|
|||||||
sz = sizeof(nlextents);
|
sz = sizeof(nlextents);
|
||||||
expect_d_eq(mallctl("arenas.nlextents", &nlextents, &sz, NULL, 0), 0,
|
expect_d_eq(mallctl("arenas.nlextents", &nlextents, &sz, NULL, 0), 0,
|
||||||
"mallctl failed for arenas.nlextents");
|
"mallctl failed for arenas.nlextents");
|
||||||
|
char arena_prefix[64];
|
||||||
|
malloc_snprintf(arena_prefix, sizeof(arena_prefix), "stats.arenas.%u",
|
||||||
|
MALLCTL_ARENAS_ALL);
|
||||||
|
uint64_t uptime = read_uint64_field(arena_prefix, "uptime");
|
||||||
|
|
||||||
json_fragment_t bins;
|
json_fragment_t bins;
|
||||||
expect_false(json_object_member(merged, "bins", &bins),
|
expect_false(json_object_member(merged, "bins", &bins),
|
||||||
@@ -1136,6 +1252,44 @@ TEST_BEGIN(test_json_stats_arena_tables) {
|
|||||||
"stats.arenas.%u.bins.%u", MALLCTL_ARENAS_ALL, i);
|
"stats.arenas.%u.bins.%u", MALLCTL_ARENAS_ALL, i);
|
||||||
expect_json_ctl_fields(
|
expect_json_ctl_fields(
|
||||||
bin, ctl_prefix, bin_fields, ARRAY_COUNT(bin_fields));
|
bin, ctl_prefix, bin_fields, ARRAY_COUNT(bin_fields));
|
||||||
|
|
||||||
|
char meta_prefix[64];
|
||||||
|
malloc_snprintf(
|
||||||
|
meta_prefix, sizeof(meta_prefix), "arenas.bin.%u", i);
|
||||||
|
size_t bin_size = read_size_field(meta_prefix, "size");
|
||||||
|
uint32_t nregs = read_uint32_field(meta_prefix, "nregs");
|
||||||
|
size_t slab_size = read_size_field(meta_prefix, "slab_size");
|
||||||
|
uint32_t nshards = read_uint32_field(meta_prefix, "nshards");
|
||||||
|
size_t curregs = read_size_field(ctl_prefix, "curregs");
|
||||||
|
size_t curslabs = read_size_field(ctl_prefix, "curslabs");
|
||||||
|
uint64_t nmalloc = read_uint64_field(ctl_prefix, "nmalloc");
|
||||||
|
uint64_t ndalloc = read_uint64_field(ctl_prefix, "ndalloc");
|
||||||
|
uint64_t nrequests = read_uint64_field(ctl_prefix, "nrequests");
|
||||||
|
uint64_t nfills = read_uint64_field(ctl_prefix, "nfills");
|
||||||
|
uint64_t nflushes = read_uint64_field(ctl_prefix, "nflushes");
|
||||||
|
uint64_t nreslabs = read_uint64_field(ctl_prefix, "nreslabs");
|
||||||
|
expect_json_uint_eq(bin, "size", bin_size, row_name);
|
||||||
|
expect_json_uint_eq(bin, "ind", i, row_name);
|
||||||
|
expect_json_uint_eq(
|
||||||
|
bin, "allocated", curregs * bin_size, row_name);
|
||||||
|
expect_json_uint_eq(bin, "nmalloc_ps",
|
||||||
|
expected_rate(nmalloc, uptime), row_name);
|
||||||
|
expect_json_uint_eq(bin, "ndalloc_ps",
|
||||||
|
expected_rate(ndalloc, uptime), row_name);
|
||||||
|
expect_json_uint_eq(bin, "nrequests_ps",
|
||||||
|
expected_rate(nrequests, uptime), row_name);
|
||||||
|
expect_json_uint_eq(bin, "nshards", nshards, row_name);
|
||||||
|
expect_json_uint_eq(bin, "regs", nregs, row_name);
|
||||||
|
expect_json_uint_eq(bin, "pgs", slab_size / PAGE, row_name);
|
||||||
|
expect_json_uint_eq(bin, "nfills_ps",
|
||||||
|
expected_rate(nfills, uptime), row_name);
|
||||||
|
expect_json_uint_eq(bin, "nflushes_ps",
|
||||||
|
expected_rate(nflushes, uptime), row_name);
|
||||||
|
expect_json_uint_eq(bin, "nreslabs_ps",
|
||||||
|
expected_rate(nreslabs, uptime), row_name);
|
||||||
|
char util[6];
|
||||||
|
expected_utilization(curregs, nregs * curslabs, util);
|
||||||
|
expect_json_string_eq(bin, "util", util, row_name);
|
||||||
if (prof_stats_present) {
|
if (prof_stats_present) {
|
||||||
expect_json_object_has_keys(
|
expect_json_object_has_keys(
|
||||||
bin, prof_keys, ARRAY_COUNT(prof_keys), row_name);
|
bin, prof_keys, ARRAY_COUNT(prof_keys), row_name);
|
||||||
@@ -1175,6 +1329,24 @@ TEST_BEGIN(test_json_stats_arena_tables) {
|
|||||||
"stats.arenas.%u.lextents.%u", MALLCTL_ARENAS_ALL, i);
|
"stats.arenas.%u.lextents.%u", MALLCTL_ARENAS_ALL, i);
|
||||||
expect_json_ctl_fields(lextent, ctl_prefix, lextent_fields,
|
expect_json_ctl_fields(lextent, ctl_prefix, lextent_fields,
|
||||||
ARRAY_COUNT(lextent_fields));
|
ARRAY_COUNT(lextent_fields));
|
||||||
|
char meta_prefix[64];
|
||||||
|
malloc_snprintf(meta_prefix, sizeof(meta_prefix),
|
||||||
|
"arenas.lextent.%u", i);
|
||||||
|
size_t lextent_size = read_size_field(meta_prefix, "size");
|
||||||
|
size_t curlextents = read_size_field(ctl_prefix, "curlextents");
|
||||||
|
uint64_t nmalloc = read_uint64_field(ctl_prefix, "nmalloc");
|
||||||
|
uint64_t ndalloc = read_uint64_field(ctl_prefix, "ndalloc");
|
||||||
|
uint64_t nrequests = read_uint64_field(ctl_prefix, "nrequests");
|
||||||
|
expect_json_uint_eq(lextent, "size", lextent_size, row_name);
|
||||||
|
expect_json_uint_eq(lextent, "ind", nbins + i, row_name);
|
||||||
|
expect_json_uint_eq(lextent, "allocated",
|
||||||
|
curlextents * lextent_size, row_name);
|
||||||
|
expect_json_uint_eq(lextent, "nmalloc_ps",
|
||||||
|
expected_rate(nmalloc, uptime), row_name);
|
||||||
|
expect_json_uint_eq(lextent, "ndalloc_ps",
|
||||||
|
expected_rate(ndalloc, uptime), row_name);
|
||||||
|
expect_json_uint_eq(lextent, "nrequests_ps",
|
||||||
|
expected_rate(nrequests, uptime), row_name);
|
||||||
if (prof_stats_present) {
|
if (prof_stats_present) {
|
||||||
expect_json_object_has_keys(lextent, prof_keys,
|
expect_json_object_has_keys(lextent, prof_keys,
|
||||||
ARRAY_COUNT(prof_keys), row_name);
|
ARRAY_COUNT(prof_keys), row_name);
|
||||||
@@ -1203,6 +1375,22 @@ TEST_BEGIN(test_json_stats_arena_tables) {
|
|||||||
"stats.arenas.%u.extents.%u", MALLCTL_ARENAS_ALL, i);
|
"stats.arenas.%u.extents.%u", MALLCTL_ARENAS_ALL, i);
|
||||||
expect_json_ctl_fields(extent, ctl_prefix, extent_fields,
|
expect_json_ctl_fields(extent, ctl_prefix, extent_fields,
|
||||||
ARRAY_COUNT(extent_fields));
|
ARRAY_COUNT(extent_fields));
|
||||||
|
size_t ndirty = read_size_field(ctl_prefix, "ndirty");
|
||||||
|
size_t nmuzzy = read_size_field(ctl_prefix, "nmuzzy");
|
||||||
|
size_t nretained = read_size_field(ctl_prefix, "nretained");
|
||||||
|
size_t npinned = read_size_field(ctl_prefix, "npinned");
|
||||||
|
size_t dirty_bytes = read_size_field(ctl_prefix, "dirty_bytes");
|
||||||
|
size_t muzzy_bytes = read_size_field(ctl_prefix, "muzzy_bytes");
|
||||||
|
size_t retained_bytes = read_size_field(
|
||||||
|
ctl_prefix, "retained_bytes");
|
||||||
|
size_t pinned_bytes = read_size_field(ctl_prefix, "pinned_bytes");
|
||||||
|
expect_json_uint_eq(extent, "size", sz_pind2sz(i), row_name);
|
||||||
|
expect_json_uint_eq(extent, "ind", i, row_name);
|
||||||
|
expect_json_uint_eq(extent, "ntotal",
|
||||||
|
ndirty + nmuzzy + nretained + npinned, row_name);
|
||||||
|
expect_json_uint_eq(extent, "total_bytes",
|
||||||
|
dirty_bytes + muzzy_bytes + retained_bytes + pinned_bytes,
|
||||||
|
row_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
stats_buf_fini(&sbuf);
|
stats_buf_fini(&sbuf);
|
||||||
|
|||||||
Reference in New Issue
Block a user