mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
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:
@@ -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{} */
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user