Skip to content

Commit a2c5425

Browse files
mhiramatrostedt
authored andcommitted
tracing: Add .graph suffix option to histogram value
Add the .graph suffix which shows the bar graph of the histogram value. For example, the below example shows that the bar graph of the histogram of the runtime for each tasks. ------ # cd /sys/kernel/debug/tracing/ # echo hist:keys=pid:vals=runtime.graph:sort=pid > \ events/sched/sched_stat_runtime/trigger # sleep 10 # cat events/sched/sched_stat_runtime/hist # event histogram # # trigger info: hist:keys=pid:vals=hitcount,runtime.graph:sort=pid:size=2048 [active] # { pid: 14 } hitcount: 2 runtime: { pid: 16 } hitcount: 8 runtime: { pid: 26 } hitcount: 1 runtime: { pid: 57 } hitcount: 3 runtime: { pid: 61 } hitcount: 20 runtime: ### { pid: 66 } hitcount: 2 runtime: { pid: 70 } hitcount: 3 runtime: { pid: 72 } hitcount: 2 runtime: { pid: 145 } hitcount: 14 runtime: #################### { pid: 152 } hitcount: 5 runtime: ####### { pid: 153 } hitcount: 2 runtime: #### Totals: Hits: 62 Entries: 11 Dropped: 0 ------- Link: https://lore.kernel.org/linux-trace-kernel/166610813953.56030.10944148382315789485.stgit@devnote2 Signed-off-by: Masami Hiramatsu (Google) <[email protected]> Reviewed-by: Tom Zanussi <[email protected]> Tested-by: Tom Zanussi <[email protected]>
1 parent abaa525 commit a2c5425

File tree

2 files changed

+63
-17
lines changed

2 files changed

+63
-17
lines changed

kernel/trace/trace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5725,7 +5725,8 @@ static const char readme_msg[] =
57255725
"\t .log2 display log2 value rather than raw number\n"
57265726
"\t .buckets=size display values in groups of size rather than raw number\n"
57275727
"\t .usecs display a common_timestamp in microseconds\n"
5728-
"\t .percent display a number of percentage value\n\n"
5728+
"\t .percent display a number of percentage value\n"
5729+
"\t .graph display a bar-graph of a value\n\n"
57295730
"\t The 'pause' parameter can be used to pause an existing hist\n"
57305731
"\t trigger or to start a hist trigger but not log any events\n"
57315732
"\t until told to do so. 'continue' can be used to start or\n"

kernel/trace/trace_events_hist.c

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ enum hist_field_flags {
507507
HIST_FIELD_FL_BUCKET = 1 << 17,
508508
HIST_FIELD_FL_CONST = 1 << 18,
509509
HIST_FIELD_FL_PERCENT = 1 << 19,
510+
HIST_FIELD_FL_GRAPH = 1 << 20,
510511
};
511512

512513
struct var_defs {
@@ -1710,6 +1711,8 @@ static const char *get_hist_field_flags(struct hist_field *hist_field)
17101711
flags_str = "usecs";
17111712
else if (hist_field->flags & HIST_FIELD_FL_PERCENT)
17121713
flags_str = "percent";
1714+
else if (hist_field->flags & HIST_FIELD_FL_GRAPH)
1715+
flags_str = "graph";
17131716

17141717
return flags_str;
17151718
}
@@ -2322,6 +2325,10 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
23222325
if (*flags & (HIST_FIELD_FL_VAR | HIST_FIELD_FL_KEY))
23232326
goto error;
23242327
*flags |= HIST_FIELD_FL_PERCENT;
2328+
} else if (strncmp(modifier, "graph", 5) == 0) {
2329+
if (*flags & (HIST_FIELD_FL_VAR | HIST_FIELD_FL_KEY))
2330+
goto error;
2331+
*flags |= HIST_FIELD_FL_GRAPH;
23252332
} else {
23262333
error:
23272334
hist_err(tr, HIST_ERR_BAD_FIELD_MODIFIER, errpos(modifier));
@@ -5316,20 +5323,52 @@ static inline unsigned int __get_percentage(u64 val, u64 total)
53165323
return val ? UINT_MAX : 0;
53175324
}
53185325

5326+
#define BAR_CHAR '#'
5327+
5328+
static inline const char *__fill_bar_str(char *buf, int size, u64 val, u64 max)
5329+
{
5330+
unsigned int len = __get_percentage(val, max);
5331+
int i;
5332+
5333+
if (len == UINT_MAX) {
5334+
snprintf(buf, size, "[ERROR]");
5335+
return buf;
5336+
}
5337+
5338+
len = len * size / 10000;
5339+
for (i = 0; i < len && i < size; i++)
5340+
buf[i] = BAR_CHAR;
5341+
while (i < size)
5342+
buf[i++] = ' ';
5343+
buf[size] = '\0';
5344+
5345+
return buf;
5346+
}
5347+
5348+
struct hist_val_stat {
5349+
u64 max;
5350+
u64 total;
5351+
};
5352+
53195353
static void hist_trigger_print_val(struct seq_file *m, unsigned int idx,
53205354
const char *field_name, unsigned long flags,
5321-
u64 *totals, struct tracing_map_elt *elt)
5355+
struct hist_val_stat *stats,
5356+
struct tracing_map_elt *elt)
53225357
{
53235358
u64 val = tracing_map_read_sum(elt, idx);
53245359
unsigned int pc;
5360+
char bar[21];
53255361

53265362
if (flags & HIST_FIELD_FL_PERCENT) {
5327-
pc = __get_percentage(val, totals[idx]);
5363+
pc = __get_percentage(val, stats[idx].total);
53285364
if (pc == UINT_MAX)
53295365
seq_printf(m, " %s (%%):[ERROR]", field_name);
53305366
else
53315367
seq_printf(m, " %s (%%): %3u.%02u", field_name,
53325368
pc / 100, pc % 100);
5369+
} else if (flags & HIST_FIELD_FL_GRAPH) {
5370+
seq_printf(m, " %s: %20s", field_name,
5371+
__fill_bar_str(bar, 20, val, stats[idx].max));
53335372
} else if (flags & HIST_FIELD_FL_HEX) {
53345373
seq_printf(m, " %s: %10llx", field_name, val);
53355374
} else {
@@ -5339,7 +5378,7 @@ static void hist_trigger_print_val(struct seq_file *m, unsigned int idx,
53395378

53405379
static void hist_trigger_entry_print(struct seq_file *m,
53415380
struct hist_trigger_data *hist_data,
5342-
u64 *totals,
5381+
struct hist_val_stat *stats,
53435382
void *key,
53445383
struct tracing_map_elt *elt)
53455384
{
@@ -5350,7 +5389,7 @@ static void hist_trigger_entry_print(struct seq_file *m,
53505389
hist_trigger_print_key(m, hist_data, key, elt);
53515390

53525391
/* At first, show the raw hitcount always */
5353-
hist_trigger_print_val(m, i, "hitcount", 0, totals, elt);
5392+
hist_trigger_print_val(m, i, "hitcount", 0, stats, elt);
53545393

53555394
for (i = 1; i < hist_data->n_vals; i++) {
53565395
field_name = hist_field_name(hist_data->fields[i], 0);
@@ -5360,7 +5399,7 @@ static void hist_trigger_entry_print(struct seq_file *m,
53605399
continue;
53615400

53625401
seq_puts(m, " ");
5363-
hist_trigger_print_val(m, i, field_name, flags, totals, elt);
5402+
hist_trigger_print_val(m, i, field_name, flags, stats, elt);
53645403
}
53655404

53665405
print_actions(m, hist_data, elt);
@@ -5374,36 +5413,42 @@ static int print_entries(struct seq_file *m,
53745413
struct tracing_map_sort_entry **sort_entries = NULL;
53755414
struct tracing_map *map = hist_data->map;
53765415
int i, j, n_entries;
5377-
u64 *totals = NULL;
5416+
struct hist_val_stat *stats = NULL;
5417+
u64 val;
53785418

53795419
n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
53805420
hist_data->n_sort_keys,
53815421
&sort_entries);
53825422
if (n_entries < 0)
53835423
return n_entries;
53845424

5425+
/* Calculate the max and the total for each field if needed. */
53855426
for (j = 0; j < hist_data->n_vals; j++) {
5386-
if (!(hist_data->fields[j]->flags & HIST_FIELD_FL_PERCENT))
5427+
if (!(hist_data->fields[j]->flags &
5428+
(HIST_FIELD_FL_PERCENT | HIST_FIELD_FL_GRAPH)))
53875429
continue;
5388-
if (!totals) {
5389-
totals = kcalloc(hist_data->n_vals, sizeof(u64),
5390-
GFP_KERNEL);
5391-
if (!totals) {
5430+
if (!stats) {
5431+
stats = kcalloc(hist_data->n_vals, sizeof(*stats),
5432+
GFP_KERNEL);
5433+
if (!stats) {
53925434
n_entries = -ENOMEM;
53935435
goto out;
53945436
}
53955437
}
5396-
for (i = 0; i < n_entries; i++)
5397-
totals[j] += tracing_map_read_sum(
5398-
sort_entries[i]->elt, j);
5438+
for (i = 0; i < n_entries; i++) {
5439+
val = tracing_map_read_sum(sort_entries[i]->elt, j);
5440+
stats[j].total += val;
5441+
if (stats[j].max < val)
5442+
stats[j].max = val;
5443+
}
53995444
}
54005445

54015446
for (i = 0; i < n_entries; i++)
5402-
hist_trigger_entry_print(m, hist_data, totals,
5447+
hist_trigger_entry_print(m, hist_data, stats,
54035448
sort_entries[i]->key,
54045449
sort_entries[i]->elt);
54055450

5406-
kfree(totals);
5451+
kfree(stats);
54075452
out:
54085453
tracing_map_destroy_sort_entries(sort_entries, n_entries);
54095454

0 commit comments

Comments
 (0)