hyptop: Support for structured output

Introduce a new command line flag ("--format") to specify the output
format in batch mode. Valid options are "pairs" for shell-compatible key
value pairs, "csv" for CSV, "json" for a formatted JSON document, and
"json-seq" for a stream of JSON text sequences as per RFC7464[1].

[1]: https://datatracker.ietf.org/doc/html/rfc7464

Note: Specifying the --format flag implies the --batch_mode flag.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Bjoern Walk
2024-04-29 18:51:51 +02:00
committed by Jan Höppner
parent 589090f79a
commit e61ed4f433
9 changed files with 186 additions and 6 deletions

View File

@@ -25,6 +25,9 @@
#include <time.h>
#include <unistd.h>
#include "lib/util_fmt.h"
#include "lib/util_libc.h"
#include "helper.h"
#include "hyptop.h"
#include "sd.h"
@@ -401,3 +404,40 @@ s64 ht_calculate_smt_util(u64 core_us, u64 thr_us, u64 mgm_us, int thread_per_co
return smt_us;
}
/*
* Add two new key value pairs containing the current time as UNIX epoch and formatted string to a
* structured output object.
*/
void ht_fmt_time(void)
{
struct timeval tv;
struct tm *tm;
char str[30];
gettimeofday(&tv, NULL);
tm = localtime(&tv.tv_sec);
if (!tm)
return;
util_fmt_pair(FMT_PERSIST, "time_epoch", "%lld", mktime(tm));
strftime(str, sizeof(str), "%F %T%z", tm);
util_fmt_pair(FMT_PERSIST | FMT_QUOTE, "time", "%s", str);
}
/*
* Add a new object for available CPU types to a structured output object.
*/
void ht_fmt_cpu_types(void)
{
struct sd_cpu_type *cpu_type;
int i;
util_fmt_obj_start(FMT_DEFAULT, "cputypes");
sd_cpu_type_iterate(cpu_type, i) {
char *cpu_type_str = sd_cpu_type_id(cpu_type);
util_str_tolower(cpu_type_str);
util_fmt_pair(FMT_PERSIST, cpu_type_str, "%i",
sd_cpu_type_cpu_cnt(cpu_type));
}
util_fmt_obj_end(); /* cpus{} */
}

View File

@@ -66,6 +66,12 @@ void ht_print_scroll_bar(int row_cnt, int row_start, int row_bar_start,
int row_bar_bottom, int can_scroll_up,
int can_scroll_down, int with_boder);
/*
* util_fmt helper functions
*/
void ht_fmt_time(void);
void ht_fmt_cpu_types(void);
/*
* Error Macros
*/

View File

@@ -18,6 +18,8 @@
#include <sys/types.h>
#include <time.h>
#include "lib/util_fmt.h"
#include "dg_debugfs.h"
#include "helper.h"
#include "hyptop.h"
@@ -218,6 +220,22 @@ static void l_term_check(void)
" try \"--batch_mode\"\n");
}
/*
* Init util_fmt if --format is specified on the command line.
*/
static void l_fmt_init(void)
{
unsigned int flags = FMT_WARN;
if (!g.o.format_specified)
return;
if (g.o.format == FMT_CSV)
flags |= FMT_QUOTEALL;
if (g.o.format == FMT_JSON || g.o.format == FMT_JSONSEQ)
flags |= FMT_HANDLEINT;
util_fmt_init(stdout, g.o.format, flags, 1);
}
/*
* Init curses
*/
@@ -359,6 +377,7 @@ void __noreturn hyptop_exit(int rc)
int main(int argc, char *argv[])
{
opts_parse(argc, argv);
l_fmt_init();
hyptop_helper_init();
sd_init();
l_dg_init();

View File

@@ -17,6 +17,8 @@
#include <stdlib.h>
#include <termios.h>
#include "lib/util_fmt.h"
#include "helper.h"
#include "nav_desc.h"
#include "table.h"
@@ -52,6 +54,8 @@ struct hyptop_win_opts {
struct hyptop_opts {
unsigned int win_specified;
unsigned int batch_mode_specified;
unsigned int format_specified;
enum util_fmt_t format;
unsigned int iterations_specified;
unsigned int iterations;
unsigned int iterations_act;

View File

@@ -12,6 +12,7 @@
#include <ctype.h>
#include <stdio.h>
#include "lib/util_fmt.h"
#include "lib/util_libc.h"
#include "lib/zt_common.h"
@@ -20,6 +21,7 @@
#include "hyptop.h"
#include "opts.h"
#include "sd.h"
#include "table.h"
static const char l_copyright_str[] = "Copyright IBM Corp. 2010, 2017";
@@ -39,10 +41,16 @@ static char HELP_TEXT[] =
"-S, --sort LETTER Sort field for current window\n"
"-t, --cpu_types TYPE[,..] CPU types used for time calculations\n"
"-b, --batch_mode Use batch mode (no curses)\n"
" --format FORMAT Output format (" FMT_TYPE_NAMES "), implies -b\n"
"-d, --delay SECONDS Delay time between screen updates\n"
"-m, --smt_factor FACTOR Machine generation dependent SMT speedup factor.\n"
"-n, --iterations NUMBER Number of iterations before ending\n";
/*
* Options with long-name only
*/
#define OPT_FORMAT 256 /* --format */
/*
* Initialize default settings
*/
@@ -288,6 +296,23 @@ static void l_batch_mode_set(void)
g.o.batch_mode_specified = 1;
}
/*
* Set the "--format" option
*/
static void l_format_set(const char *str)
{
enum util_fmt_t fmt;
if (!util_fmt_name_to_type(str, &fmt)) {
ERR_EXIT("Unknown format '%s', supported formats: "
FMT_TYPE_NAMES "\n", str);
}
l_batch_mode_set();
g.o.format_specified = 1;
g.o.format = fmt;
}
/*
* Make option consisteny checks at end of command line parsing
*/
@@ -323,6 +348,7 @@ void opts_parse(int argc, char *argv[])
{ "fields", required_argument, NULL, 'f'},
{ "sort_field", required_argument, NULL, 'S'},
{ "cpu_types", required_argument, NULL, 't'},
{ "format", required_argument, NULL, OPT_FORMAT },
{ NULL, 0, NULL, 0 }
};
static const char option_string[] = "vhbd:m:w:s:n:f:t:S:";
@@ -367,6 +393,9 @@ void opts_parse(int argc, char *argv[])
case 'S':
l_sort_field_set(optarg);
break;
case OPT_FORMAT:
l_format_set(optarg);
break;
default:
l_std_usage_exit();
}
@@ -432,8 +461,11 @@ void opts_iterations_next(void)
{
if (g.o.iterations_specified) {
g.o.iterations_act++;
if (g.o.iterations_act >= g.o.iterations)
if (g.o.iterations_act >= g.o.iterations) {
if (g.o.format_specified)
table_fmt_end();
hyptop_exit(0);
}
}
}

View File

@@ -16,6 +16,7 @@
#include <stdlib.h>
#include <string.h>
#include "lib/util_fmt.h"
#include "lib/util_libc.h"
#include "helper.h"
@@ -955,15 +956,86 @@ static void l_table_print_all(struct table *t)
"-------------------------\n");
}
/*
* Print one table row as structured output
*
* Note: column filtering and sorting is explicitly ignored because the
* assumption is that these operations can be trivially performed by the
* consumer.
*/
static void l_row_print_formatted(struct table *t, struct table_row *row)
{
struct table_col *col;
int col_nr;
table_col_iterate(t, col, col_nr) {
unsigned int flags = 0;
struct table_entry *e = &row->entries[col_nr];
if (row == t->row_last && col_nr == 0)
continue;
if (table_col_needs_quotes(col))
flags = FMT_QUOTE;
util_fmt_pair(flags, col->head, "%s", e->str);
}
}
/*
* Print table as structured output
*/
static void l_table_print_all_formatted(struct table *t)
{
struct table_row *row;
util_fmt_obj_start(FMT_ROW, "iteration");
util_fmt_pair(FMT_PERSIST, "iteration", "%u", g.o.iterations_act);
ht_fmt_time();
ht_fmt_cpu_types();
if (strcmp(g.o.cur_win->id, "sys_list") == 0)
util_fmt_obj_start(FMT_LIST, "systems");
else
util_fmt_obj_start(FMT_LIST, "cpus");
util_list_iterate(&t->row_list, row) {
util_fmt_obj_start(FMT_ROW, "entry");
l_row_print_formatted(t, row);
util_fmt_obj_end(); /* entry */
}
util_fmt_obj_end(); /* systems[] */
util_fmt_obj_start(FMT_DEFAULT, "summary");
l_row_print_formatted(t, t->row_last);
util_fmt_obj_end(); /* summary{} */
util_fmt_obj_end(); /* iteration */
}
void table_fmt_start(void)
{
if (!g.o.format_specified)
return;
if (g.o.format != FMT_JSONSEQ)
util_fmt_obj_start(FMT_LIST, "hyptop");
}
void table_fmt_end(void)
{
if (!g.o.format_specified)
return;
if (g.o.format != FMT_JSONSEQ)
util_fmt_obj_end(); /* hyptop[] */
}
/*
* Print table to screen
*/
void table_print(struct table *t)
{
if (g.o.batch_mode_specified)
l_table_print_all(t);
else
if (g.o.batch_mode_specified) {
if (!g.o.format_specified)
l_table_print_all(t);
else
l_table_print_all_formatted(t);
} else {
l_table_print_curses(t);
}
}
/*

View File

@@ -390,6 +390,9 @@ extern struct table_row *table_row_alloc(struct table *t);
extern void table_scroll_down(struct table *t, enum table_scroll_unit unit);
extern void table_scroll_up(struct table *t, enum table_scroll_unit unit);
extern void table_fmt_start(void);
extern void table_fmt_end(void);
/*
* Entry add functions
*/

View File

@@ -194,7 +194,8 @@ static void l_table_update_term(struct hyptop_win *win)
{
(void) win;
ht_print_head(l_sys_id);
if (!g.o.format_specified)
ht_print_head(l_sys_id);
table_print(l_t);
}
@@ -300,6 +301,7 @@ static void l_run(struct hyptop_win *win)
/* Reformat table when entering window */
table_rebuild(l_t);
table_fmt_start();
while (1) {
if (l_table_create()) {
if (g.o.batch_mode_specified)

View File

@@ -206,7 +206,8 @@ static void l_table_update_term(struct hyptop_win *win)
{
(void) win;
ht_print_head(NULL);
if (!g.o.format_specified)
ht_print_head(NULL);
table_print(l_t);
}
@@ -310,6 +311,7 @@ static void l_run(struct hyptop_win *win)
/* Reformat table when entering window */
table_rebuild(l_t);
table_fmt_start();
while (1) {
l_table_create();
hyptop_update_term();