Emitter: Add support for row-based output in table mode.

This is needed for things like mutex stats in table mode.
This commit is contained in:
David Goldblatt 2018-03-02 14:11:27 -08:00 committed by David Goldblatt
parent 9e1846b004
commit ebe0b5f828
2 changed files with 123 additions and 7 deletions

View File

@ -1,6 +1,8 @@
#ifndef JEMALLOC_INTERNAL_EMITTER_H #ifndef JEMALLOC_INTERNAL_EMITTER_H
#define JEMALLOC_INTERNAL_EMITTER_H #define JEMALLOC_INTERNAL_EMITTER_H
#include "jemalloc/internal/ql.h"
typedef enum emitter_output_e emitter_output_t; typedef enum emitter_output_e emitter_output_t;
enum emitter_output_e { enum emitter_output_e {
emitter_output_json, emitter_output_json,
@ -25,8 +27,50 @@ enum emitter_type_e {
emitter_type_size, emitter_type_size,
emitter_type_ssize, emitter_type_ssize,
emitter_type_string, emitter_type_string,
/*
* A title is a column title in a table; it's just a string, but it's
* not quoted.
*/
emitter_type_title,
}; };
typedef struct emitter_col_s emitter_col_t;
struct emitter_col_s {
/* Filled in by the user. */
emitter_justify_t justify;
int width;
emitter_type_t type;
union {
bool bool_val;
int int_val;
unsigned unsigned_val;
uint32_t uint32_val;
uint64_t uint64_val;
size_t size_val;
ssize_t ssize_val;
const char *str_val;
};
/* Filled in by initialization. */
ql_elm(emitter_col_t) link;
};
typedef struct emitter_row_s emitter_row_t;
struct emitter_row_s {
ql_head(emitter_col_t) cols;
};
static inline void
emitter_row_init(emitter_row_t *row) {
ql_new(&row->cols);
}
static inline void
emitter_col_init(emitter_col_t *col, emitter_row_t *row) {
ql_elm_new(col, link);
ql_tail_insert(&row->cols, col, link);
}
typedef struct emitter_s emitter_t; typedef struct emitter_s emitter_t;
struct emitter_s { struct emitter_s {
emitter_output_t output; emitter_output_t output;
@ -141,12 +185,6 @@ emitter_print_value(emitter_t *emitter, emitter_justify_t justify, int width,
* anywhere near the fmt size. * anywhere near the fmt size.
*/ */
assert(str_written < BUF_SIZE); assert(str_written < BUF_SIZE);
/*
* We don't support justified quoted string primitive values for
* now. Fortunately, we don't want to emit them.
*/
emitter_gen_fmt(fmt, FMT_SIZE, "s", justify, width); emitter_gen_fmt(fmt, FMT_SIZE, "s", justify, width);
emitter_printf(emitter, fmt, buf); emitter_printf(emitter, fmt, buf);
break; break;
@ -156,6 +194,9 @@ emitter_print_value(emitter_t *emitter, emitter_justify_t justify, int width,
case emitter_type_uint64: case emitter_type_uint64:
EMIT_SIMPLE(uint64_t, FMTu64) EMIT_SIMPLE(uint64_t, FMTu64)
break; break;
case emitter_type_title:
EMIT_SIMPLE(char *const, "s");
break;
default: default:
unreachable(); unreachable();
} }
@ -378,4 +419,17 @@ emitter_json_arr_value(emitter_t *emitter, emitter_type_t value_type,
} }
} }
static inline void
emitter_table_row(emitter_t *emitter, emitter_row_t *row) {
if (emitter->output != emitter_output_table) {
return;
}
emitter_col_t *col;
ql_foreach(col, &row->cols, link) {
emitter_print_value(emitter, col->justify, col->width,
col->type, (const void *)&col->bool_val);
}
emitter_table_printf(emitter, "\n");
}
#endif /* JEMALLOC_INTERNAL_EMITTER_H */ #endif /* JEMALLOC_INTERNAL_EMITTER_H */

View File

@ -217,6 +217,10 @@ emit_types(emitter_t *emitter) {
emitter_kv(emitter, "k6", "K6", emitter_type_string, &str); emitter_kv(emitter, "k6", "K6", emitter_type_string, &str);
emitter_kv(emitter, "k7", "K7", emitter_type_uint32, &u32); emitter_kv(emitter, "k7", "K7", emitter_type_uint32, &u32);
emitter_kv(emitter, "k8", "K8", emitter_type_uint64, &u64); emitter_kv(emitter, "k8", "K8", emitter_type_uint64, &u64);
/*
* We don't test the title type, since it's only used for tables. It's
* tested in the emitter_table_row tests.
*/
emitter_end(emitter); emitter_end(emitter);
} }
@ -339,6 +343,63 @@ TEST_BEGIN(test_json_arr) {
} }
TEST_END TEST_END
static void
emit_table_row(emitter_t *emitter) {
emitter_begin(emitter);
emitter_row_t row;
emitter_col_t abc = {emitter_justify_left, 10, emitter_type_title};
abc.str_val = "ABC title";
emitter_col_t def = {emitter_justify_right, 15, emitter_type_title};
def.str_val = "DEF title";
emitter_col_t ghi = {emitter_justify_right, 5, emitter_type_title};
ghi.str_val = "GHI";
emitter_row_init(&row);
emitter_col_init(&abc, &row);
emitter_col_init(&def, &row);
emitter_col_init(&ghi, &row);
emitter_table_row(emitter, &row);
abc.type = emitter_type_int;
def.type = emitter_type_bool;
ghi.type = emitter_type_int;
abc.int_val = 123;
def.bool_val = true;
ghi.int_val = 456;
emitter_table_row(emitter, &row);
abc.int_val = 789;
def.bool_val = false;
ghi.int_val = 1011;
emitter_table_row(emitter, &row);
abc.type = emitter_type_string;
abc.str_val = "a string";
def.bool_val = false;
ghi.type = emitter_type_title;
ghi.str_val = "ghi";
emitter_table_row(emitter, &row);
emitter_end(emitter);
}
static const char *table_row_json =
"{\n"
"}\n";
static const char *table_row_table =
"ABC title DEF title GHI\n"
"123 true 456\n"
"789 false 1011\n"
"\"a string\" false ghi\n";
TEST_BEGIN(test_table_row) {
assert_emit_output(&emit_table_row, table_row_json, table_row_table);
}
TEST_END
int int
main(void) { main(void) {
return test_no_reentrancy( return test_no_reentrancy(
@ -347,5 +408,6 @@ main(void) {
test_nested_dict, test_nested_dict,
test_types, test_types,
test_modal, test_modal,
test_json_arr); test_json_arr,
test_table_row);
} }