Skip to content

Commit a3785b7

Browse files
tzanussirostedt
authored andcommitted
tracing: Add hist trigger snapshot() action
Add support for hist:handlerXXX($var).snapshot(), which will take a snapshot of the current trace buffer whenever handlerXXX is hit. As a first user, this also adds snapshot() action support for the onmax() handler i.e. hist:onmax($var).snapshot(). Also, the hist trigger key printing is moved into a separate function so the snapshot() action can print a histogram key outside the histogram display - add and use hist_trigger_print_key() for that purpose. Link: http://lkml.kernel.org/r/2f1a952c0dcd8aca8702ce81269581a692396d45.1550100284.git.tom.zanussi@linux.intel.com Signed-off-by: Tom Zanussi <[email protected]> Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent a35873a commit a3785b7

File tree

2 files changed

+259
-10
lines changed

2 files changed

+259
-10
lines changed

kernel/trace/trace.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4919,6 +4919,9 @@ static const char readme_msg[] =
49194919
"\t The available actions are:\n\n"
49204920
"\t <synthetic_event>(param list) - generate synthetic event\n"
49214921
"\t save(field,...) - save current event fields\n"
4922+
#ifdef CONFIG_TRACER_SNAPSHOT
4923+
"\t snapshot() - snapshot the trace buffer\n"
4924+
#endif
49224925
#endif
49234926
;
49244927

kernel/trace/trace_events_hist.c

Lines changed: 256 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ enum handler_id {
396396
enum action_id {
397397
ACTION_SAVE = 1,
398398
ACTION_TRACE,
399+
ACTION_SNAPSHOT,
399400
};
400401

401402
struct action_data {
@@ -454,6 +455,83 @@ struct action_data {
454455
};
455456
};
456457

458+
struct track_data {
459+
u64 track_val;
460+
bool updated;
461+
462+
unsigned int key_len;
463+
void *key;
464+
struct tracing_map_elt elt;
465+
466+
struct action_data *action_data;
467+
struct hist_trigger_data *hist_data;
468+
};
469+
470+
struct hist_elt_data {
471+
char *comm;
472+
u64 *var_ref_vals;
473+
char *field_var_str[SYNTH_FIELDS_MAX];
474+
};
475+
476+
struct snapshot_context {
477+
struct tracing_map_elt *elt;
478+
void *key;
479+
};
480+
481+
static void track_data_free(struct track_data *track_data)
482+
{
483+
struct hist_elt_data *elt_data;
484+
485+
if (!track_data)
486+
return;
487+
488+
kfree(track_data->key);
489+
490+
elt_data = track_data->elt.private_data;
491+
if (elt_data) {
492+
kfree(elt_data->comm);
493+
kfree(elt_data);
494+
}
495+
496+
kfree(track_data);
497+
}
498+
499+
static struct track_data *track_data_alloc(unsigned int key_len,
500+
struct action_data *action_data,
501+
struct hist_trigger_data *hist_data)
502+
{
503+
struct track_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
504+
struct hist_elt_data *elt_data;
505+
506+
if (!data)
507+
return ERR_PTR(-ENOMEM);
508+
509+
data->key = kzalloc(key_len, GFP_KERNEL);
510+
if (!data->key) {
511+
track_data_free(data);
512+
return ERR_PTR(-ENOMEM);
513+
}
514+
515+
data->key_len = key_len;
516+
data->action_data = action_data;
517+
data->hist_data = hist_data;
518+
519+
elt_data = kzalloc(sizeof(*elt_data), GFP_KERNEL);
520+
if (!elt_data) {
521+
track_data_free(data);
522+
return ERR_PTR(-ENOMEM);
523+
}
524+
data->elt.private_data = elt_data;
525+
526+
elt_data->comm = kzalloc(TASK_COMM_LEN, GFP_KERNEL);
527+
if (!elt_data->comm) {
528+
track_data_free(data);
529+
return ERR_PTR(-ENOMEM);
530+
}
531+
532+
return data;
533+
}
534+
457535
static char last_hist_cmd[MAX_FILTER_STR_VAL];
458536
static char hist_err_str[MAX_FILTER_STR_VAL];
459537

@@ -1726,12 +1804,6 @@ static struct hist_field *find_event_var(struct hist_trigger_data *hist_data,
17261804
return hist_field;
17271805
}
17281806

1729-
struct hist_elt_data {
1730-
char *comm;
1731-
u64 *var_ref_vals;
1732-
char *field_var_str[SYNTH_FIELDS_MAX];
1733-
};
1734-
17351807
static u64 hist_field_var_ref(struct hist_field *hist_field,
17361808
struct tracing_map_elt *elt,
17371809
struct ring_buffer_event *rbe,
@@ -3452,6 +3524,112 @@ static bool check_track_val(struct tracing_map_elt *elt,
34523524
return data->track_data.check_val(track_val, var_val);
34533525
}
34543526

3527+
#ifdef CONFIG_TRACER_SNAPSHOT
3528+
static bool cond_snapshot_update(struct trace_array *tr, void *cond_data)
3529+
{
3530+
/* called with tr->max_lock held */
3531+
struct track_data *track_data = tr->cond_snapshot->cond_data;
3532+
struct hist_elt_data *elt_data, *track_elt_data;
3533+
struct snapshot_context *context = cond_data;
3534+
u64 track_val;
3535+
3536+
if (!track_data)
3537+
return false;
3538+
3539+
track_val = get_track_val(track_data->hist_data, context->elt,
3540+
track_data->action_data);
3541+
3542+
track_data->track_val = track_val;
3543+
memcpy(track_data->key, context->key, track_data->key_len);
3544+
3545+
elt_data = context->elt->private_data;
3546+
track_elt_data = track_data->elt.private_data;
3547+
if (elt_data->comm)
3548+
memcpy(track_elt_data->comm, elt_data->comm, TASK_COMM_LEN);
3549+
3550+
track_data->updated = true;
3551+
3552+
return true;
3553+
}
3554+
3555+
static void save_track_data_snapshot(struct hist_trigger_data *hist_data,
3556+
struct tracing_map_elt *elt, void *rec,
3557+
struct ring_buffer_event *rbe, void *key,
3558+
struct action_data *data,
3559+
u64 *var_ref_vals)
3560+
{
3561+
struct trace_event_file *file = hist_data->event_file;
3562+
struct snapshot_context context;
3563+
3564+
context.elt = elt;
3565+
context.key = key;
3566+
3567+
tracing_snapshot_cond(file->tr, &context);
3568+
}
3569+
3570+
static void hist_trigger_print_key(struct seq_file *m,
3571+
struct hist_trigger_data *hist_data,
3572+
void *key,
3573+
struct tracing_map_elt *elt);
3574+
3575+
static struct action_data *snapshot_action(struct hist_trigger_data *hist_data)
3576+
{
3577+
unsigned int i;
3578+
3579+
if (!hist_data->n_actions)
3580+
return NULL;
3581+
3582+
for (i = 0; i < hist_data->n_actions; i++) {
3583+
struct action_data *data = hist_data->actions[i];
3584+
3585+
if (data->action == ACTION_SNAPSHOT)
3586+
return data;
3587+
}
3588+
3589+
return NULL;
3590+
}
3591+
3592+
static void track_data_snapshot_print(struct seq_file *m,
3593+
struct hist_trigger_data *hist_data)
3594+
{
3595+
struct trace_event_file *file = hist_data->event_file;
3596+
struct track_data *track_data;
3597+
struct action_data *action;
3598+
3599+
track_data = tracing_cond_snapshot_data(file->tr);
3600+
if (!track_data)
3601+
return;
3602+
3603+
if (!track_data->updated)
3604+
return;
3605+
3606+
action = snapshot_action(hist_data);
3607+
if (!action)
3608+
return;
3609+
3610+
seq_puts(m, "\nSnapshot taken (see tracing/snapshot). Details:\n");
3611+
seq_printf(m, "\ttriggering value { %s(%s) }: %10llu",
3612+
action->handler == HANDLER_ONMAX ? "onmax" : "onchange",
3613+
action->track_data.var_str, track_data->track_val);
3614+
3615+
seq_puts(m, "\ttriggered by event with key: ");
3616+
hist_trigger_print_key(m, hist_data, track_data->key, &track_data->elt);
3617+
seq_putc(m, '\n');
3618+
}
3619+
#else
3620+
static bool cond_snapshot_update(struct trace_array *tr, void *cond_data)
3621+
{
3622+
return false;
3623+
}
3624+
static void save_track_data_snapshot(struct hist_trigger_data *hist_data,
3625+
struct tracing_map_elt *elt, void *rec,
3626+
struct ring_buffer_event *rbe, void *key,
3627+
struct action_data *data,
3628+
u64 *var_ref_vals) {}
3629+
static void track_data_snapshot_print(struct seq_file *m,
3630+
struct hist_trigger_data *hist_data) {}
3631+
#endif /* CONFIG_TRACER_SNAPSHOT */
3632+
34553633
static void track_data_print(struct seq_file *m,
34563634
struct hist_trigger_data *hist_data,
34573635
struct tracing_map_elt *elt,
@@ -3463,6 +3641,9 @@ static void track_data_print(struct seq_file *m,
34633641
if (data->handler == HANDLER_ONMAX)
34643642
seq_printf(m, "\n\tmax: %10llu", track_val);
34653643

3644+
if (data->action == ACTION_SNAPSHOT)
3645+
return;
3646+
34663647
for (i = 0; i < hist_data->n_save_vars; i++) {
34673648
struct hist_field *save_val = hist_data->save_vars[i]->val;
34683649
struct hist_field *save_var = hist_data->save_vars[i]->var;
@@ -3513,9 +3694,21 @@ static void action_data_destroy(struct action_data *data)
35133694
static void track_data_destroy(struct hist_trigger_data *hist_data,
35143695
struct action_data *data)
35153696
{
3697+
struct trace_event_file *file = hist_data->event_file;
3698+
35163699
destroy_hist_field(data->track_data.track_var, 0);
35173700
destroy_hist_field(data->track_data.var_ref, 0);
35183701

3702+
if (data->action == ACTION_SNAPSHOT) {
3703+
struct track_data *track_data;
3704+
3705+
track_data = tracing_cond_snapshot_data(file->tr);
3706+
if (track_data && track_data->hist_data == hist_data) {
3707+
tracing_snapshot_cond_disable(file->tr);
3708+
track_data_free(track_data);
3709+
}
3710+
}
3711+
35193712
kfree(data->track_data.var_str);
35203713

35213714
action_data_destroy(data);
@@ -3646,6 +3839,26 @@ static int action_parse(char *str, struct action_data *data,
36463839
data->track_data.save_data = save_track_data_vars;
36473840
data->fn = ontrack_action;
36483841
data->action = ACTION_SAVE;
3842+
} else if (str_has_prefix(action_name, "snapshot")) {
3843+
char *params = strsep(&str, ")");
3844+
3845+
if (!str) {
3846+
hist_err("action parsing: No closing paren found: %s", params);
3847+
ret = -EINVAL;
3848+
goto out;
3849+
}
3850+
3851+
if (handler == HANDLER_ONMAX)
3852+
data->track_data.check_val = check_track_val_max;
3853+
else {
3854+
hist_err("action parsing: Handler doesn't support action: ", action_name);
3855+
ret = -EINVAL;
3856+
goto out;
3857+
}
3858+
3859+
data->track_data.save_data = save_track_data_snapshot;
3860+
data->fn = ontrack_action;
3861+
data->action = ACTION_SNAPSHOT;
36493862
} else {
36503863
char *params = strsep(&str, ")");
36513864

@@ -3942,6 +4155,8 @@ static int trace_action_create(struct hist_trigger_data *hist_data,
39424155
static int action_create(struct hist_trigger_data *hist_data,
39434156
struct action_data *data)
39444157
{
4158+
struct trace_event_file *file = hist_data->event_file;
4159+
struct track_data *track_data;
39454160
struct field_var *field_var;
39464161
unsigned int i;
39474162
char *param;
@@ -3950,6 +4165,21 @@ static int action_create(struct hist_trigger_data *hist_data,
39504165
if (data->action == ACTION_TRACE)
39514166
return trace_action_create(hist_data, data);
39524167

4168+
if (data->action == ACTION_SNAPSHOT) {
4169+
track_data = track_data_alloc(hist_data->key_size, data, hist_data);
4170+
if (IS_ERR(track_data)) {
4171+
ret = PTR_ERR(track_data);
4172+
goto out;
4173+
}
4174+
4175+
ret = tracing_snapshot_cond_enable(file->tr, track_data,
4176+
cond_snapshot_update);
4177+
if (ret)
4178+
track_data_free(track_data);
4179+
4180+
goto out;
4181+
}
4182+
39534183
if (data->action == ACTION_SAVE) {
39544184
if (hist_data->n_save_vars) {
39554185
ret = -EEXIST;
@@ -4552,6 +4782,9 @@ static void print_actions(struct seq_file *m,
45524782
for (i = 0; i < hist_data->n_actions; i++) {
45534783
struct action_data *data = hist_data->actions[i];
45544784

4785+
if (data->action == ACTION_SNAPSHOT)
4786+
continue;
4787+
45554788
if (data->handler == HANDLER_ONMAX)
45564789
track_data_print(m, hist_data, elt, data);
45574790
}
@@ -4946,10 +5179,10 @@ static void hist_trigger_stacktrace_print(struct seq_file *m,
49465179
}
49475180
}
49485181

4949-
static void
4950-
hist_trigger_entry_print(struct seq_file *m,
4951-
struct hist_trigger_data *hist_data, void *key,
4952-
struct tracing_map_elt *elt)
5182+
static void hist_trigger_print_key(struct seq_file *m,
5183+
struct hist_trigger_data *hist_data,
5184+
void *key,
5185+
struct tracing_map_elt *elt)
49535186
{
49545187
struct hist_field *key_field;
49555188
char str[KSYM_SYMBOL_LEN];
@@ -5025,6 +5258,17 @@ hist_trigger_entry_print(struct seq_file *m,
50255258
seq_puts(m, " ");
50265259

50275260
seq_puts(m, "}");
5261+
}
5262+
5263+
static void hist_trigger_entry_print(struct seq_file *m,
5264+
struct hist_trigger_data *hist_data,
5265+
void *key,
5266+
struct tracing_map_elt *elt)
5267+
{
5268+
const char *field_name;
5269+
unsigned int i;
5270+
5271+
hist_trigger_print_key(m, hist_data, key, elt);
50285272

50295273
seq_printf(m, " hitcount: %10llu",
50305274
tracing_map_read_sum(elt, HITCOUNT_IDX));
@@ -5091,6 +5335,8 @@ static void hist_trigger_show(struct seq_file *m,
50915335
if (n_entries < 0)
50925336
n_entries = 0;
50935337

5338+
track_data_snapshot_print(m, hist_data);
5339+
50945340
seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n",
50955341
(u64)atomic64_read(&hist_data->map->hits),
50965342
n_entries, (u64)atomic64_read(&hist_data->map->drops));

0 commit comments

Comments
 (0)