Skip to content

Commit abaa525

Browse files
mhiramatrostedt
authored andcommitted
tracing: Add .percent suffix option to histogram values
Add .percent suffix option to show the histogram values in percentage. This feature is useful when we need yo undersntand the overall trend for the histograms of large values. E.g. this shows the runtime percentage for each tasks. ------ # cd /sys/kernel/debug/tracing/ # echo hist:keys=pid:vals=hitcount,runtime.percent: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.percent:sort=pid:size=2048 [active] # { pid: 8 } hitcount: 7 runtime (%): 4.14 { pid: 14 } hitcount: 5 runtime (%): 3.69 { pid: 16 } hitcount: 11 runtime (%): 3.41 { pid: 61 } hitcount: 41 runtime (%): 19.75 { pid: 65 } hitcount: 4 runtime (%): 1.48 { pid: 70 } hitcount: 6 runtime (%): 3.60 { pid: 72 } hitcount: 2 runtime (%): 1.10 { pid: 144 } hitcount: 10 runtime (%): 32.01 { pid: 151 } hitcount: 8 runtime (%): 22.66 { pid: 152 } hitcount: 2 runtime (%): 8.10 Totals: Hits: 96 Entries: 10 Dropped: 0 ----- Link: https://lore.kernel.org/linux-trace-kernel/166610813077.56030.4238090506973562347.stgit@devnote2 Signed-off-by: Masami Hiramatsu (Google) <[email protected]> Reviewed-by: Tom Zanussi <[email protected]> Tested-by: Tom Zanussi <[email protected]>
1 parent 5f2e094 commit abaa525

File tree

2 files changed

+78
-15
lines changed

2 files changed

+78
-15
lines changed

kernel/trace/trace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5724,7 +5724,8 @@ static const char readme_msg[] =
57245724
"\t .syscall display a syscall id as a syscall name\n"
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"
5727-
"\t .usecs display a common_timestamp in microseconds\n\n"
5727+
"\t .usecs display a common_timestamp in microseconds\n"
5728+
"\t .percent display a number of percentage value\n\n"
57285729
"\t The 'pause' parameter can be used to pause an existing hist\n"
57295730
"\t trigger or to start a hist trigger but not log any events\n"
57305731
"\t until told to do so. 'continue' can be used to start or\n"

kernel/trace/trace_events_hist.c

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ enum hist_field_flags {
506506
HIST_FIELD_FL_ALIAS = 1 << 16,
507507
HIST_FIELD_FL_BUCKET = 1 << 17,
508508
HIST_FIELD_FL_CONST = 1 << 18,
509+
HIST_FIELD_FL_PERCENT = 1 << 19,
509510
};
510511

511512
struct var_defs {
@@ -1707,6 +1708,8 @@ static const char *get_hist_field_flags(struct hist_field *hist_field)
17071708
flags_str = "buckets";
17081709
else if (hist_field->flags & HIST_FIELD_FL_TIMESTAMP_USECS)
17091710
flags_str = "usecs";
1711+
else if (hist_field->flags & HIST_FIELD_FL_PERCENT)
1712+
flags_str = "percent";
17101713

17111714
return flags_str;
17121715
}
@@ -2315,6 +2318,10 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
23152318
if (ret || !(*buckets))
23162319
goto error;
23172320
*flags |= HIST_FIELD_FL_BUCKET;
2321+
} else if (strncmp(modifier, "percent", 7) == 0) {
2322+
if (*flags & (HIST_FIELD_FL_VAR | HIST_FIELD_FL_KEY))
2323+
goto error;
2324+
*flags |= HIST_FIELD_FL_PERCENT;
23182325
} else {
23192326
error:
23202327
hist_err(tr, HIST_ERR_BAD_FIELD_MODIFIER, errpos(modifier));
@@ -5291,33 +5298,69 @@ static void hist_trigger_print_key(struct seq_file *m,
52915298
seq_puts(m, "}");
52925299
}
52935300

5301+
/* Get the 100 times of the percentage of @val in @total */
5302+
static inline unsigned int __get_percentage(u64 val, u64 total)
5303+
{
5304+
if (!total)
5305+
goto div0;
5306+
5307+
if (val < (U64_MAX / 10000))
5308+
return (unsigned int)div64_ul(val * 10000, total);
5309+
5310+
total = div64_u64(total, 10000);
5311+
if (!total)
5312+
goto div0;
5313+
5314+
return (unsigned int)div64_ul(val, total);
5315+
div0:
5316+
return val ? UINT_MAX : 0;
5317+
}
5318+
5319+
static void hist_trigger_print_val(struct seq_file *m, unsigned int idx,
5320+
const char *field_name, unsigned long flags,
5321+
u64 *totals, struct tracing_map_elt *elt)
5322+
{
5323+
u64 val = tracing_map_read_sum(elt, idx);
5324+
unsigned int pc;
5325+
5326+
if (flags & HIST_FIELD_FL_PERCENT) {
5327+
pc = __get_percentage(val, totals[idx]);
5328+
if (pc == UINT_MAX)
5329+
seq_printf(m, " %s (%%):[ERROR]", field_name);
5330+
else
5331+
seq_printf(m, " %s (%%): %3u.%02u", field_name,
5332+
pc / 100, pc % 100);
5333+
} else if (flags & HIST_FIELD_FL_HEX) {
5334+
seq_printf(m, " %s: %10llx", field_name, val);
5335+
} else {
5336+
seq_printf(m, " %s: %10llu", field_name, val);
5337+
}
5338+
}
5339+
52945340
static void hist_trigger_entry_print(struct seq_file *m,
52955341
struct hist_trigger_data *hist_data,
5342+
u64 *totals,
52965343
void *key,
52975344
struct tracing_map_elt *elt)
52985345
{
52995346
const char *field_name;
5300-
unsigned int i;
5347+
unsigned int i = HITCOUNT_IDX;
5348+
unsigned long flags;
53015349

53025350
hist_trigger_print_key(m, hist_data, key, elt);
53035351

5304-
seq_printf(m, " hitcount: %10llu",
5305-
tracing_map_read_sum(elt, HITCOUNT_IDX));
5352+
/* At first, show the raw hitcount always */
5353+
hist_trigger_print_val(m, i, "hitcount", 0, totals, elt);
53065354

53075355
for (i = 1; i < hist_data->n_vals; i++) {
53085356
field_name = hist_field_name(hist_data->fields[i], 0);
5357+
flags = hist_data->fields[i]->flags;
53095358

5310-
if (hist_data->fields[i]->flags & HIST_FIELD_FL_VAR ||
5311-
hist_data->fields[i]->flags & HIST_FIELD_FL_EXPR)
5359+
if (flags & HIST_FIELD_FL_VAR || flags & HIST_FIELD_FL_EXPR)
53125360
continue;
53135361

5314-
if (hist_data->fields[i]->flags & HIST_FIELD_FL_HEX) {
5315-
seq_printf(m, " %s: %10llx", field_name,
5316-
tracing_map_read_sum(elt, i));
5317-
} else {
5318-
seq_printf(m, " %s: %10llu", field_name,
5319-
tracing_map_read_sum(elt, i));
5320-
}
5362+
seq_puts(m, " ");
5363+
hist_trigger_print_val(m, i, field_name, flags, totals, elt);
53215364
}
53225365

53235366
print_actions(m, hist_data, elt);
@@ -5330,19 +5373,38 @@ static int print_entries(struct seq_file *m,
53305373
{
53315374
struct tracing_map_sort_entry **sort_entries = NULL;
53325375
struct tracing_map *map = hist_data->map;
5333-
int i, n_entries;
5376+
int i, j, n_entries;
5377+
u64 *totals = NULL;
53345378

53355379
n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
53365380
hist_data->n_sort_keys,
53375381
&sort_entries);
53385382
if (n_entries < 0)
53395383
return n_entries;
53405384

5385+
for (j = 0; j < hist_data->n_vals; j++) {
5386+
if (!(hist_data->fields[j]->flags & HIST_FIELD_FL_PERCENT))
5387+
continue;
5388+
if (!totals) {
5389+
totals = kcalloc(hist_data->n_vals, sizeof(u64),
5390+
GFP_KERNEL);
5391+
if (!totals) {
5392+
n_entries = -ENOMEM;
5393+
goto out;
5394+
}
5395+
}
5396+
for (i = 0; i < n_entries; i++)
5397+
totals[j] += tracing_map_read_sum(
5398+
sort_entries[i]->elt, j);
5399+
}
5400+
53415401
for (i = 0; i < n_entries; i++)
5342-
hist_trigger_entry_print(m, hist_data,
5402+
hist_trigger_entry_print(m, hist_data, totals,
53435403
sort_entries[i]->key,
53445404
sort_entries[i]->elt);
53455405

5406+
kfree(totals);
5407+
out:
53465408
tracing_map_destroy_sort_entries(sort_entries, n_entries);
53475409

53485410
return n_entries;

0 commit comments

Comments
 (0)