Skip to content

Commit 2d19bd7

Browse files
Tom Zanussirostedt
authored andcommitted
tracing: Add hist_debug trace event files for histogram debugging
Add a new "hist_debug" file for each trace event, which when read will dump out a bunch of internal details about the hist triggers defined on that event. This is normally off but can be enabled by saying 'y' to the new CONFIG_HIST_TRIGGERS_DEBUG config option. This is in support of the new Documentation file describing histogram internals, Documentation/trace/histogram-design.rst, which was requested by developers trying to understand the internals when extending or making use of the hist triggers for higher-level tools. The histogram-design.rst documentation refers to the hist_debug files and demonstrates their use with output in the test examples. Link: http://lkml.kernel.org/r/77914c22b0ba493d9783c53bbfbc6087d6a7e1b1.1585941485.git.zanussi@kernel.org Signed-off-by: Tom Zanussi <[email protected]> Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent 16b585f commit 2d19bd7

File tree

4 files changed

+301
-0
lines changed

4 files changed

+301
-0
lines changed

kernel/trace/Kconfig

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,29 @@ config KPROBE_EVENT_GEN_TEST
847847

848848
If unsure, say N.
849849

850+
config HIST_TRIGGERS_DEBUG
851+
bool "Hist trigger debug support"
852+
depends on HIST_TRIGGERS
853+
help
854+
Add "hist_debug" file for each event, which when read will
855+
dump out a bunch of internal details about the hist triggers
856+
defined on that event.
857+
858+
The hist_debug file serves a couple of purposes:
859+
860+
- Helps developers verify that nothing is broken.
861+
862+
- Provides educational information to support the details
863+
of the hist trigger internals as described by
864+
Documentation/trace/histogram-design.rst.
865+
866+
The hist_debug output only covers the data structures
867+
related to the histogram definitions themselves and doesn't
868+
display the internals of map buckets or variable values of
869+
running histograms.
870+
871+
If unsure, say N.
872+
850873
endif # FTRACE
851874

852875
endif # TRACING_SUPPORT

kernel/trace/trace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,6 +1661,7 @@ extern struct list_head ftrace_events;
16611661

16621662
extern const struct file_operations event_trigger_fops;
16631663
extern const struct file_operations event_hist_fops;
1664+
extern const struct file_operations event_hist_debug_fops;
16641665
extern const struct file_operations event_inject_fops;
16651666

16661667
#ifdef CONFIG_HIST_TRIGGERS

kernel/trace/trace_events.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,10 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file)
22082208
#ifdef CONFIG_HIST_TRIGGERS
22092209
trace_create_file("hist", 0444, file->dir, file,
22102210
&event_hist_fops);
2211+
#endif
2212+
#ifdef CONFIG_HIST_TRIGGERS_DEBUG
2213+
trace_create_file("hist_debug", 0444, file->dir, file,
2214+
&event_hist_debug_fops);
22112215
#endif
22122216
trace_create_file("format", 0444, file->dir, call,
22132217
&ftrace_event_format_fops);

kernel/trace/trace_events_hist.c

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6478,6 +6478,279 @@ const struct file_operations event_hist_fops = {
64786478
.release = single_release,
64796479
};
64806480

6481+
#ifdef CONFIG_HIST_TRIGGERS_DEBUG
6482+
static void hist_field_debug_show_flags(struct seq_file *m,
6483+
unsigned long flags)
6484+
{
6485+
seq_puts(m, " flags:\n");
6486+
6487+
if (flags & HIST_FIELD_FL_KEY)
6488+
seq_puts(m, " HIST_FIELD_FL_KEY\n");
6489+
else if (flags & HIST_FIELD_FL_HITCOUNT)
6490+
seq_puts(m, " VAL: HIST_FIELD_FL_HITCOUNT\n");
6491+
else if (flags & HIST_FIELD_FL_VAR)
6492+
seq_puts(m, " HIST_FIELD_FL_VAR\n");
6493+
else if (flags & HIST_FIELD_FL_VAR_REF)
6494+
seq_puts(m, " HIST_FIELD_FL_VAR_REF\n");
6495+
else
6496+
seq_puts(m, " VAL: normal u64 value\n");
6497+
6498+
if (flags & HIST_FIELD_FL_ALIAS)
6499+
seq_puts(m, " HIST_FIELD_FL_ALIAS\n");
6500+
}
6501+
6502+
static int hist_field_debug_show(struct seq_file *m,
6503+
struct hist_field *field, unsigned long flags)
6504+
{
6505+
if ((field->flags & flags) != flags) {
6506+
seq_printf(m, "ERROR: bad flags - %lx\n", flags);
6507+
return -EINVAL;
6508+
}
6509+
6510+
hist_field_debug_show_flags(m, field->flags);
6511+
if (field->field)
6512+
seq_printf(m, " ftrace_event_field name: %s\n",
6513+
field->field->name);
6514+
6515+
if (field->flags & HIST_FIELD_FL_VAR) {
6516+
seq_printf(m, " var.name: %s\n", field->var.name);
6517+
seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n",
6518+
field->var.idx);
6519+
}
6520+
6521+
if (field->flags & HIST_FIELD_FL_ALIAS)
6522+
seq_printf(m, " var_ref_idx (into hist_data->var_refs[]): %u\n",
6523+
field->var_ref_idx);
6524+
6525+
if (field->flags & HIST_FIELD_FL_VAR_REF) {
6526+
seq_printf(m, " name: %s\n", field->name);
6527+
seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n",
6528+
field->var.idx);
6529+
seq_printf(m, " var.hist_data: %p\n", field->var.hist_data);
6530+
seq_printf(m, " var_ref_idx (into hist_data->var_refs[]): %u\n",
6531+
field->var_ref_idx);
6532+
if (field->system)
6533+
seq_printf(m, " system: %s\n", field->system);
6534+
if (field->event_name)
6535+
seq_printf(m, " event_name: %s\n", field->event_name);
6536+
}
6537+
6538+
seq_printf(m, " type: %s\n", field->type);
6539+
seq_printf(m, " size: %u\n", field->size);
6540+
seq_printf(m, " is_signed: %u\n", field->is_signed);
6541+
6542+
return 0;
6543+
}
6544+
6545+
static int field_var_debug_show(struct seq_file *m,
6546+
struct field_var *field_var, unsigned int i,
6547+
bool save_vars)
6548+
{
6549+
const char *vars_name = save_vars ? "save_vars" : "field_vars";
6550+
struct hist_field *field;
6551+
int ret = 0;
6552+
6553+
seq_printf(m, "\n hist_data->%s[%d]:\n", vars_name, i);
6554+
6555+
field = field_var->var;
6556+
6557+
seq_printf(m, "\n %s[%d].var:\n", vars_name, i);
6558+
6559+
hist_field_debug_show_flags(m, field->flags);
6560+
seq_printf(m, " var.name: %s\n", field->var.name);
6561+
seq_printf(m, " var.idx (into tracing_map_elt.vars[]): %u\n",
6562+
field->var.idx);
6563+
6564+
field = field_var->val;
6565+
6566+
seq_printf(m, "\n %s[%d].val:\n", vars_name, i);
6567+
if (field->field)
6568+
seq_printf(m, " ftrace_event_field name: %s\n",
6569+
field->field->name);
6570+
else {
6571+
ret = -EINVAL;
6572+
goto out;
6573+
}
6574+
6575+
seq_printf(m, " type: %s\n", field->type);
6576+
seq_printf(m, " size: %u\n", field->size);
6577+
seq_printf(m, " is_signed: %u\n", field->is_signed);
6578+
out:
6579+
return ret;
6580+
}
6581+
6582+
static int hist_action_debug_show(struct seq_file *m,
6583+
struct action_data *data, int i)
6584+
{
6585+
int ret = 0;
6586+
6587+
if (data->handler == HANDLER_ONMAX ||
6588+
data->handler == HANDLER_ONCHANGE) {
6589+
seq_printf(m, "\n hist_data->actions[%d].track_data.var_ref:\n", i);
6590+
ret = hist_field_debug_show(m, data->track_data.var_ref,
6591+
HIST_FIELD_FL_VAR_REF);
6592+
if (ret)
6593+
goto out;
6594+
6595+
seq_printf(m, "\n hist_data->actions[%d].track_data.track_var:\n", i);
6596+
ret = hist_field_debug_show(m, data->track_data.track_var,
6597+
HIST_FIELD_FL_VAR);
6598+
if (ret)
6599+
goto out;
6600+
}
6601+
6602+
if (data->handler == HANDLER_ONMATCH) {
6603+
seq_printf(m, "\n hist_data->actions[%d].match_data.event_system: %s\n",
6604+
i, data->match_data.event_system);
6605+
seq_printf(m, " hist_data->actions[%d].match_data.event: %s\n",
6606+
i, data->match_data.event);
6607+
}
6608+
out:
6609+
return ret;
6610+
}
6611+
6612+
static int hist_actions_debug_show(struct seq_file *m,
6613+
struct hist_trigger_data *hist_data)
6614+
{
6615+
int i, ret = 0;
6616+
6617+
if (hist_data->n_actions)
6618+
seq_puts(m, "\n action tracking variables (for onmax()/onchange()/onmatch()):\n");
6619+
6620+
for (i = 0; i < hist_data->n_actions; i++) {
6621+
struct action_data *action = hist_data->actions[i];
6622+
6623+
ret = hist_action_debug_show(m, action, i);
6624+
if (ret)
6625+
goto out;
6626+
}
6627+
6628+
if (hist_data->n_save_vars)
6629+
seq_puts(m, "\n save action variables (save() params):\n");
6630+
6631+
for (i = 0; i < hist_data->n_save_vars; i++) {
6632+
ret = field_var_debug_show(m, hist_data->save_vars[i], i, true);
6633+
if (ret)
6634+
goto out;
6635+
}
6636+
out:
6637+
return ret;
6638+
}
6639+
6640+
static void hist_trigger_debug_show(struct seq_file *m,
6641+
struct event_trigger_data *data, int n)
6642+
{
6643+
struct hist_trigger_data *hist_data;
6644+
int i, ret;
6645+
6646+
if (n > 0)
6647+
seq_puts(m, "\n\n");
6648+
6649+
seq_puts(m, "# event histogram\n#\n# trigger info: ");
6650+
data->ops->print(m, data->ops, data);
6651+
seq_puts(m, "#\n\n");
6652+
6653+
hist_data = data->private_data;
6654+
6655+
seq_printf(m, "hist_data: %p\n\n", hist_data);
6656+
seq_printf(m, " n_vals: %u\n", hist_data->n_vals);
6657+
seq_printf(m, " n_keys: %u\n", hist_data->n_keys);
6658+
seq_printf(m, " n_fields: %u\n", hist_data->n_fields);
6659+
6660+
seq_puts(m, "\n val fields:\n\n");
6661+
6662+
seq_puts(m, " hist_data->fields[0]:\n");
6663+
ret = hist_field_debug_show(m, hist_data->fields[0],
6664+
HIST_FIELD_FL_HITCOUNT);
6665+
if (ret)
6666+
return;
6667+
6668+
for (i = 1; i < hist_data->n_vals; i++) {
6669+
seq_printf(m, "\n hist_data->fields[%d]:\n", i);
6670+
ret = hist_field_debug_show(m, hist_data->fields[i], 0);
6671+
if (ret)
6672+
return;
6673+
}
6674+
6675+
seq_puts(m, "\n key fields:\n");
6676+
6677+
for (i = hist_data->n_vals; i < hist_data->n_fields; i++) {
6678+
seq_printf(m, "\n hist_data->fields[%d]:\n", i);
6679+
ret = hist_field_debug_show(m, hist_data->fields[i],
6680+
HIST_FIELD_FL_KEY);
6681+
if (ret)
6682+
return;
6683+
}
6684+
6685+
if (hist_data->n_var_refs)
6686+
seq_puts(m, "\n variable reference fields:\n");
6687+
6688+
for (i = 0; i < hist_data->n_var_refs; i++) {
6689+
seq_printf(m, "\n hist_data->var_refs[%d]:\n", i);
6690+
ret = hist_field_debug_show(m, hist_data->var_refs[i],
6691+
HIST_FIELD_FL_VAR_REF);
6692+
if (ret)
6693+
return;
6694+
}
6695+
6696+
if (hist_data->n_field_vars)
6697+
seq_puts(m, "\n field variables:\n");
6698+
6699+
for (i = 0; i < hist_data->n_field_vars; i++) {
6700+
ret = field_var_debug_show(m, hist_data->field_vars[i], i, false);
6701+
if (ret)
6702+
return;
6703+
}
6704+
6705+
ret = hist_actions_debug_show(m, hist_data);
6706+
if (ret)
6707+
return;
6708+
}
6709+
6710+
static int hist_debug_show(struct seq_file *m, void *v)
6711+
{
6712+
struct event_trigger_data *data;
6713+
struct trace_event_file *event_file;
6714+
int n = 0, ret = 0;
6715+
6716+
mutex_lock(&event_mutex);
6717+
6718+
event_file = event_file_data(m->private);
6719+
if (unlikely(!event_file)) {
6720+
ret = -ENODEV;
6721+
goto out_unlock;
6722+
}
6723+
6724+
list_for_each_entry(data, &event_file->triggers, list) {
6725+
if (data->cmd_ops->trigger_type == ETT_EVENT_HIST)
6726+
hist_trigger_debug_show(m, data, n++);
6727+
}
6728+
6729+
out_unlock:
6730+
mutex_unlock(&event_mutex);
6731+
6732+
return ret;
6733+
}
6734+
6735+
static int event_hist_debug_open(struct inode *inode, struct file *file)
6736+
{
6737+
int ret;
6738+
6739+
ret = security_locked_down(LOCKDOWN_TRACEFS);
6740+
if (ret)
6741+
return ret;
6742+
6743+
return single_open(file, hist_debug_show, file);
6744+
}
6745+
6746+
const struct file_operations event_hist_debug_fops = {
6747+
.open = event_hist_debug_open,
6748+
.read = seq_read,
6749+
.llseek = seq_lseek,
6750+
.release = single_release,
6751+
};
6752+
#endif
6753+
64816754
static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
64826755
{
64836756
const char *field_name = hist_field_name(hist_field, 0);

0 commit comments

Comments
 (0)