tracing: Hist trigger snapshot and onchange additions
Subsystems (4)
v6 cover tracing: Hist trigger snapshot and onchange additions
From: Tom Zanussi <[email protected]>
Hi,
This is v6 of the hist trigger snapshot and onchange additions patchset. It breaks up the onchange patch into separate code, Documentation, and test case patches, and adds a README-based check for onchange functionality as suggested by Masami.
In addition to adding the above, I updated the README code with the other new recent actions and handlers, as well as corresponding updates to Documentation.
I also added a new snapshot() test case, and moved the new trace() test case into its own file, to allow it to fail separately if unsupported.
Also rebased to lastest ftrace/core.
v5->v6 changes:
- Added new Documentation patch explaining handler.action
- Added new README patch explaining handler.action
- Added separate snapshot() Documentation
- Added new snapshot() test case
- Updated README with snapshote()
- Added separate onchange() Documentation
- Added separate onchange() test case
- Updated README with onchange()
- Added separate trace() test case
- Updated README with trace() and <synthetic_event>() syntax
v4->v5 changes:
- added 'trace' keyword test case
- added 'onchange' handler test case
v3->v4 changes:
- added 'trace' keyword for generating synthetic events
- fix elt_data leak
- changed cond_update to cond_update_fn_t
v2->v3 changes:
- fixed problem where trace actions were only being allowed for onmatch handlers - now trace actions can be used with any handler.
- fixed problem where no action was being assigned to onmatch handlers if save or snapshot actions were specified.
v1->v2 changes:
- added missing tracing_cond_snapshot_data() definition for when CONFIG_TRACER_SNAPSHOT not defined
- removed an unnecessary WARN_ON() in track_data_snapshot_print()
Original text:
This patchset adds some useful new functions to the hist trigger code: a snapshot action and an onchange handler.
In order to make it easier to add these and in the process make the code more generic, I separated the code into explicit 'handlers' and 'actions', handlers being things like 'onmax' and 'onchange', and 'actions' being things like 'take a snapshot' or 'save some fields'.
The first few patches do that basic refactoring, which make it easier to add the subsequent changes that arbitrarily combine actions and handlers.
The fourth patch adds a 'conditional snapshot' capability that via a new tracing_snaphot_cond() function extends the existing snapshot code. It allows the caller to associate some user data with the snapshot that can be checked and saved in an update() callback whose return value determines whether the snapshot should be taken or not.
The remaining patches finally add the new snapshot action and onchange handler functionality - please see those patches for details and some examples.
Thanks,
Tom
The following changes since commit a6ca88b241d5e929e6e60b12ad8cd288f0ffa256:
trace_uprobe: support reference counter in fd-based uprobe (2018-10-10 22:14:17 -0400)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/zanussi/linux-trace.git ftrace/hist-snapshot-onchange-v6
Tom Zanussi (15):
tracing: Refactor hist trigger action code
tracing: Make hist trigger Documentation better reflect
actions/handlers
tracing: Add hist trigger handler.action documentation to README
tracing: Split up onmatch action data
tracing: Generalize hist trigger onmax and save action
tracing: Add conditional snapshot
tracing: Move hist trigger key printing into a separate function
tracing: Add hist trigger snapshot() action
tracing: Add hist trigger snapshot() action Documentation
tracing: Add hist trigger snapshot() action test case
tracing: Add hist trigger onchange() handler
tracing: Add hist trigger onchange() handler Documentation
tracing: Add hist trigger onchange() handler test case
tracing: Add alternative synthetic event trace action syntax
tracing: Add alternative synthetic event trace action test case
Documentation/trace/histogram.rst | 285 +++++- kernel/trace/trace.c | 177 +++- kernel/trace/trace.h | 56 +- kernel/trace/trace_events_hist.c | 1062 +++++++++++++++----- kernel/trace/trace_events_trigger.c | 2 +- kernel/trace/trace_sched_wakeup.c | 2 +- .../inter-event/trigger-onchange-action-hist.tc | 39 + .../inter-event/trigger-snapshot-action-hist.tc | 55 + .../inter-event/trigger-trace-action-hist.tc | 52 + 9 files changed, 1430 insertions(+), 300 deletions(-) create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onchange-action-hist.tc create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-trace-action-hist.tc
Signature · 1 line
2.14.1
PATCH v6 1/15 tracing: Refactor hist trigger action code
From: Tom Zanussi <[email protected]>
The hist trigger action code currently implements two essentially hard-coded pairs of 'actions' - onmax(), which tracks a variable and saves some event fields when a max is hit, and onmatch(), which is hard-coded to generate a synthetic event.
These hardcoded pairs (track max/save fields and detect match/generate synthetic event) should really be decoupled into separate components that can then be arbitrarily combined. The first component of each pair (track max/detect match) is called a 'handler' in the new code, while the second component (save fields/generate synthetic event) is called an 'action' in this scheme.
This change refactors the action code to reflect this split by adding two handlers, HANDLER_ONMATCH and HANDLER_ONMAX, along with two actions, ACTION_SAVE and ACTION_TRACE.
The new code combines them to produce the existing ONMATCH/TRACE and ONMAX/SAVE functionality, but doesn't implement the other combinations now possible. Future patches will expand these to further useful cases, such as ONMAX/TRACE, as well as add additional handlers and actions such as ONCHANGE and SNAPSHOT.
--- kernel/trace/trace_events_hist.c | 402 +++++++++++++++++++++++---------------- 1 file changed, 239 insertions(+), 163 deletions(-)
kernel/trace/trace_events_hist.c +239 -163
@@ -287,9 +287,9 @@ struct hist_trigger_data {struct field_var_hist *field_var_hists[SYNTH_FIELDS_MAX ];unsigned int n_field_var_hists; -struct field_var *max_vars[SYNTH_FIELDS_MAX ]; -unsigned int n_max_vars; -unsigned int n_max_var_str; +struct field_var *save_vars[SYNTH_FIELDS_MAX ]; +unsigned int n_save_vars; +unsigned int n_save_var_str; };struct synth_field {
@@ -319,8 +319,22 @@ typedef void (*action_fn_t) (struct hist_trigger_data *hist_data,struct ring_buffer_event *rbe, struct action_data *data, u64 *var_ref_vals); +enum handler_id { +HANDLER_ONMATCH =1 , +HANDLER_ONMAX , +}; + +enum action_id { +ACTION_SAVE =1 , +ACTION_TRACE , +}; +struct action_data { +enum handler_id handler; +enum action_id action; +char *action_name;action_fn_t fn; +unsigned int n_params;char *params[SYNTH_FIELDS_MAX ];
@@ -329,13 +343,11 @@ struct action_data {unsigned int var_ref_idx;char *match_event;char *match_event_system; -char *synth_event_name;struct synth_event *synth_event; } onmatch;struct {char *var_str; -char *fn_name;unsigned int max_var_ref_idx;struct hist_field *max_var;struct hist_field *var;
@@ -1551,7 +1563,7 @@ find_match_var(struct hist_trigger_data *hist_data, char *var_name)for (i =0 ; i < hist_data->n_actions; i++) {struct action_data *data = hist_data->actions[i]; -if (data->fn == action_trace) { +if (data->handler ==HANDLER_ONMATCH ) {char *system = data->onmatch.match_event_system;char *event_name = data->onmatch.match_event;
@@ -1983,7 +1995,7 @@ static int hist_trigger_elt_data_alloc(struct tracing_map_elt *elt) } } - n_str = hist_data->n_field_var_str + hist_data->n_max_var_str; + n_str = hist_data->n_field_var_str + hist_data->n_save_var_str; size =STR_VAR_LEN_MAX ;
@@ -2925,7 +2937,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,int ret;if (target_hist_data->n_field_var_hists >=SYNTH_FIELDS_MAX ) { -hist_err_event ("onmatch: Too many field variables defined: " , +hist_err_event ("trace action: Too many field variables defined: " , subsys_name, event_name, field_name);return ERR_PTR (-EINVAL ); }
@@ -2933,7 +2945,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data, file =event_file (tr, subsys_name, event_name);if (IS_ERR (file)) { -hist_err_event ("onmatch: Event file not found: " , +hist_err_event ("trace action: Event file not found: " , subsys_name, event_name, field_name); ret =PTR_ERR (file);return ERR_PTR (ret);
@@ -2947,7 +2959,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,*/ hist_data =find_compatible_hist (target_hist_data, file);if (!hist_data) { -hist_err_event ("onmatch: Matching event histogram not found: " , +hist_err_event ("trace action: Matching event histogram not found: " , subsys_name, event_name, field_name);return ERR_PTR (-EINVAL ); }
@@ -3009,7 +3021,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,kfree (cmd);kfree (var_hist->cmd);kfree (var_hist); -hist_err_event ("onmatch: Couldn't create histogram for field: " , +hist_err_event ("trace action: Couldn't create histogram for field: " , subsys_name, event_name, field_name);return ERR_PTR (ret); }
@@ -3022,7 +3034,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,if (IS_ERR_OR_NULL (event_var)) {kfree (var_hist->cmd);kfree (var_hist); -hist_err_event ("onmatch: Couldn't find synthetic variable: " , +hist_err_event ("trace action: Couldn't find synthetic variable: " , subsys_name, event_name, field_name);return ERR_PTR (-EINVAL ); }
@@ -3105,8 +3117,8 @@ static void update_max_vars(struct hist_trigger_data *hist_data,struct ring_buffer_event *rbe, void *rec) { - __update_field_vars(elt, rbe, rec, hist_data->max_vars, - hist_data->n_max_vars, hist_data->n_field_var_str); + __update_field_vars(elt, rbe, rec, hist_data->save_vars, + hist_data->n_save_vars, hist_data->n_field_var_str); } static struct hist_field *create_var(struct hist_trigger_data *hist_data,
@@ -3248,11 +3260,12 @@ static void onmax_print(struct seq_file *m, {unsigned int i, save_var_idx, max_idx = data->onmax.max_var->var.idx; -seq_printf (m,"\n\tmax: %10llu" ,tracing_map_read_var (elt, max_idx)); +if (data->handler ==HANDLER_ONMAX ) +seq_printf (m,"\n\tmax: %10llu" ,tracing_map_read_var (elt, max_idx)); -for (i =0 ; i < hist_data->n_max_vars; i++) { -struct hist_field *save_val = hist_data->max_vars[i]->val; -struct hist_field *save_var = hist_data->max_vars[i]->var; +for (i =0 ; i < hist_data->n_save_vars; i++) { +struct hist_field *save_val = hist_data->save_vars[i]->val; +struct hist_field *save_var = hist_data->save_vars[i]->var;u64 val; save_var_idx = save_var->var.idx;
@@ -3296,7 +3309,7 @@ static void onmax_destroy(struct action_data *data)destroy_hist_field (data->onmax.var,0 );kfree (data->onmax.var_str); -kfree (data->onmax.fn_name); +kfree (data->action_name);for (i =0 ; i < data->n_params; i++)kfree (data->params[i]);
@@ -3304,16 +3317,17 @@ static void onmax_destroy(struct action_data *data)kfree (data); } +static int action_create (struct hist_trigger_data *hist_data, +struct action_data *data); +static int onmax_create (struct hist_trigger_data *hist_data,struct action_data *data) { +struct hist_field *var_field, *ref_field, *max_var =NULL ;struct trace_event_file *file = hist_data->event_file; -struct hist_field *var_field, *ref_field, *max_var;unsigned int var_ref_idx = hist_data->n_var_refs; -struct field_var *field_var; -char *onmax_var_str, *param; +char *onmax_var_str;unsigned long flags; -unsigned int i;int ret =0 ; onmax_var_str = data->onmax.var_str;
@@ -3343,9 +3357,10 @@ static int onmax_create(struct hist_trigger_data *hist_data, ref_field->var_ref_idx = hist_data->n_var_refs++; data->onmax.var = ref_field; - data->fn = onmax_save; data->onmax.max_var_ref_idx = var_ref_idx; - max_var =create_var (hist_data, file,"max" ,sizeof (u64),"u64" ); + +if (data->handler ==HANDLER_ONMAX ) + max_var =create_var (hist_data, file,"max" ,sizeof (u64),"u64" );if (IS_ERR (max_var)) {hist_err ("onmax: Couldn't create onmax variable: " ,"max" ); ret =PTR_ERR (max_var);
@@ -3353,27 +3368,7 @@ static int onmax_create(struct hist_trigger_data *hist_data, } data->onmax.max_var = max_var; -for (i =0 ; i < data->n_params; i++) { - param =kstrdup (data->params[i],GFP_KERNEL ); -if (!param) { - ret = -ENOMEM ; - goto out; - } - - field_var =create_target_field_var (hist_data,NULL ,NULL , param); -if (IS_ERR (field_var)) { -hist_err ("onmax: Couldn't create field variable: " , param); - ret =PTR_ERR (field_var); -kfree (param); - goto out; - } - - hist_data->max_vars[hist_data->n_max_vars++] = field_var; -if (field_var->val->flags &HIST_FIELD_FL_STRING ) - hist_data->n_max_var_str++; - -kfree (param); - } + ret =action_create (hist_data, data); out:return ret; }
@@ -3384,11 +3379,14 @@ static int parse_action_params(char *params, struct action_data *data)int ret =0 ;while (params) { -if (data->n_params >=SYNTH_FIELDS_MAX ) +if (data->n_params >=SYNTH_FIELDS_MAX ) { +hist_err ("Too many action params" ,"" ); goto out; + } param =strsep (¶ms,"," );if (!param) { +hist_err ("No action param found" ,"" ); ret = -EINVAL ; goto out; }
@@ -3412,10 +3410,69 @@ static int parse_action_params(char *params, struct action_data *data)return ret; } -static struct action_data *onmax_parse (char *str) +static int action_parse (char *str,struct action_data *data, +enum handler_id handler) +{ +char *action_name; +int ret =0 ; + +strsep (&str,"." ); +if (!str) { +hist_err ("action parsing: No action found" ,"" ); + ret = -EINVAL ; + goto out; + } + + action_name =strsep (&str,"(" ); +if (!action_name || !str) { +hist_err ("action parsing: No action found" ,"" ); + ret = -EINVAL ; + goto out; + } + +if (strncmp (action_name,"save" ,strlen ("save" )) ==0 ) { +char *params =strsep (&str,")" ); + +if (!params) { +hist_err ("action parsing: No params found for %s" ,"save" ); + ret = -EINVAL ; + goto out; + } + + ret =parse_action_params (params, data); +if (ret) + goto out; + +if (handler ==HANDLER_ONMAX ) + data->fn = onmax_save; + + data->action =ACTION_SAVE ; + }else { +char *params =strsep (&str,")" ); + +if (params) { + ret =parse_action_params (params, data); +if (ret) + goto out; + } + + data->fn = action_trace; + data->action =ACTION_TRACE ; + } + + data->action_name =kstrdup (action_name,GFP_KERNEL ); +if (!data->action_name) { + ret = -ENOMEM ; + goto out; + } + out: +return ret; +} + +static struct action_data *onmax_parse (char *str,enum handler_id handler) { -char *onmax_fn_name, *onmax_var_str;struct action_data *data; +char *onmax_var_str;int ret = -EINVAL ; data =kzalloc (sizeof (*data),GFP_KERNEL );
@@ -3434,33 +3491,11 @@ static struct action_data *onmax_parse(char *str) goto free; } -strsep (&str,"." ); -if (!str) - goto free; - - onmax_fn_name =strsep (&str,"(" ); -if (!onmax_fn_name || !str) - goto free; - -if (strncmp (onmax_fn_name,"save" ,strlen ("save" )) ==0 ) { -char *params =strsep (&str,")" ); - -if (!params) { - ret = -EINVAL ; - goto free; - } - - ret =parse_action_params (params, data); -if (ret) - goto free; - }else + ret =action_parse (str, data, handler); +if (ret) goto free; - data->onmax.fn_name =kstrdup (onmax_fn_name,GFP_KERNEL ); -if (!data->onmax.fn_name) { - ret = -ENOMEM ; - goto free; - } + data->handler = handler; out:return data; free:
@@ -3477,7 +3512,7 @@ static void onmatch_destroy(struct action_data *data)kfree (data->onmatch.match_event);kfree (data->onmatch.match_event_system); -kfree (data->onmatch.synth_event_name); +kfree (data->action_name);for (i =0 ; i < data->n_params; i++)kfree (data->params[i]);
@@ -3554,8 +3589,9 @@ static int check_synth_field(struct synth_event *event, }static struct hist_field * -onmatch_find_var (struct hist_trigger_data *hist_data,struct action_data *data, -char *system,char *event,char *var) +trace_action_find_var (struct hist_trigger_data *hist_data, +struct action_data *data, +char *system,char *event,char *var) {struct hist_field *hist_field;
@@ -3563,7 +3599,7 @@ onmatch_find_var(struct hist_trigger_data *hist_data, struct action_data *data, hist_field =find_target_event_var (hist_data, system, event, var);if (!hist_field) { -if (!system) { +if (!system && data->handler ==HANDLER_ONMATCH ) { system = data->onmatch.match_event_system; event = data->onmatch.match_event; }
@@ -3572,15 +3608,15 @@ onmatch_find_var(struct hist_trigger_data *hist_data, struct action_data *data, }if (!hist_field) -hist_err_event ("onmatch: Couldn't find onmatch param: $" , system, event, var); +hist_err_event ("trace action: Couldn't find param: $" , system, event, var);return hist_field; }static struct hist_field * -onmatch_create_field_var (struct hist_trigger_data *hist_data, -struct action_data *data,char *system, -char *event,char *var) +trace_action_create_field_var (struct hist_trigger_data *hist_data, +struct action_data *data,char *system, +char *event,char *var) {struct hist_field *hist_field =NULL ;struct field_var *field_var;
@@ -3603,7 +3639,7 @@ onmatch_create_field_var(struct hist_trigger_data *hist_data,* looking for fields on the onmatch(system.event.xxx) * event. */ -if (!system) { +if (!system && data->handler ==HANDLER_ONMATCH ) { system = data->onmatch.match_event_system; event = data->onmatch.match_event; }
@@ -3627,9 +3663,8 @@ onmatch_create_field_var(struct hist_trigger_data *hist_data, goto out; } -static int onmatch_create (struct hist_trigger_data *hist_data, -struct trace_event_file *file, -struct action_data *data) +static int trace_action_create (struct hist_trigger_data *hist_data, +struct action_data *data) {char *event_name, *param, *system =NULL ;struct hist_field *hist_field, *var_ref;
@@ -3639,12 +3674,14 @@ static int onmatch_create(struct hist_trigger_data *hist_data,int ret =0 ;mutex_lock (&synth_event_mutex); - event =find_synth_event (data->onmatch.synth_event_name); + + event =find_synth_event (data->action_name);if (!event) { -hist_err ("onmatch: Couldn't find synthetic event: " , data->onmatch.synth_event_name); +hist_err ("trace action: Couldn't find synthetic event: " , data->action_name);mutex_unlock (&synth_event_mutex);return -EINVAL ; } + event->ref++;mutex_unlock (&synth_event_mutex);
@@ -3673,13 +3710,15 @@ static int onmatch_create(struct hist_trigger_data *hist_data, }if (param[0 ] =='$' ) - hist_field =onmatch_find_var (hist_data, data, system, - event_name, param); + hist_field =trace_action_find_var (hist_data, data, + system, event_name, + param);else - hist_field =onmatch_create_field_var (hist_data, data, - system, - event_name, - param); + hist_field =trace_action_create_field_var (hist_data, + data, + system, + event_name, + param);if (!hist_field) {kfree (p);
@@ -3701,7 +3740,7 @@ static int onmatch_create(struct hist_trigger_data *hist_data,continue ; } -hist_err_event ("onmatch: Param type doesn't match synthetic event field type: " , +hist_err_event ("trace action: Param type doesn't match synthetic event field type: " , system, event_name, param);kfree (p); ret = -EINVAL ;
@@ -3709,12 +3748,11 @@ static int onmatch_create(struct hist_trigger_data *hist_data, }if (field_pos != event->n_fields) { -hist_err ("onmatch: Param count doesn't match synthetic event field count: " , event->name); +hist_err ("trace action: Param count doesn't match synthetic event field count: " , event->name); ret = -EINVAL ; goto err; } - data->fn = action_trace; data->onmatch.synth_event = event; data->onmatch.var_ref_idx = var_ref_idx; out:
@@ -3727,10 +3765,60 @@ static int onmatch_create(struct hist_trigger_data *hist_data, goto out; } +static int action_create (struct hist_trigger_data *hist_data, +struct action_data *data) +{ +struct field_var *field_var; +unsigned int i; +char *param; +int ret =0 ; + +if (data->action ==ACTION_TRACE ) { + ret =trace_action_create (hist_data, data); + goto out; + } + +if (data->action ==ACTION_SAVE ) { +if (hist_data->n_save_vars) { + ret = -EINVAL ; +hist_err ("save action: Can't have more than one save() action per hist" ,"" ); + goto out; + } + +for (i =0 ; i < data->n_params; i++) { + param =kstrdup (data->params[i],GFP_KERNEL ); +if (!param) { + ret = -ENOMEM ; + goto out; + } + + field_var =create_target_field_var (hist_data,NULL ,NULL , param); +if (IS_ERR (field_var)) { +hist_err ("save action: Couldn't create field variable: " , param); + ret =PTR_ERR (field_var); +kfree (param); + goto out; + } + + hist_data->save_vars[hist_data->n_save_vars++] = field_var; +if (field_var->val->flags &HIST_FIELD_FL_STRING ) + hist_data->n_save_var_str++; +kfree (param); + } + } + out: +return ret; +} + +static int onmatch_create (struct hist_trigger_data *hist_data, +struct action_data *data) +{ +return action_create (hist_data, data); +} +static struct action_data *onmatch_parse (struct trace_array *tr,char *str) {char *match_event, *match_event_system; -char *synth_event_name, *params;struct action_data *data;int ret = -EINVAL ;
@@ -3768,33 +3856,11 @@ static struct action_data *onmatch_parse(struct trace_array *tr, char *str) goto free; } -strsep (&str,"." ); -if (!str) { -hist_err ("onmatch: Missing . after onmatch(): " , str); - goto free; - } - - synth_event_name =strsep (&str,"(" ); -if (!synth_event_name || !str) { -hist_err ("onmatch: Missing opening paramlist paren: " , synth_event_name); - goto free; - } - - data->onmatch.synth_event_name =kstrdup (synth_event_name,GFP_KERNEL ); -if (!data->onmatch.synth_event_name) { - ret = -ENOMEM ; - goto free; - } - - params =strsep (&str,")" ); -if (!params || !str || (str &&strlen (str))) { -hist_err ("onmatch: Missing closing paramlist paren: " , params); - goto free; - } - - ret =parse_action_params (params, data); + ret =action_parse (str, data,HANDLER_ONMATCH );if (ret) goto free; + + data->handler =HANDLER_ONMATCH ; out:return data; free:
@@ -4232,9 +4298,9 @@ static void destroy_actions(struct hist_trigger_data *hist_data)for (i =0 ; i < hist_data->n_actions; i++) {struct action_data *data = hist_data->actions[i]; -if (data->fn == action_trace) +if (data->handler ==HANDLER_ONMATCH )onmatch_destroy (data); -else if (data->fn == onmax_save) +else if (data->handler ==HANDLER_ONMAX )onmax_destroy (data);else kfree (data);
@@ -4260,16 +4326,14 @@ static int parse_actions(struct hist_trigger_data *hist_data) ret =PTR_ERR (data);break ; } - data->fn = action_trace; }else if (strncmp (str,"onmax(" ,strlen ("onmax(" )) ==0 ) {char *action_str = str +strlen ("onmax(" ); - data =onmax_parse (action_str); + data =onmax_parse (action_str,HANDLER_ONMAX );if (IS_ERR (data)) { ret =PTR_ERR (data);break ; } - data->fn = onmax_save; }else { ret = -EINVAL ;break ;
@@ -4281,8 +4345,7 @@ static int parse_actions(struct hist_trigger_data *hist_data)return ret; } -static int create_actions (struct hist_trigger_data *hist_data, -struct trace_event_file *file) +static int create_actions (struct hist_trigger_data *hist_data) {struct action_data *data;unsigned int i;
@@ -4291,14 +4354,17 @@ static int create_actions(struct hist_trigger_data *hist_data,for (i =0 ; i < hist_data->attrs->n_actions; i++) { data = hist_data->actions[i]; -if (data->fn == action_trace) { - ret =onmatch_create (hist_data, file, data); +if (data->handler ==HANDLER_ONMATCH ) { + ret =onmatch_create (hist_data, data);if (ret)return ret; - }else if (data->fn == onmax_save) { + }else if (data->handler ==HANDLER_ONMAX ) { ret =onmax_create (hist_data, data);if (ret)return ret; + }else { + ret = -EINVAL ; +break ; } }
@@ -4314,26 +4380,43 @@ static void print_actions(struct seq_file *m,for (i =0 ; i < hist_data->n_actions; i++) {struct action_data *data = hist_data->actions[i]; -if (data->fn == onmax_save) +if (data->handler ==HANDLER_ONMAX )onmax_print (m, hist_data, elt, data); } } +static void print_action_spec (struct seq_file *m, +struct hist_trigger_data *hist_data, +struct action_data *data) +{ +unsigned int i; + +if (data->action ==ACTION_SAVE ) { +for (i =0 ; i < hist_data->n_save_vars; i++) { +seq_printf (m,"%s" , hist_data->save_vars[i]->var->var.name); +if (i < hist_data->n_save_vars -1 ) +seq_puts (m,"," ); + } + }else if (data->action ==ACTION_TRACE ) { +for (i =0 ; i < data->n_params; i++) { +if (i) +seq_puts (m,"," ); +seq_printf (m,"%s" , data->params[i]); + } + } +} +static void print_onmax_spec (struct seq_file *m,struct hist_trigger_data *hist_data,struct action_data *data) { -unsigned int i; - -seq_puts (m,":onmax(" ); +if (data->handler ==HANDLER_ONMAX ) +seq_puts (m,":onmax(" );seq_printf (m,"%s" , data->onmax.var_str); -seq_printf (m,").%s(" , data->onmax.fn_name); +seq_printf (m,").%s(" , data->action_name); + +print_action_spec (m, hist_data, data); -for (i =0 ; i < hist_data->n_max_vars; i++) { -seq_printf (m,"%s" , hist_data->max_vars[i]->var->var.name); -if (i < hist_data->n_max_vars -1 ) -seq_puts (m,"," ); - }seq_puts (m,")" ); }
@@ -4341,18 +4424,12 @@ static void print_onmatch_spec(struct seq_file *m, struct hist_trigger_data *hist_data, struct action_data *data) { - unsigned int i; - seq_printf(m, ":onmatch(%s.%s).", data->onmatch.match_event_system, data->onmatch.match_event); -seq_printf (m,"%s(" , data->onmatch.synth_event->name); +seq_printf (m,"%s(" , data->action_name); -for (i =0 ; i < data->n_params; i++) { -if (i) -seq_puts (m,"," ); -seq_printf (m,"%s" , data->params[i]); - } +print_action_spec (m, hist_data, data);seq_puts (m,")" ); }
@@ -4369,7 +4446,9 @@ static bool actions_match(struct hist_trigger_data *hist_data,struct action_data *data = hist_data->actions[i];struct action_data *data_test = hist_data_test->actions[i]; -if (data->fn != data_test->fn) +if (data->handler != data_test->handler) +return false; +if (data->action != data_test->action)return false;if (data->n_params != data_test->n_params)
@@ -4380,23 +4459,20 @@ static bool actions_match(struct hist_trigger_data *hist_data,return false; } -if (data->fn == action_trace) { -if (strcmp (data->onmatch.synth_event_name, - data_test->onmatch.synth_event_name) !=0 ) -return false; +if (strcmp (data->action_name, data_test->action_name) !=0 ) +return false; + +if (data->handler ==HANDLER_ONMATCH ) {if (strcmp (data->onmatch.match_event_system, data_test->onmatch.match_event_system) !=0 )return false;if (strcmp (data->onmatch.match_event, data_test->onmatch.match_event) !=0 )return false; - }else if (data->fn == onmax_save) { + }else if (data->handler ==HANDLER_ONMAX ) {if (strcmp (data->onmax.var_str, data_test->onmax.var_str) !=0 )return false; -if (strcmp (data->onmax.fn_name, - data_test->onmax.fn_name) !=0 ) -return false; } }
@@ -4412,9 +4488,9 @@ static void print_actions_spec(struct seq_file *m,for (i =0 ; i < hist_data->n_actions; i++) {struct action_data *data = hist_data->actions[i]; -if (data->fn == action_trace) +if (data->handler ==HANDLER_ONMATCH )print_onmatch_spec (m, hist_data, data); -else if (data->fn == onmax_save) +else if (data->handler ==HANDLER_ONMAX )print_onmax_spec (m, hist_data, data); } }
@@ -5591,7 +5667,7 @@ static int event_hist_trigger_func(struct event_command *cmd_ops,if (has_hist_vars (hist_data))save_hist_vars (hist_data); - ret =create_actions (hist_data, file); + ret =create_actions (hist_data);if (ret) goto out_unreg;
Signature · 1 line
2.14.1
Masami Hiramatsu
maintainerRe: [PATCH v6 01/15] tracing: Refactor hist trigger action code
Hi Tom,
Quoted 18 lines · On Thu, 11 Oct 2018 16:01:58 -0500 Tom Zanussi <[email protected]> wrote:
From: Tom Zanussi <[email protected]>
The hist trigger action code currently implements two essentially hard-coded pairs of 'actions' -
onmax(), which tracks a variable and saves some event fields when a max is hit, andonmatch(), which is hard-coded to generate a synthetic event.These hardcoded pairs (track max/save fields and detect match/generate synthetic event) should really be decoupled into separate components that can then be arbitrarily combined. The first component of each pair (track max/detect match) is called a 'handler' in the new code, while the second component (save fields/generate synthetic event) is called an 'action' in this scheme.
This change refactors the action code to reflect this split by adding two handlers,
HANDLER_ONMATCHandHANDLER_ONMAX, along with two actions,ACTION_SAVEandACTION_TRACE.
Quoted 5 lines
The new code combines them to produce the existing ONMATCH/TRACE and ONMAX/SAVE functionality, but doesn't implement the other combinations now possible. Future patches will expand these to further useful cases, such as ONMAX/TRACE, as well as add additional handlers and actions such as ONCHANGE and SNAPSHOT.
This patch looks good, but I have some comment below;
[...]
kernel/trace/trace_events_hist.c static void onmax_print(struct seq_file *m, · line 3263
Quoted 6 lines
kernel/trace/trace_events_hist.c +1
-1@@ -3248,11 +3260,12 @@ static void onmax_print(struct seq_file *m, {unsigned int i, save_var_idx, max_idx = data->onmax.max_var->var.idx; -seq_printf (m,"\n\tmax: %10llu" ,tracing_map_read_var (elt, max_idx)); +if (data->handler ==HANDLER_ONMAX )
It seems a bit odd that checks HANDLER_ONMAX or not in onmax_X function().
Quoted 43 lines
kernel/trace/trace_events_hist.c +10
-8+seq_printf (m,"\n\tmax: %10llu" ,tracing_map_read_var (elt, max_idx)); -for (i =0 ; i < hist_data->n_max_vars; i++) { -struct hist_field *save_val = hist_data->max_vars[i]->val; -struct hist_field *save_var = hist_data->max_vars[i]->var; +for (i =0 ; i < hist_data->n_save_vars; i++) { +struct hist_field *save_val = hist_data->save_vars[i]->val; +struct hist_field *save_var = hist_data->save_vars[i]->var;u64 val; save_var_idx = save_var->var.idx;@@ -3296,7 +3309,7 @@ static void onmax_destroy(struct action_data *data)destroy_hist_field (data->onmax.var,0 );kfree (data->onmax.var_str); -kfree (data->onmax.fn_name); +kfree (data->action_name);for (i =0 ; i < data->n_params; i++)kfree (data->params[i]);@@ -3304,16 +3317,17 @@ static void onmax_destroy(struct action_data *data)kfree (data); } +static int action_create (struct hist_trigger_data *hist_data, +struct action_data *data); +static int onmax_create (struct hist_trigger_data *hist_data,struct action_data *data) { +struct hist_field *var_field, *ref_field, *max_var =NULL ;struct trace_event_file *file = hist_data->event_file; -struct hist_field *var_field, *ref_field, *max_var;unsigned int var_ref_idx = hist_data->n_var_refs; -struct field_var *field_var; -char *onmax_var_str, *param; +char *onmax_var_str;unsigned long flags; -unsigned int i;int ret =0 ; onmax_var_str = data->onmax.var_str;
kernel/trace/trace_events_hist.c static int onmax_create(struct hist_trigger_data *hist_data, · line 3362
Quoted 8 lines
kernel/trace/trace_events_hist.c +2
-2@@ -3343,9 +3357,10 @@ static int onmax_create(struct hist_trigger_data *hist_data, ref_field->var_ref_idx = hist_data->n_var_refs++; data->onmax.var = ref_field; - data->fn = onmax_save; data->onmax.max_var_ref_idx = var_ref_idx; - max_var =create_var (hist_data, file,"max" ,sizeof (u64),"u64" ); + +if (data->handler ==HANDLER_ONMAX )
Ditto.
Quoted 99 lines
kernel/trace/trace_events_hist.c +51
-23+ max_var =create_var (hist_data, file,"max" ,sizeof (u64),"u64" );if (IS_ERR (max_var)) {hist_err ("onmax: Couldn't create onmax variable: " ,"max" ); ret =PTR_ERR (max_var);@@ -3353,27 +3368,7 @@ static int onmax_create(struct hist_trigger_data *hist_data, } data->onmax.max_var = max_var; -for (i =0 ; i < data->n_params; i++) { - param =kstrdup (data->params[i],GFP_KERNEL ); -if (!param) { - ret = -ENOMEM ; - goto out; - } - - field_var =create_target_field_var (hist_data,NULL ,NULL , param); -if (IS_ERR (field_var)) { -hist_err ("onmax: Couldn't create field variable: " , param); - ret =PTR_ERR (field_var); -kfree (param); - goto out; - } - - hist_data->max_vars[hist_data->n_max_vars++] = field_var; -if (field_var->val->flags &HIST_FIELD_FL_STRING ) - hist_data->n_max_var_str++; - -kfree (param); - } + ret =action_create (hist_data, data); out:return ret; }@@ -3384,11 +3379,14 @@ static int parse_action_params(char *params, struct action_data *data)int ret =0 ;while (params) { -if (data->n_params >=SYNTH_FIELDS_MAX ) +if (data->n_params >=SYNTH_FIELDS_MAX ) { +hist_err ("Too many action params" ,"" ); goto out; + } param =strsep (¶ms,"," );if (!param) { +hist_err ("No action param found" ,"" ); ret = -EINVAL ; goto out; }@@ -3412,10 +3410,69 @@ static int parse_action_params(char *params, struct action_data *data)return ret; } -static struct action_data *onmax_parse (char *str) +static int action_parse (char *str,struct action_data *data, +enum handler_id handler) +{ +char *action_name; +int ret =0 ; + +strsep (&str,"." ); +if (!str) { +hist_err ("action parsing: No action found" ,"" ); + ret = -EINVAL ; + goto out; + } + + action_name =strsep (&str,"(" ); +if (!action_name || !str) { +hist_err ("action parsing: No action found" ,"" ); + ret = -EINVAL ; + goto out; + } + +if (strncmp (action_name,"save" ,strlen ("save" )) ==0 ) { +char *params =strsep (&str,")" ); + +if (!params) { +hist_err ("action parsing: No params found for %s" ,"save" ); + ret = -EINVAL ; + goto out; + } + + ret =parse_action_params (params, data); +if (ret) + goto out; + +if (handler ==HANDLER_ONMAX ) + data->fn = onmax_save; + + data->action =ACTION_SAVE ; + }else { +char *params =strsep (&str,")" ); + +if (params) { + ret =parse_action_params (params, data); +if (ret) + goto out; + }
kernel/trace/trace_events_hist.c static int parse_action_params(char *params, struct action_data *data) · line 3467
Quoted 10 lines
kernel/trace/trace_events_hist.c +10
-0+ + data->fn = action_trace; + data->action =ACTION_TRACE ; + } + + data->action_name =kstrdup (action_name,GFP_KERNEL ); +if (!data->action_name) { + ret = -ENOMEM ; + goto out; + }
Since we know "handler", it is natural that data->handler is assigned here.
Quoted 186 lines
kernel/trace/trace_events_hist.c +35
-49+ out: +return ret; +} + +static struct action_data *onmax_parse (char *str,enum handler_id handler) { -char *onmax_fn_name, *onmax_var_str;struct action_data *data; +char *onmax_var_str;int ret = -EINVAL ; data =kzalloc (sizeof (*data),GFP_KERNEL );@@ -3434,33 +3491,11 @@ static struct action_data *onmax_parse(char *str) goto free; } -strsep (&str,"." ); -if (!str) - goto free; - - onmax_fn_name =strsep (&str,"(" ); -if (!onmax_fn_name || !str) - goto free; - -if (strncmp (onmax_fn_name,"save" ,strlen ("save" )) ==0 ) { -char *params =strsep (&str,")" ); - -if (!params) { - ret = -EINVAL ; - goto free; - } - - ret =parse_action_params (params, data); -if (ret) - goto free; - }else + ret =action_parse (str, data, handler); +if (ret) goto free; - data->onmax.fn_name =kstrdup (onmax_fn_name,GFP_KERNEL ); -if (!data->onmax.fn_name) { - ret = -ENOMEM ; - goto free; - } + data->handler = handler; out:return data; free:@@ -3477,7 +3512,7 @@ static void onmatch_destroy(struct action_data *data)kfree (data->onmatch.match_event);kfree (data->onmatch.match_event_system); -kfree (data->onmatch.synth_event_name); +kfree (data->action_name);for (i =0 ; i < data->n_params; i++)kfree (data->params[i]);@@ -3554,8 +3589,9 @@ static int check_synth_field(struct synth_event *event, }static struct hist_field * -onmatch_find_var (struct hist_trigger_data *hist_data,struct action_data *data, -char *system,char *event,char *var) +trace_action_find_var (struct hist_trigger_data *hist_data, +struct action_data *data, +char *system,char *event,char *var) {struct hist_field *hist_field;@@ -3563,7 +3599,7 @@ onmatch_find_var(struct hist_trigger_data *hist_data, struct action_data *data, hist_field =find_target_event_var (hist_data, system, event, var);if (!hist_field) { -if (!system) { +if (!system && data->handler ==HANDLER_ONMATCH ) { system = data->onmatch.match_event_system; event = data->onmatch.match_event; }@@ -3572,15 +3608,15 @@ onmatch_find_var(struct hist_trigger_data *hist_data, struct action_data *data, }if (!hist_field) -hist_err_event ("onmatch: Couldn't find onmatch param: $" , system, event, var); +hist_err_event ("trace action: Couldn't find param: $" , system, event, var);return hist_field; }static struct hist_field * -onmatch_create_field_var (struct hist_trigger_data *hist_data, -struct action_data *data,char *system, -char *event,char *var) +trace_action_create_field_var (struct hist_trigger_data *hist_data, +struct action_data *data,char *system, +char *event,char *var) {struct hist_field *hist_field =NULL ;struct field_var *field_var;@@ -3603,7 +3639,7 @@ onmatch_create_field_var(struct hist_trigger_data *hist_data,* looking for fields on the onmatch(system.event.xxx) * event. */ -if (!system) { +if (!system && data->handler ==HANDLER_ONMATCH ) { system = data->onmatch.match_event_system; event = data->onmatch.match_event; }@@ -3627,9 +3663,8 @@ onmatch_create_field_var(struct hist_trigger_data *hist_data, goto out; } -static int onmatch_create (struct hist_trigger_data *hist_data, -struct trace_event_file *file, -struct action_data *data) +static int trace_action_create (struct hist_trigger_data *hist_data, +struct action_data *data) {char *event_name, *param, *system =NULL ;struct hist_field *hist_field, *var_ref;@@ -3639,12 +3674,14 @@ static int onmatch_create(struct hist_trigger_data *hist_data,int ret =0 ;mutex_lock (&synth_event_mutex); - event =find_synth_event (data->onmatch.synth_event_name); + + event =find_synth_event (data->action_name);if (!event) { -hist_err ("onmatch: Couldn't find synthetic event: " , data->onmatch.synth_event_name); +hist_err ("trace action: Couldn't find synthetic event: " , data->action_name);mutex_unlock (&synth_event_mutex);return -EINVAL ; } + event->ref++;mutex_unlock (&synth_event_mutex);@@ -3673,13 +3710,15 @@ static int onmatch_create(struct hist_trigger_data *hist_data, }if (param[0 ] =='$' ) - hist_field =onmatch_find_var (hist_data, data, system, - event_name, param); + hist_field =trace_action_find_var (hist_data, data, + system, event_name, + param);else - hist_field =onmatch_create_field_var (hist_data, data, - system, - event_name, - param); + hist_field =trace_action_create_field_var (hist_data, + data, + system, + event_name, + param);if (!hist_field) {kfree (p);@@ -3701,7 +3740,7 @@ static int onmatch_create(struct hist_trigger_data *hist_data,continue ; } -hist_err_event ("onmatch: Param type doesn't match synthetic event field type: " , +hist_err_event ("trace action: Param type doesn't match synthetic event field type: " , system, event_name, param);kfree (p); ret = -EINVAL ;@@ -3709,12 +3748,11 @@ static int onmatch_create(struct hist_trigger_data *hist_data, }if (field_pos != event->n_fields) { -hist_err ("onmatch: Param count doesn't match synthetic event field count: " , event->name); +hist_err ("trace action: Param count doesn't match synthetic event field count: " , event->name); ret = -EINVAL ; goto err; } - data->fn = action_trace; data->onmatch.synth_event = event; data->onmatch.var_ref_idx = var_ref_idx; out:@@ -3727,10 +3765,60 @@ static int onmatch_create(struct hist_trigger_data *hist_data, goto out; }
kernel/trace/trace_events_hist.c static int onmatch_create(struct hist_trigger_data *hist_data, · line 3777
Quoted 10 lines
kernel/trace/trace_events_hist.c +10
-0+static int action_create (struct hist_trigger_data *hist_data, +struct action_data *data) +{ +struct field_var *field_var; +unsigned int i; +char *param; +int ret =0 ; + +if (data->action ==ACTION_TRACE ) { + ret =trace_action_create (hist_data, data);
This can return soon without "goto".
kernel/trace/trace_events_hist.c static int onmatch_create(struct hist_trigger_data *hist_data, · line 3783
Quoted 6 lines
kernel/trace/trace_events_hist.c +6
-0+ goto out; + } + +if (data->action ==ACTION_SAVE ) { +if (hist_data->n_save_vars) { + ret = -EINVAL ;
Maybe -EEXIST?
Quoted 66 lines
kernel/trace/trace_events_hist.c +35
-21+hist_err ("save action: Can't have more than one save() action per hist" ,"" ); + goto out; + } + +for (i =0 ; i < data->n_params; i++) { + param =kstrdup (data->params[i],GFP_KERNEL ); +if (!param) { + ret = -ENOMEM ; + goto out; + } + + field_var =create_target_field_var (hist_data,NULL ,NULL , param); +if (IS_ERR (field_var)) { +hist_err ("save action: Couldn't create field variable: " , param); + ret =PTR_ERR (field_var); +kfree (param); + goto out; + } + + hist_data->save_vars[hist_data->n_save_vars++] = field_var; +if (field_var->val->flags &HIST_FIELD_FL_STRING ) + hist_data->n_save_var_str++; +kfree (param); + } + } + out: +return ret; +} + +static int onmatch_create (struct hist_trigger_data *hist_data, +struct action_data *data) +{ +return action_create (hist_data, data); +} +static struct action_data *onmatch_parse (struct trace_array *tr,char *str) {char *match_event, *match_event_system; -char *synth_event_name, *params;struct action_data *data;int ret = -EINVAL ;@@ -3768,33 +3856,11 @@ static struct action_data *onmatch_parse(struct trace_array *tr, char *str) goto free; } -strsep (&str,"." ); -if (!str) { -hist_err ("onmatch: Missing . after onmatch(): " , str); - goto free; - } - - synth_event_name =strsep (&str,"(" ); -if (!synth_event_name || !str) { -hist_err ("onmatch: Missing opening paramlist paren: " , synth_event_name); - goto free; - } - - data->onmatch.synth_event_name =kstrdup (synth_event_name,GFP_KERNEL ); -if (!data->onmatch.synth_event_name) { - ret = -ENOMEM ; - goto free; - } - - params =strsep (&str,")" ); -if (!params || !str || (str &&strlen (str))) {
kernel/trace/trace_events_hist.c static struct action_data *onmatch_parse(struct trace_array *tr, char *str) · line 3863
Quoted 10 lines
kernel/trace/trace_events_hist.c +3
-5-hist_err ("onmatch: Missing closing paramlist paren: " , params); - goto free; - } - - ret =parse_action_params (params, data); + ret =action_parse (str, data,HANDLER_ONMATCH );if (ret) goto free; + + data->handler =HANDLER_ONMATCH ;
This assignment seems to be done in action_parse().
Quoted 50 lines
kernel/trace/trace_events_hist.c +5
-9out:return data; free:@@ -4232,9 +4298,9 @@ static void destroy_actions(struct hist_trigger_data *hist_data)for (i =0 ; i < hist_data->n_actions; i++) {struct action_data *data = hist_data->actions[i]; -if (data->fn == action_trace) +if (data->handler ==HANDLER_ONMATCH )onmatch_destroy (data); -else if (data->fn == onmax_save) +else if (data->handler ==HANDLER_ONMAX )onmax_destroy (data);else kfree (data);@@ -4260,16 +4326,14 @@ static int parse_actions(struct hist_trigger_data *hist_data) ret =PTR_ERR (data);break ; } - data->fn = action_trace; }else if (strncmp (str,"onmax(" ,strlen ("onmax(" )) ==0 ) {char *action_str = str +strlen ("onmax(" ); - data =onmax_parse (action_str); + data =onmax_parse (action_str,HANDLER_ONMAX );if (IS_ERR (data)) { ret =PTR_ERR (data);break ; } - data->fn = onmax_save; }else { ret = -EINVAL ;break ;@@ -4281,8 +4345,7 @@ static int parse_actions(struct hist_trigger_data *hist_data)return ret; } -static int create_actions (struct hist_trigger_data *hist_data, -struct trace_event_file *file) +static int create_actions (struct hist_trigger_data *hist_data) {struct action_data *data;unsigned int i;@@ -4291,14 +4354,17 @@ static int create_actions(struct hist_trigger_data *hist_data,for (i =0 ; i < hist_data->attrs->n_actions; i++) { data = hist_data->actions[i]; -if (data->fn == action_trace) { - ret =onmatch_create (hist_data, file, data); +if (data->handler ==HANDLER_ONMATCH ) {
kernel/trace/trace_events_hist.c static int create_actions(struct hist_trigger_data *hist_data, · line 4366
Quoted 10 lines
kernel/trace/trace_events_hist.c +4
-1+ ret =onmatch_create (hist_data, data);if (ret)return ret; - }else if (data->fn == onmax_save) { + }else if (data->handler ==HANDLER_ONMAX ) { ret =onmax_create (hist_data, data);if (ret)return ret; + }else { + ret = -EINVAL ;
This is a bit odd (or just mixtured), return -EINVAL will be enough here. Or above "if (ret) return ret;" shoud be "if (ret) break;" since this function returns ret soon after this loop.
kernel/trace/trace_events_hist.c static int create_actions(struct hist_trigger_data *hist_data, · line 4370
Quoted 4 lines
kernel/trace/trace_events_hist.c +1
-0+break ; } }
Thank you,
Signature · 1 line
Masami Hiramatsu <[email protected]>
Re: [PATCH v6 01/15] tracing: Refactor hist trigger action code
Hi Masami,
Quoted 43 lines · Masami Hiramatsu
Hi Tom,
Quoted 24 lines · On Thu, 11 Oct 2018 16:01:58 -0500 Tom Zanussi <[email protected]> wrote:
From: Tom Zanussi <[email protected]>
The hist trigger action code currently implements two essentially hard-coded pairs of 'actions' -
onmax(), which tracks a variable and
saves some event fields when a max is hit, andonmatch(), which is hard-coded to generate a synthetic event.These hardcoded pairs (track max/save fields and detect match/generate
synthetic event) should really be decoupled into separate components
that can then be arbitrarily combined. The first component of each pair (track max/detect match) is called a 'handler' in the new code,
while the second component (save fields/generate synthetic event) is
called an 'action' in this scheme.This change refactors the action code to reflect this split by adding
two handlers,HANDLER_ONMATCHandHANDLER_ONMAX, along with two actions,ACTION_SAVEandACTION_TRACE.Quoted 7 lines
The new code combines them to produce the existing ONMATCH/TRACE and
ONMAX/SAVE functionality, but doesn't implement the other combinations
now possible. Future patches will expand these to further useful cases, such as ONMAX/TRACE, as well as add additional handlers and actions such as ONCHANGE and SNAPSHOT.This patch looks good, but I have some comment below;
[...]
Quoted 3 lines
(quoted diff) +0
-0@@ -3248,11 +3260,12 @@ static void onmax_print(struct seq_file *m, { unsigned int i, save_var_idx, max_idx = data-
Quoted 9 lines
Review static void onmax_print(struct seq_file *m, · line 3265
Quoted 5 lines
(quoted diff) +1
-1>onmax.max_var->var.idx; - seq_printf(m, "\n\tmax: %10llu", tracing_map_read_var(elt, max_idx)); + if (data->handler == HANDLER_ONMAX)It seems a bit odd that checks
HANDLER_ONMAXor not inonmax_Xfunction().
Later patches change things so it makes more sense i.e. onmax_print is renamed to track_data_print() which handles not just ONMAX but ONCHANGE as well, and then this check is needed. But I can move this check to those patches.
Quoted 54 lines
Quoted 54 lines
(quoted diff) +1
-3+ seq_printf(m, "\n\tmax: %10llu", tracing_map_read_var(elt, max_idx)); - for (i = 0; i < hist_data->n_max_vars; i++) { - struct hist_field *save_val = hist_data- >max_vars[i]->val; - struct hist_field *save_var = hist_data-Quoted 1 line
max_vars[i]->var;
(quoted diff) +2
-0+ for (i = 0; i < hist_data->n_save_vars; i++) { + struct hist_field *save_val = hist_data-Quoted 1 line
save_vars[i]->val;
(quoted diff) +1
-0+ struct hist_field *save_var = hist_data-Quoted 1 line
save_vars[i]->var;
kernel/trace/trace_events_hist.c +1
-1u64 val; save_var_idx = save_var->var.idx;@@ -3296,7 +3309,7 @@ static void onmax_destroy(struct action_data *data)destroy_hist_field (data->onmax.var,0 );kfree (data->onmax.var_str); -kfree (data->onmax.fn_name); +kfree (data->action_name);for (i =0 ; i < data->n_params; i++)kernel/trace/trace_events_hist.c +5
-4kfree (data->params[i]);@@ -3304,16 +3317,17 @@ static void onmax_destroy(struct action_data *data)kfree (data ); } +static int action_create (struct hist_trigger_data *hist_data, +struct action_data *data); +static int onmax_create (struct hist_trigger_data *hist_data,struct action_data *data) { +struct hist_field *var_field, *ref_field, *max_var =NULL ;struct trace_event_file *file = hist_data->event_file; -struct hist_field *var_field, *ref_field, *max_var;unsigned int var_ref_idx = hist_data->n_var_refs; -struct field_var *field_var; -char *onmax_var_str, *param; +char *onmax_var_str;unsigned long flags; -unsigned int i;int ret =0 ;kernel/trace/trace_events_hist.c +0
-0onmax_var_str = data->onmax.var_str;@@ -3343,9 +3357,10 @@ static int onmax_create(struct hist_trigger_data *hist_data, ref_field->var_ref_idx = hist_data->n_var_refs++; data->onmax.var = ref_field;
Quoted 8 lines
kernel/trace/trace_events_hist.c static int onmax_create(struct hist_trigger_data *hist_data, · line 3362
Quoted 6 lines
kernel/trace/trace_events_hist.c +2
-2- data->fn = onmax_save; data->onmax.max_var_ref_idx = var_ref_idx; - max_var =create_var (hist_data, file,"max" ,sizeof (u64), "u64"); + +if (data->handler ==HANDLER_ONMAX )Ditto.
Same here, this changes to track_data_create() in later patches, where it makes sense. But, will move it there.
Quoted 114 lines
Quoted 114 lines
(quoted diff) +1
-0+ max_var = create_var(hist_data, file, "max", sizeof(u64), "u64");(quoted diff) +0
-0if (IS_ERR(max_var)) { hist_err("onmax: Couldn't create onmax variable:", "max");
kernel/trace/trace_events_hist.c +5
-22ret =PTR_ERR (max_var);@@ -3353,27 +3368,7 @@ static int onmax_create(struct hist_trigger_data *hist_data, } data->onmax.max_var = max_var; -for (i =0 ; i < data->n_params; i++) { - param =kstrdup (data->params[i],GFP_KERNEL ); -if (!param) { - ret = -ENOMEM ; - goto out; - } - - field_var =create_target_field_var (hist_data, NULL, NULL, param); -if (IS_ERR (field_var)) { -hist_err ("onmax: Couldn't create field variable: ", param); - ret =PTR_ERR (field_var); -kfree (param); - goto out; - } - - hist_data->max_vars[hist_data->n_max_vars++] = field_var; -if (field_var->val->flags &HIST_FIELD_FL_STRING ) - hist_data->n_max_var_str++; - -kfree (param); - } + ret =action_create (hist_data, data); out:return ret; }@@ -3384,11 +3379,14 @@ static int parse_action_params(char *params, struct action_data *data)int ret =0 ;while (params) { -if (data->n_params >=SYNTH_FIELDS_MAX ) +if (data->n_params >=SYNTH_FIELDS_MAX ) { +hist_err ("Too many action params" ,"" ); goto out; + } param =strsep (¶ms,"," );if (!param) { +hist_err ("No action param found" ,"" ); ret = -EINVAL ; goto out;kernel/trace/trace_events_hist.c +50
-1}@@ -3412,10 +3410,69 @@ static int parse_action_params(char *params, struct action_data *data)return ret; } -static struct action_data *onmax_parse (char *str) +static int action_parse (char *str,struct action_data *data, +enum handler_id handler) +{ +char *action_name; +int ret =0 ; + +strsep (&str,"." ); +if (!str) { +hist_err ("action parsing: No action found" ,"" ); + ret = -EINVAL ; + goto out; + } + + action_name =strsep (&str,"(" ); +if (!action_name || !str) { +hist_err ("action parsing: No action found" ,"" ); + ret = -EINVAL ; + goto out; + } + +if (strncmp (action_name,"save" ,strlen ("save" )) ==0 ) { +char *params =strsep (&str,")" ); + +if (!params) { + hist_err("action parsing: No params found for %s", "save"); + ret = -EINVAL; + goto out; + } + + ret = parse_action_params(params, data); +if (ret) + goto out; + +if (handler ==HANDLER_ONMAX ) + data->fn = onmax_save; + + data->action =ACTION_SAVE ; + }else { +char *params =strsep (&str,")" ); + +if (params) { + ret =parse_action_params (params, data); +if (ret) + goto out; + } + + data->fn = action_trace; + data->action =ACTION_TRACE ; + } +
Quoted 8 lines
kernel/trace/trace_events_hist.c static int parse_action_params(char *params, struct action_data *data) · line 3467
Quoted 5 lines
kernel/trace/trace_events_hist.c +5
-0+ data->action_name =kstrdup (action_name,GFP_KERNEL ); +if (!data->action_name) { + ret = -ENOMEM ; + goto out; + }Since we know "handler", it is natural that
data->handleris assigned here.
Makes sense, will change.
Quoted 239 lines
Quoted 226 lines
kernel/trace/trace_events_hist.c +6
-1+ out: +return ret; +} + +static struct action_data *onmax_parse (char *str,enum handler_id handler) { -char *onmax_fn_name, *onmax_var_str;struct action_data *data; +char *onmax_var_str;kernel/trace/trace_events_hist.c +3
-25int ret = -EINVAL ; data =kzalloc (sizeof (*data),GFP_KERNEL );@@ -3434,33 +3491,11 @@ static struct action_data *onmax_parse(char *str) goto free; } -strsep (&str,"." ); -if (!str) - goto free; - - onmax_fn_name =strsep (&str,"(" ); -if (!onmax_fn_name || !str) - goto free; - -if (strncmp (onmax_fn_name,"save" ,strlen ("save" )) ==0 ) { -char *params =strsep (&str,")" ); - -if (!params) { - ret = -EINVAL ; - goto free; - } - - ret =parse_action_params (params, data); -if (ret) - goto free; - }else + ret =action_parse (str, data, handler); +if (ret) goto free; - data->onmax.fn_name =kstrdup (onmax_fn_name,GFP_KERNEL ); -if (!data->onmax.fn_name) { - ret = -ENOMEM ; - goto free; - } + data->handler = handler; out:return data;free:
kernel/trace/trace_events_hist.c +1
-1@@ -3477,7 +3512,7 @@ static void onmatch_destroy(struct action_data *data) kfree(data->onmatch.match_event);kfree (data->onmatch.match_event_system); -kfree (data->onmatch.synth_event_name); +kfree (data->action_name);for (i =0 ; i < data->n_params; i++)kernel/trace/trace_events_hist.c +3
-2kfree (data->params[i]);@@ -3554,8 +3589,9 @@ static int check_synth_field(struct synth_event *event, } static struct hist_field * -onmatch_find_var (struct hist_trigger_data *hist_data,struct action_data *data, -char *system,char *event,char *var) +trace_action_find_var(struct hist_trigger_data *hist_data, + struct action_data *data, + char *system, char *event, char *var) {kernel/trace/trace_events_hist.c +1
-1struct hist_field *hist_field;@@ -3563,7 +3599,7 @@ onmatch_find_var(struct hist_trigger_data *hist_data, struct action_data *data, hist_field =find_target_event_var (hist_data, system, event, var);if (!hist_field) { -if (!system) { +if (!system && data->handler ==HANDLER_ONMATCH ) { system = data->onmatch.match_event_system;kernel/trace/trace_events_hist.c +3
-4event = data->onmatch.match_event; }@@ -3572,15 +3608,15 @@ onmatch_find_var(struct hist_trigger_data *hist_data, struct action_data *data, }if (!hist_field) -hist_err_event ("onmatch: Couldn't find onmatch param: $", system, event, var); + hist_err_event("trace action: Couldn't find param: $", system, event, var);return hist_field; }static struct hist_field * -onmatch_create_field_var (struct hist_trigger_data *hist_data, -struct action_data *data,char *system, -char *event,char *var) +trace_action_create_field_var (struct hist_trigger_data *hist_data, + struct action_data *data, char*system,
kernel/trace/trace_events_hist.c +2
-1+ char *event, char *var) { struct hist_field *hist_field = NULL;struct field_var *field_var;@@ -3603,7 +3639,7 @@ onmatch_create_field_var(structhist_trigger_data *hist_data, * looking for fields on the onmatch(system.event.xxx) * event. */ -if (!system) { +if (!system && data->handler ==HANDLER_ONMATCH ) { system = data->onmatch.match_event_system;kernel/trace/trace_events_hist.c +2
-3event = data->onmatch.match_event; }@@ -3627,9 +3663,8 @@ onmatch_create_field_var(structhist_trigger_data *hist_data, goto out; } -static int onmatch_create (struct hist_trigger_data *hist_data, -struct trace_event_file *file, - struct action_data *data) +static int trace_action_create (struct hist_trigger_data *hist_data, +struct action_data *data) {kernel/trace/trace_events_hist.c +4
-2char *event_name, *param, *system =NULL ;struct hist_field *hist_field, *var_ref;@@ -3639,12 +3674,14 @@ static int onmatch_create(structhist_trigger_data *hist_data, int ret = 0;mutex_lock (&synth_event_mutex); - event =find_synth_event (data->onmatch.synth_event_name); + + event =find_synth_event (data->action_name);if (!event) { -hist_err ("onmatch: Couldn't find synthetic event: ", data->onmatch.synth_event_name); + hist_err("trace action: Couldn't find synthetic event: ", data->action_name);mutex_unlock (&synth_event_mutex);return -EINVAL ; } +kernel/trace/trace_events_hist.c +3
-4event->ref++;mutex_unlock (&synth_event_mutex);@@ -3673,13 +3710,15 @@ static int onmatch_create(struct hist_trigger_data *hist_data, }if (param[0 ] =='$' ) - hist_field =onmatch_find_var (hist_data, data, system, - event_name, param); + hist_field =trace_action_find_var (hist_data, data, + system, event_name, + param); else - hist_field = onmatch_create_field_var(hist_data, data, - system,
(quoted diff) +0
-1- even
t_name,(quoted diff) +0
-1- param);
(quoted diff) +1
-0+ hist_field =trace_action_create_field_var(hist_data,
(quoted diff) +5
-1+ data, + system, + event_name, + param); if (!hist_field) { kfree(p);@@ -3701,7 +3740,7 @@ static int onmatch_create(struct hist_trigger_data *hist_data, continue; } - hist_err_event("onmatch: Param type doesn't match synthetic event field type: ", + hist_err_event("trace action: Param type doesn't match synthetic event field type: ",kernel/trace/trace_events_hist.c +1
-2system, event_name, param);kfree (p); ret = -EINVAL ;@@ -3709,12 +3748,11 @@ static int onmatch_create(struct hist_trigger_data *hist_data, }if (field_pos != event->n_fields) { - hist_err("onmatch: Param count doesn't match synthetic event field count: ", event->name); + hist_err("trace action: Param count doesn't match synthetic event field count: ", event->name); ret = -EINVAL ; goto err; } - data->fn = action_trace;kernel/trace/trace_events_hist.c +0
-0data->onmatch.synth_event = event; data->onmatch.var_ref_idx = var_ref_idx; out:@@ -3727,10 +3765,60 @@ static int onmatch_create(structhist_trigger_data *hist_data, goto out; }kernel/trace/trace_events_hist.c static int onmatch_create(struct · line 3778
Quoted 10 lines
kernel/trace/trace_events_hist.c +10
-0+static int action_create (struct hist_trigger_data *hist_data, +struct action_data *data) +{ +struct field_var *field_var; +unsigned int i; +char *param; +int ret =0 ; + +if (data->action ==ACTION_TRACE ) { + ret =trace_action_create (hist_data, data);This can return soon without "goto".
Quoted 9 lines
kernel/trace/trace_events_hist.c static int onmatch_create(struct hist_trigger_data *hist_data, · line 3783
Quoted 6 lines
kernel/trace/trace_events_hist.c +6
-0+ goto out; + } + +if (data->action ==ACTION_SAVE ) { +if (hist_data->n_save_vars) { + ret = -EINVAL ;Maybe
-EEXIST?
Yep, makes sense, will change.
Quoted 156 lines
Quoted 78 lines
kernel/trace/trace_events_hist.c +35
-0+ hist_err("save action: Can't have more than one save() action per hist", ""); + goto out; + } + +for (i =0 ; i < data->n_params; i++) { + param =kstrdup (data->params[i],GFP_KERNEL ); +if (!param) { + ret = -ENOMEM ; + goto out; + } + + field_var =create_target_field_var (hist_data,NULL ,NULL , param); +if (IS_ERR (field_var)) { + hist_err("save action: Couldn't create field variable: ", param); + ret =PTR_ERR (field_var); +kfree (param); + goto out; + } + + hist_data->save_vars[hist_data- >n_save_vars++] = field_var; +if (field_var->val->flags &HIST_FIELD_FL_STRING ) + hist_data->n_save_var_str++; +kfree (param); + } + } + out: +return ret; +} + +static int onmatch_create (struct hist_trigger_data *hist_data, +struct action_data *data) +{ +return action_create (hist_data, data); +} + static struct action_data *onmatch_parse(struct trace_array *tr,char *str)
{kernel/trace/trace_events_hist.c +0
-22char *match_event, *match_event_system; -char *synth_event_name, *params;struct action_data *data;int ret = -EINVAL ;@@ -3768,33 +3856,11 @@ static struct action_data *onmatch_parse(struct trace_array *tr, char *str) goto free; } -strsep (&str,"." ); -if (!str) { -hist_err ("onmatch: Missing . after onmatch(): " , str); - goto free; - } - - synth_event_name =strsep (&str,"(" ); -if (!synth_event_name || !str) { -hist_err ("onmatch: Missing opening paramlist paren: ", synth_event_name); - goto free; - } - - data->onmatch.synth_event_name =kstrdup (synth_event_name, GFP_KERNEL); -if (!data->onmatch.synth_event_name) { - ret = -ENOMEM ; - goto free; - } - - params =strsep (&str,")" ); -if (!params || !str || (str &&strlen (str))) { - hist_err("onmatch: Missing closing paramlistkernel/trace/trace_events_hist.c static struct action_data · line 3863
Quoted 10 lines
kernel/trace/trace_events_hist.c +3
-4paren: ", params); - goto free; - } - - ret =parse_action_params (params, data); + ret =action_parse (str, data,HANDLER_ONMATCH );if (ret) goto free; + + data->handler =HANDLER_ONMATCH ;This assignment seems to be done in
action_parse().Quoted 65 lines
out:
kernel/trace/trace_events_hist.c +2
-2return data; free:@@ -4232,9 +4298,9 @@ static void destroy_actions(struct hist_trigger_data *hist_data)for (i =0 ; i < hist_data->n_actions; i++) {struct action_data *data = hist_data->actions[i]; -if (data->fn == action_trace) +if (data->handler ==HANDLER_ONMATCH )onmatch_destroy (data); -else if (data->fn == onmax_save) +else if (data->handler ==HANDLER_ONMAX )onmax_destroy (data);else kernel/trace/trace_events_hist.c +1
-3kfree (data);@@ -4260,16 +4326,14 @@ static int parse_actions(struct hist_trigger_data *hist_data) ret =PTR_ERR (data);break ; } - data->fn = action_trace; }else if (strncmp (str,"onmax(" ,strlen ("onmax(" )) ==0 ) {char *action_str = str +strlen ("onmax(" ); - data =onmax_parse (action_str); + data =onmax_parse (action_str,HANDLER_ONMAX );if (IS_ERR (data)) { ret =PTR_ERR (data);break ; } - data->fn = onmax_save;kernel/trace/trace_events_hist.c +1
-2}else { ret = -EINVAL ;break ;@@ -4281,8 +4345,7 @@ static int parse_actions(struct hist_trigger_data *hist_data)return ret; } -static int create_actions (struct hist_trigger_data *hist_data, -struct trace_event_file *file) +static int create_actions (struct hist_trigger_data *hist_data) {struct action_data *data;kernel/trace/trace_events_hist.c +3
-3unsigned int i;@@ -4291,14 +4354,17 @@ static int create_actions(struct hist_trigger_data *hist_data, for (i = 0; i < hist_data->attrs->n_actions; i++) { data = hist_data->actions[i]; -if (data->fn == action_trace) { - ret =onmatch_create (hist_data, file, data); +if (data->handler ==HANDLER_ONMATCH ) { + ret =onmatch_create (hist_data, data);if (ret)return ret; - }else if (data->fn == onmax_save) { + }else if (data->handler ==HANDLER_ONMAX ) { ret =onmax_create (hist_data, data);if (ret)return ret;
Quoted 9 lines
kernel/trace/trace_events_hist.c static int create_actions(struct hist_trigger_data *hist_data, · line 4366
Quoted 2 lines
kernel/trace/trace_events_hist.c +2
-0+ }else { + ret = -EINVAL ;This is a bit odd (or just mixtured), return
-EINVALwill be enough here.
Or above "if (ret) return ret;" shoud be "if (ret) break;" since this function
returns ret soon after this loop.
Yeah, I'll change them all to just break, and have them all fall into the final ret.
Thanks,
Tom
Quoted 8 lines
Quoted 4 lines
kernel/trace/trace_events_hist.c +1
-0+break ; }}
Thank you,
PATCH v6 2/15 tracing: Make hist trigger Documentation better reflect actions/handlers
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
The action/handler code refactoring didn't change the action/handler syntax, but did generalize it - the Documentation should reflect that.
--- Documentation/trace/histogram.rst | 56 ++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 13 deletions(-)
Documentation/trace/histogram.rst +43 -13
@@ -25,7 +25,7 @@ Documentation written by Tom Zanussi hist:keys=<field1[,field2,...]>[:values=<field1[,field2,...]>] [:sort=<field1[,field2,...]>][:size=#entries][:pause][:continue] - [:clear][:name=histname1] [if <filter>] + [:clear][:name=histname1][:<handler>.<action>] [if <filter>] When a matching event is hit, an entry is added to a hash table using the key(s) and value(s) named. Keys and values correspond to
@@ -1831,21 +1831,51 @@ and looks and behaves just like any other event:: Like any other event, once a histogram is enabled for the event, the output can be displayed by reading the event's 'hist' file. -2.2.3 Hist trigger 'actions' ----------------------------- +2.2.3 Hist trigger 'handlers' and 'actions' +------------------------------------------- -A hist trigger 'action' is a function that's executed whenever a -histogram entry is added or updated. +A hist trigger 'action' is a function that's executed (in most cases +conditionally) whenever a histogram entry is added or updated. -The default 'action' if no special function is explicity specified is -as it always has been, to simply update the set of values associated -with an entry. Some applications, however, may want to perform -additional actions at that point, such as generate another event, or -compare and save a maximum. +When histogram entry is added or updated, a hist trigger 'handler' is +what decides whether the corresponding action is actually invoked or +not. -The following additional actions are available. To specify an action -for a given event, simply specify the action between colons in the -hist trigger specification. +Hist trigger handlers and actions are paired together in the general +form: + + <handler>.<action> + +To specify a handler.action pair for a given event, simply specify +that handler.action pair between colons in the hist trigger +specification. + +In theory, any handler can be combined with any action, but in +practice, not every handler.action combination is currently supported; +if a given handler.action combination isn't supported, the hist +trigger will fail with -EINVAL; + +The default 'handler.action' if none is explicity specified is as it +always has been, to simply update the set of values associated with an +entry. Some applications, however, may want to perform additional +actions at that point, such as generate another event, or compare and +save a maximum. + +The supported handlers and actions are listed below, and each is +described in more detail in the following paragraphs, in the context +of descriptions of some common and useful handler.action combinations. + +The available handlers are: + + - onmatch(matching.event) - invoke action on any addition or update + - onmax(var) - invoke action if var exceeds current max + +The available actions are: + + - <synthetic_event_name>(param list) - generate synthetic event + - save(field,...) - save current event fields + +The following commonly-used handler.action pairs are available: - onmatch(matching.event).<synthetic_event_name>(param list)
Signature · 1 line
2.14.1
PATCH v6 3/15 tracing: Add hist trigger handler.action documentation to README
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
Add abbreviated documentation for handlers and actions to README.
--- kernel/trace/trace.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
kernel/trace/trace.c +11 -1
@@ -4680,6 +4680,7 @@ static const char readme_msg[] ="\t [:size=#entries]\n" "\t [:pause][:continue][:clear]\n" "\t [:name=histname1]\n" +"\t [:<handler>.<action>]\n" "\t [if <filter>]\n\n" "\t When a matching event is hit, an entry is added to a hash\n" "\t table using the key(s) and value(s) named, and the value of a\n"
@@ -4721,7 +4722,16 @@ static const char readme_msg[] ="\t The enable_hist and disable_hist triggers can be used to\n" "\t have one event conditionally start and stop another event's\n" "\t already-attached hist trigger. The syntax is analagous to\n" - "\t the enable_event and disable_event triggers.\n" +"\t the enable_event and disable_event triggers.\n\n" +"\t Hist trigger handlers and actions are executed whenever a\n" +"\t a histogram entry is added or updated. They take the form:\n\n" +"\t <handler>.<action>\n\n" +"\t The available handlers are:\n\n" +"\t onmatch(matching.event) - invoke on addition or update\n" +"\t onmax(var) - invoke if var exceeds current max\n\n" +"\t The available actions are:\n\n" +"\t <synthetic_event>(param list) - generate synthetic event\n" + "\t save(field,...) - save current event fields\n"#endif ;
Signature · 1 line
2.14.1
PATCH v6 4/15 tracing: Split up onmatch action data
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
Currently, the onmatch action data binds the onmatch action to data related to synthetic event generation. Since we want to allow the onmatch handler to potentially invoke a different action, and because we expect other handlers to generate synthetic events, we need to separate the data related to these two functions.
Also rename the onmatch data to something more descriptive, and create and use common action data destroy function.
--- kernel/trace/trace_events_hist.c | 91 ++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 45 deletions(-)
kernel/trace/trace_events_hist.c +46 -45
@@ -338,13 +338,14 @@ struct action_data {unsigned int n_params;char *params[SYNTH_FIELDS_MAX ]; +unsigned int var_ref_idx; +struct synth_event *synth_event; +union {struct { -unsigned int var_ref_idx; -char *match_event; -char *match_event_system; -struct synth_event *synth_event; - } onmatch; +char *event; +char *event_system; + } match_data;struct {char *var_str;
@@ -992,9 +993,9 @@ static void action_trace(struct hist_trigger_data *hist_data,struct ring_buffer_event *rbe, struct action_data *data, u64 *var_ref_vals) { - struct synth_event *event = data->onmatch.synth_event; + struct synth_event *event = data->synth_event; -trace_synth (event, var_ref_vals, data->onmatch.var_ref_idx); +trace_synth (event, var_ref_vals, data->var_ref_idx); } struct hist_var_data {
@@ -1564,8 +1565,8 @@ find_match_var(struct hist_trigger_data *hist_data, char *var_name)struct action_data *data = hist_data->actions[i];if (data->handler ==HANDLER_ONMATCH ) { -char *system = data->onmatch.match_event_system; -char *event_name = data->onmatch.match_event; +char *system = data->match_data.event_system; +char *event_name = data->match_data.event; file =find_var_file (tr, system, event_name, var_name);if (!file)
@@ -3301,20 +3302,33 @@ static void onmax_save(struct hist_trigger_data *hist_data,update_max_vars (hist_data, elt, rbe, rec); } -static void onmax_destroy (struct action_data *data) +static void action_data_destroy (struct action_data *data) {unsigned int i; -destroy_hist_field (data->onmax.max_var,0 ); -destroy_hist_field (data->onmax.var,0 ); +mutex_lock (&synth_event_mutex); -kfree (data->onmax.var_str);kfree (data->action_name);for (i =0 ; i < data->n_params; i++)kfree (data->params[i]); +if (data->synth_event) + data->synth_event->ref--; +kfree (data); + +mutex_unlock (&synth_event_mutex); +} + +static void onmax_destroy (struct action_data *data) +{ +destroy_hist_field (data->onmax.max_var,0 ); +destroy_hist_field (data->onmax.var,0 ); + +kfree (data->onmax.var_str); + +action_data_destroy (data); } static int action_create(struct hist_trigger_data *hist_data,
@@ -3506,23 +3520,10 @@ static struct action_data *onmax_parse(char *str, enum handler_id handler)static void onmatch_destroy (struct action_data *data) { -unsigned int i; - -mutex_lock (&synth_event_mutex); - -kfree (data->onmatch.match_event); -kfree (data->onmatch.match_event_system); -kfree (data->action_name); +kfree (data->match_data.event); +kfree (data->match_data.event_system); -for (i =0 ; i < data->n_params; i++) -kfree (data->params[i]); - -if (data->onmatch.synth_event) - data->onmatch.synth_event->ref--; - -kfree (data); - -mutex_unlock (&synth_event_mutex); +action_data_destroy (data); }static void destroy_field_var (struct field_var *field_var)
@@ -3600,8 +3601,8 @@ trace_action_find_var(struct hist_trigger_data *hist_data, hist_field =find_target_event_var (hist_data, system, event, var);if (!hist_field) {if (!system && data->handler ==HANDLER_ONMATCH ) { - system = data->onmatch.match_event_system; - event = data->onmatch.match_event; + system = data->match_data.event_system; + event = data->match_data.event; } hist_field =find_event_var (hist_data, system, event, var);
@@ -3640,8 +3641,8 @@ trace_action_create_field_var(struct hist_trigger_data *hist_data,* event. */ if (!system && data->handler ==HANDLER_ONMATCH ) { - system = data->onmatch.match_event_system; - event = data->onmatch.match_event; + system = data->match_data.event_system; + event = data->match_data.event; }/*
@@ -3753,8 +3754,8 @@ static int trace_action_create(struct hist_trigger_data *hist_data, goto err; } - data->onmatch.synth_event = event; - data->onmatch.var_ref_idx = var_ref_idx; + data->synth_event = event; + data->var_ref_idx = var_ref_idx; out:return ret; err:
@@ -3844,14 +3845,14 @@ static struct action_data *onmatch_parse(struct trace_array *tr, char *str) goto free; } - data->onmatch.match_event =kstrdup (match_event,GFP_KERNEL ); -if (!data->onmatch.match_event) { + data->match_data.event =kstrdup (match_event,GFP_KERNEL ); +if (!data->match_data.event) { ret = -ENOMEM ; goto free; } - data->onmatch.match_event_system =kstrdup (match_event_system,GFP_KERNEL ); -if (!data->onmatch.match_event_system) { + data->match_data.event_system =kstrdup (match_event_system,GFP_KERNEL ); +if (!data->match_data.event_system) { ret = -ENOMEM ; goto free; }
@@ -4424,8 +4425,8 @@ static void print_onmatch_spec(struct seq_file *m, struct hist_trigger_data *hist_data, struct action_data *data) { - seq_printf(m, ":onmatch(%s.%s).", data->onmatch.match_event_system, - data->onmatch.match_event); + seq_printf(m, ":onmatch(%s.%s).", data->match_data.event_system, + data->match_data.event);seq_printf (m,"%s(" , data->action_name);
@@ -4463,11 +4464,11 @@ static bool actions_match(struct hist_trigger_data *hist_data,return false;if (data->handler ==HANDLER_ONMATCH ) { -if (strcmp (data->onmatch.match_event_system, - data_test->onmatch.match_event_system) !=0 ) +if (strcmp (data->match_data.event_system, + data_test->match_data.event_system) !=0 )return false; -if (strcmp (data->onmatch.match_event, - data_test->onmatch.match_event) !=0 ) +if (strcmp (data->match_data.event, + data_test->match_data.event) !=0 )return false; }else if (data->handler ==HANDLER_ONMAX ) { if (strcmp(data->onmax.var_str,
Signature · 1 line
2.14.1
PATCH v6 5/15 tracing: Generalize hist trigger onmax and save action
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
The action refactor code allowed actions and handlers to be separated, but the existing onmax handler and save action code is still not flexible enough to handle arbitrary coupling. This change generalizes them and in the process makes additional handlers and actions easier to implement.
The onmax action can be broken up and thought of as two separate components - a variable to be tracked (the parameter given to the onmax($var_to_track) function) and an invisible variable created to save the ongoing result of doing something with that variable, such as saving the max value of that variable so far seen.
Separating it out like this and renaming it appropriately allows us to use the same code for similar tracking functions such as onchange($var_to_track), which would just track the last value seen rather than the max seen so far, which is useful in some situations.
Additionally, because different handlers and actions may want to save and access data differently e.g. save and retrieve tracking values as local variables vs something more global, save_val() and get_val() interface functions are introduced and max-specific implementations are used instead.
The same goes for the code that checks whether a maximum has been hit
- a generic check_val() interface and max-checking implementation is used instead, which allows future patches to make use of he same code using their own implemetations of similar functionality.
--- kernel/trace/trace_events_hist.c | 220 ++++++++++++++++++++++++++------------- 1 file changed, 147 insertions(+), 73 deletions(-)
kernel/trace/trace_events_hist.c +147 -73
@@ -319,6 +319,15 @@ typedef void (*action_fn_t) (struct hist_trigger_data *hist_data,struct ring_buffer_event *rbe, struct action_data *data, u64 *var_ref_vals); +typedef bool (*check_track_val_fn_t ) (u64 track_val,u64 var_val); +typedef bool (*save_track_val_fn_t ) (struct hist_trigger_data *hist_data, +struct tracing_map_elt *elt, +struct action_data *data, +unsigned int track_var_idx,u64 var_val); +typedef u64 (*get_track_val_fn_t ) (struct hist_trigger_data *hist_data, +struct tracing_map_elt *elt, +struct action_data *data); +enum handler_id {HANDLER_ONMATCH =1 ,HANDLER_ONMAX ,
@@ -349,14 +358,18 @@ struct action_data {struct {char *var_str; -unsigned int max_var_ref_idx; -struct hist_field *max_var; -struct hist_field *var; - } onmax; +struct hist_field *var_ref; +unsigned int var_ref_idx; + +struct hist_field *track_var; + +check_track_val_fn_t check_val; +save_track_val_fn_t save_val; +get_track_val_fn_t get_val; + } track_data; }; }; -static char last_hist_cmd[MAX_FILTER_STR_VAL ];static char hist_err_str[MAX_FILTER_STR_VAL ];
@@ -3113,10 +3126,10 @@ static void update_field_vars(struct hist_trigger_data *hist_data, hist_data->n_field_vars, 0); } -static void update_max_vars (struct hist_trigger_data *hist_data, -struct tracing_map_elt *elt, -struct ring_buffer_event *rbe, -void *rec) +static void update_save_vars (struct hist_trigger_data *hist_data, +struct tracing_map_elt *elt, +struct ring_buffer_event *rbe, +void *rec) {__update_field_vars (elt, rbe, rec, hist_data->save_vars, hist_data->n_save_vars, hist_data->n_field_var_str);
@@ -3254,15 +3267,68 @@ create_target_field_var(struct hist_trigger_data *target_hist_data,return create_field_var (target_hist_data, file, var_name); } -static void onmax_print (struct seq_file *m, -struct hist_trigger_data *hist_data, -struct tracing_map_elt *elt, -struct action_data *data) +static bool check_track_val_max (u64 track_val,u64 var_val) { -unsigned int i, save_var_idx, max_idx = data->onmax.max_var->var.idx; +if (var_val <= track_val) +return false; + +return true; +} + +static u64 get_track_val_local (struct hist_trigger_data *hist_data, +struct tracing_map_elt *elt, +struct action_data *data) +{ +unsigned int track_var_idx = data->track_data.track_var->var.idx; +u64 track_val; + + track_val =tracing_map_read_var (elt, track_var_idx); + +return track_val; +} + +static bool save_track_val_local (struct hist_trigger_data *hist_data, +struct tracing_map_elt *elt, +struct action_data *data, +unsigned int track_var_idx,u64 var_val) +{ +bool ret = false; +u64 track_val; + + track_val =tracing_map_read_var (elt, track_var_idx); + +if (data->track_data.check_val (track_val, var_val)) { +tracing_map_set_var (elt, track_var_idx, var_val); + ret = true; + } + +return ret; +} + +static bool update_track_val (struct hist_trigger_data *hist_data, +struct tracing_map_elt *elt, +struct action_data *data,u64 *var_ref_vals) +{ +unsigned int track_var_idx = data->track_data.track_var->var.idx; +unsigned int track_var_ref_idx = data->track_data.var_ref_idx; +u64 var_val; + + var_val = var_ref_vals[track_var_ref_idx]; + +return data->track_data.save_val (hist_data, elt, data, + track_var_idx, var_val); +} + +static void track_data_print (struct seq_file *m, +struct hist_trigger_data *hist_data, +struct tracing_map_elt *elt, +struct action_data *data) +{ +u64 track_val = data->track_data.get_val (hist_data, elt, data); +unsigned int i, save_var_idx;if (data->handler ==HANDLER_ONMAX ) -seq_printf (m,"\n\tmax: %10llu" ,tracing_map_read_var (elt, max_idx)); +seq_printf (m,"\n\tmax: %10llu" , track_val);for (i =0 ; i < hist_data->n_save_vars; i++) {struct hist_field *save_val = hist_data->save_vars[i]->val;
@@ -3281,25 +3347,13 @@ static void onmax_print(struct seq_file *m, } } -static void onmax_save (struct hist_trigger_data *hist_data, -struct tracing_map_elt *elt,void *rec, -struct ring_buffer_event *rbe, -struct action_data *data,u64 *var_ref_vals) +static void ontrack_save (struct hist_trigger_data *hist_data, +struct tracing_map_elt *elt,void *rec, +struct ring_buffer_event *rbe, +struct action_data *data,u64 *var_ref_vals) { -unsigned int max_idx = data->onmax.max_var->var.idx; -unsigned int max_var_ref_idx = data->onmax.max_var_ref_idx; - -u64 var_val, max_val; - - var_val = var_ref_vals[max_var_ref_idx]; - max_val =tracing_map_read_var (elt, max_idx); - -if (var_val <= max_val) -return ; - -tracing_map_set_var (elt, max_idx, var_val); - -update_max_vars (hist_data, elt, rbe, rec); +if (update_track_val (hist_data, elt, data, var_ref_vals)) +update_save_vars (hist_data, elt, rbe, rec); }static void action_data_destroy (struct action_data *data)
@@ -3321,12 +3375,13 @@ static void action_data_destroy(struct action_data *data)mutex_unlock (&synth_event_mutex); } -static void onmax_destroy (struct action_data *data) +static void track_data_destroy (struct hist_trigger_data *hist_data, +struct action_data *data) { -destroy_hist_field (data->onmax.max_var,0 ); -destroy_hist_field (data->onmax.var,0 ); +destroy_hist_field (data->track_data.track_var,0 ); +destroy_hist_field (data->track_data.var_ref,0 ); -kfree (data->onmax.var_str); +kfree (data->track_data.var_str);action_data_destroy (data); }
@@ -3334,26 +3389,26 @@ static void onmax_destroy(struct action_data *data)static int action_create (struct hist_trigger_data *hist_data,struct action_data *data); -static int onmax_create (struct hist_trigger_data *hist_data, -struct action_data *data) +static int track_data_create (struct hist_trigger_data *hist_data, +struct action_data *data) { -struct hist_field *var_field, *ref_field, *max_var =NULL ; +struct hist_field *var_field, *ref_field, *track_var =NULL ;struct trace_event_file *file = hist_data->event_file;unsigned int var_ref_idx = hist_data->n_var_refs; -char *onmax_var_str; +char *track_data_var_str;unsigned long flags;int ret =0 ; - onmax_var_str = data->onmax.var_str; -if (onmax_var_str[0 ] !='$' ) { -hist_err ("onmax: For onmax(x), x must be a variable: " , onmax_var_str); + track_data_var_str = data->track_data.var_str; +if (track_data_var_str[0 ] !='$' ) { +hist_err ("For onmax(x), x must be a variable: " , track_data_var_str);return -EINVAL ; } - onmax_var_str++; + track_data_var_str++; - var_field =find_target_event_var (hist_data,NULL ,NULL , onmax_var_str); + var_field =find_target_event_var (hist_data,NULL ,NULL , track_data_var_str);if (!var_field) { -hist_err ("onmax: Couldn't find onmax variable: " , onmax_var_str); +hist_err ("Couldn't find onmax variable: " , track_data_var_str);return -EINVAL ; }
@@ -3369,18 +3424,18 @@ static int onmax_create(struct hist_trigger_data *hist_data, } hist_data->var_refs[hist_data->n_var_refs] = ref_field; ref_field->var_ref_idx = hist_data->n_var_refs++; - data->onmax.var = ref_field; + data->track_data.var_ref = ref_field; - data->onmax.max_var_ref_idx = var_ref_idx; + data->track_data.var_ref_idx = var_ref_idx;if (data->handler ==HANDLER_ONMAX ) - max_var =create_var (hist_data, file,"max" ,sizeof (u64),"u64" ); -if (IS_ERR (max_var)) { -hist_err ("onmax: Couldn't create onmax variable: " ,"max" ); - ret =PTR_ERR (max_var); + track_var =create_var (hist_data, file,"__max" ,sizeof (u64),"u64" ); +if (IS_ERR (track_var)) { +hist_err ("Couldn't create onmax variable: " ,"__max" ); + ret =PTR_ERR (track_var); goto out; } - data->onmax.max_var = max_var; + data->track_data.track_var = track_var; ret =action_create (hist_data, data); out:
@@ -3458,7 +3513,17 @@ static int action_parse(char *str, struct action_data *data, goto out;if (handler ==HANDLER_ONMAX ) - data->fn = onmax_save; + data->track_data.check_val = check_track_val_max; +else { +hist_err ("action parsing: Handler doesn't support action: " , action_name); + ret = -EINVAL ; + goto out; + } + + data->track_data.save_val = save_track_val_local; + data->track_data.get_val = get_track_val_local; + + data->fn = ontrack_save; data->action =ACTION_SAVE ; }else {
@@ -3470,7 +3535,14 @@ static int action_parse(char *str, struct action_data *data, goto out; } +if (handler ==HANDLER_ONMAX ) + data->track_data.check_val = check_track_val_max; + + data->track_data.save_val = save_track_val_local; + data->track_data.get_val = get_track_val_local; + data->fn = action_trace; + data->action =ACTION_TRACE ; }
@@ -3483,24 +3555,25 @@ static int action_parse(char *str, struct action_data *data,return ret; } -static struct action_data *onmax_parse (char *str,enum handler_id handler) +static struct action_data *track_data_parse (struct hist_trigger_data *hist_data, +char *str,enum handler_id handler) {struct action_data *data; -char *onmax_var_str;int ret = -EINVAL ; +char *var_str; data =kzalloc (sizeof (*data),GFP_KERNEL );if (!data)return ERR_PTR (-ENOMEM ); - onmax_var_str =strsep (&str,")" ); -if (!onmax_var_str || !str) { + var_str =strsep (&str,")" ); +if (!var_str || !str) { ret = -EINVAL ; goto free; } - data->onmax.var_str =kstrdup (onmax_var_str,GFP_KERNEL ); -if (!data->onmax.var_str) { + data->track_data.var_str =kstrdup (var_str,GFP_KERNEL ); +if (!data->track_data.var_str) { ret = -ENOMEM ; goto free; }
@@ -3513,7 +3586,7 @@ static struct action_data *onmax_parse(char *str, enum handler_id handler) out:return data; free: -onmax_destroy (data); +track_data_destroy (hist_data, data); data =ERR_PTR (ret); goto out; }
@@ -4302,7 +4375,7 @@ static void destroy_actions(struct hist_trigger_data *hist_data)if (data->handler ==HANDLER_ONMATCH )onmatch_destroy (data);else if (data->handler ==HANDLER_ONMAX ) -onmax_destroy (data); +track_data_destroy (hist_data, data);else kfree (data); }
@@ -4330,7 +4403,8 @@ static int parse_actions(struct hist_trigger_data *hist_data) }else if (strncmp (str,"onmax(" ,strlen ("onmax(" )) ==0 ) {char *action_str = str +strlen ("onmax(" ); - data =onmax_parse (action_str,HANDLER_ONMAX ); + data =track_data_parse (hist_data, action_str, +HANDLER_ONMAX );if (IS_ERR (data)) { ret =PTR_ERR (data);break ;
@@ -4360,7 +4434,7 @@ static int create_actions(struct hist_trigger_data *hist_data)if (ret)return ret; }else if (data->handler ==HANDLER_ONMAX ) { - ret =onmax_create (hist_data, data); + ret =track_data_create (hist_data, data);if (ret)return ret; }else {
@@ -4382,7 +4456,7 @@ static void print_actions(struct seq_file *m,struct action_data *data = hist_data->actions[i];if (data->handler ==HANDLER_ONMAX ) -onmax_print (m, hist_data, elt, data); +track_data_print (m, hist_data, elt, data); } }
@@ -4407,13 +4481,13 @@ static void print_action_spec(struct seq_file *m, } } -static void print_onmax_spec (struct seq_file *m, -struct hist_trigger_data *hist_data, -struct action_data *data) +static void print_track_data_spec (struct seq_file *m, +struct hist_trigger_data *hist_data, +struct action_data *data) {if (data->handler ==HANDLER_ONMAX )seq_puts (m,":onmax(" ); -seq_printf (m,"%s" , data->onmax.var_str); +seq_printf (m,"%s" , data->track_data.var_str);seq_printf (m,").%s(" , data->action_name);print_action_spec (m, hist_data, data);
@@ -4471,8 +4545,8 @@ static bool actions_match(struct hist_trigger_data *hist_data, data_test->match_data.event) != 0)return false; }else if (data->handler ==HANDLER_ONMAX ) { -if (strcmp (data->onmax.var_str, - data_test->onmax.var_str) !=0 ) +if (strcmp (data->track_data.var_str, + data_test->track_data.var_str) !=0 )return false; } }
@@ -4492,7 +4566,7 @@ static void print_actions_spec(struct seq_file *m,if (data->handler ==HANDLER_ONMATCH )print_onmatch_spec (m, hist_data, data);else if (data->handler ==HANDLER_ONMAX ) -print_onmax_spec (m, hist_data, data); +print_track_data_spec (m, hist_data, data); } }
Signature · 1 line
2.14.1
PATCH v6 6/15 tracing: Add conditional snapshot
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
Currently, tracing snapshots are context-free - they capture the ring buffer contents at the time the tracing_snapshot() function was invoked, and nothing else. Additionally, they're always taken unconditionally - the calling code can decide whether or not to take a snapshot, but the data used to make that decision is kept separately from the snapshot itself.
This change adds the ability to associate with each trace instance some user data, along with an 'update' function that can use that data to determine whether or not to actually take a snapshot. The update function can then update that data along with any other state (as part of the data presumably), if warranted.
Because snapshots are 'global' per-instance, only one user can enable and use a conditional snapshot for any given trace instance. To enable a conditional snapshot (see details in the function and data structure comments), the user calls tracing_snapshot_cond_enable(). Similarly, to disable a conditional snapshot and free it up for other users, tracing_snapshot_cond_disable() should be called.
To actually initiate a conditional snapshot, tracing_snapshot_cond() should be called. tracing_snapshot_cond() will invoke the update() callback, allowing the user to decide whether or not to actually take the snapshot and update the user-defined data associated with the snapshot. If the callback returns 'true', tracing_snapshot_cond() will then actually take the snapshot and return.
This scheme allows for flexibility in snapshot implementations - for example, by implementing slightly different update() callbacks, snapshots can be taken in situations where the user is only interested in taking a snapshot when a new maximum in hit versus when a value changes in any way at all. Future patches will demonstrate both cases.
--- kernel/trace/trace.c | 162 ++++++++++++++++++++++++++++++++++-- kernel/trace/trace.h | 56 ++++++++++++- kernel/trace/trace_events_trigger.c | 2 +- kernel/trace/trace_sched_wakeup.c | 2 +- 4 files changed, 211 insertions(+), 11 deletions(-)
kernel/trace/trace.c +155 -7
@@ -894,7 +894,7 @@ int __trace_bputs(unsigned long ip, const char *str)EXPORT_SYMBOL_GPL (__trace_bputs);#ifdef CONFIG_TRACER_SNAPSHOT -void tracing_snapshot_instance (struct trace_array *tr) +void tracing_snapshot_instance (struct trace_array *tr,void *cond_data) {struct tracer *tracer = tr->current_trace;unsigned long flags;
@@ -920,7 +920,7 @@ void tracing_snapshot_instance(struct trace_array *tr) }local_irq_save (flags); -update_max_tr (tr, current,smp_processor_id ()); +update_max_tr (tr, current,smp_processor_id (), cond_data);local_irq_restore (flags); }
@@ -942,10 +942,58 @@ void tracing_snapshot(void) {struct trace_array *tr = &global_trace; -tracing_snapshot_instance (tr); +tracing_snapshot_instance (tr,NULL ); }EXPORT_SYMBOL_GPL (tracing_snapshot); +/** +* tracing_snapshot_cond - conditionally take a snapshot of the current buffer. +* @tr: The tracing instance to snapshot +* @cond_data: The data to be tested conditionally, and possibly saved +* +* This is the same as tracing_snapshot() except that the snapshot is +* conditional - the snapshot will only happen if the +* cond_snapshot.update() implementation receiving the cond_data +* returns true, which means that the trace array's cond_snapshot +* update() operation used the cond_data to determine whether the +* snapshot should be taken, and if it was, presumably saved it along +* with the snapshot. +*/ +void tracing_snapshot_cond (struct trace_array *tr,void *cond_data) +{ +tracing_snapshot_instance (tr, cond_data); +} +EXPORT_SYMBOL_GPL (tracing_snapshot_cond); + +/** +* tracing_snapshot_cond_data - get the user data associated with a snapshot +* @tr: The tracing instance +* +* When the user enables a conditional snapshot using +* tracing_snapshot_cond_enable(), the user-defined cond_data is saved +* with the snapshot. This accessor is used to retrieve it. +* +* Should not be called from cond_snapshot.update(), since it takes +* the tr->max_lock lock, which the code calling +* cond_snapshot.update() has already done. +* +* Returns the cond_data associated with the trace array's snapshot. +*/ +void *tracing_cond_snapshot_data (struct trace_array *tr) +{ +void *cond_data =NULL ; + +arch_spin_lock (&tr->max_lock); + +if (tr->cond_snapshot) + cond_data = tr->cond_snapshot->cond_data; + +arch_spin_unlock (&tr->max_lock); + +return cond_data; +} +EXPORT_SYMBOL_GPL (tracing_cond_snapshot_data); +static int resize_buffer_duplicate_size (struct trace_buffer *trace_buf,struct trace_buffer *size_buf,int cpu_id);static void set_buffer_entries (struct trace_buffer *buf,unsigned long val);
@@ -1025,12 +1073,85 @@ void tracing_snapshot_alloc(void)tracing_snapshot (); }EXPORT_SYMBOL_GPL (tracing_snapshot_alloc); + +/** +* tracing_snapshot_cond_enable - enable conditional snapshot for an instance +* @tr: The tracing instance +* @cond_data: User data to associate with the snapshot +* @update: Implementation of the cond_snapshot update function +* +* Check whether the conditional snapshot for the given instance has +* already been enabled; if so, return -EBUSY, else create a +* cond_snapshot and save the cond_data and update function inside. +* +* Returns 0 if successful, error otherwise. +*/ +int tracing_snapshot_cond_enable (struct trace_array *tr,void *cond_data, +cond_update_fn_t update) +{ +struct cond_snapshot *cond_snapshot; +int ret =0 ; + + cond_snapshot =kzalloc (sizeof (*cond_snapshot),GFP_KERNEL ); +if (!cond_snapshot) +return -ENOMEM ; + + cond_snapshot->cond_data = cond_data; + cond_snapshot->update = update; + +arch_spin_lock (&tr->max_lock); + +if (tr->cond_snapshot) { +kfree (cond_snapshot); + ret = -EBUSY ; + }else + tr->cond_snapshot = cond_snapshot; + +arch_spin_unlock (&tr->max_lock); + +return ret; +} +EXPORT_SYMBOL_GPL (tracing_snapshot_cond_enable); + +/** +* tracing_snapshot_cond_disable - disable conditional snapshot for an instance +* @tr: The tracing instance +* +* Check whether the conditional snapshot for the given instance is +* enabled; if so, free the cond_snapshot associated with it, +* otherwise return -EINVAL. +* +* Returns 0 if successful, error otherwise. +*/ +int tracing_snapshot_cond_disable (struct trace_array *tr) +{ +int ret =0 ; + +arch_spin_lock (&tr->max_lock); + +if (!tr->cond_snapshot) + ret = -EINVAL ; +else { +kfree (tr->cond_snapshot); + tr->cond_snapshot =NULL ; + } + +arch_spin_unlock (&tr->max_lock); + +return ret; +} +EXPORT_SYMBOL_GPL (tracing_snapshot_cond_disable);#else void tracing_snapshot (void ) {WARN_ONCE (1 ,"Snapshot feature not enabled, but internal snapshot used" ); }EXPORT_SYMBOL_GPL (tracing_snapshot); +void tracing_snapshot_cond (struct trace_array *tr,void *cond_data) +{ +WARN_ONCE (1 ,"Snapshot feature not enabled, but internal conditional snapshot used" ); +} +EXPORT_SYMBOL_GPL (tracing_snapshot_cond);int tracing_alloc_snapshot (void ) {WARN_ONCE (1 ,"Snapshot feature not enabled, but snapshot allocation used" );
@@ -1043,6 +1164,27 @@ void tracing_snapshot_alloc(void) tracing_snapshot(); }EXPORT_SYMBOL_GPL (tracing_snapshot_alloc); +void *tracing_cond_snapshot_data (struct trace_array *tr) +{ +WARN_ONCE (1 ,"Snapshot feature not enabled, but tried to get internal conditional snapshot data" ); + +return NULL ; +} +EXPORT_SYMBOL_GPL (tracing_cond_snapshot_data); +int tracing_snapshot_cond_enable (struct trace_array *tr,void *cond_data,cond_update_fn_t update) +{ +WARN_ONCE (1 ,"Snapshot feature not enabled, but tried to enable internal conditional snapshot" ); + +return false; +} +EXPORT_SYMBOL_GPL (tracing_snapshot_cond_enable); +int tracing_snapshot_cond_disable (struct trace_array *tr) +{ +WARN_ONCE (1 ,"Snapshot feature not enabled, but tried to disable internal conditional snapshot" ); + +return false; +} +EXPORT_SYMBOL_GPL (tracing_snapshot_cond_disable);#endif /* CONFIG_TRACER_SNAPSHOT */ void tracer_tracing_off (struct trace_array *tr)
@@ -1359,7 +1501,8 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)* about which task was the cause of this latency. */ void -update_max_tr (struct trace_array *tr,struct task_struct *tsk,int cpu) +update_max_tr (struct trace_array *tr,struct task_struct *tsk,int cpu, +void *cond_data) {if (tr->stop_count)return ;
@@ -1380,6 +1523,11 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)else ring_buffer_record_off (tr->max_buffer.buffer); +if (tr->cond_snapshot && !tr->cond_snapshot->update (tr, cond_data)) { +arch_spin_unlock (&tr->max_lock); +return ; + } +swap (tr->trace_buffer.buffer, tr->max_buffer.buffer);__update_max_tr (tr, tsk, cpu);
@@ -6483,7 +6631,7 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,local_irq_disable ();/* Now, we're going to swap */ if (iter->cpu_file ==RING_BUFFER_ALL_CPUS ) -update_max_tr (tr, current,smp_processor_id ()); +update_max_tr (tr, current,smp_processor_id (),NULL );else update_max_tr_single (tr, current, iter->cpu_file);local_irq_enable ();
@@ -7075,7 +7223,7 @@ ftrace_snapshot(unsigned long ip, unsigned long parent_ip, struct trace_array *tr, struct ftrace_probe_ops *ops, void *data) { -tracing_snapshot_instance (tr ); +tracing_snapshot_instance (tr ,NULL ); } static void
@@ -7097,7 +7245,7 @@ ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip, (*count)--; } -tracing_snapshot_instance (tr); +tracing_snapshot_instance (tr,NULL ); } static int
kernel/trace/trace.h +54 -2
86 lines not on this page · raw message
kernel/trace/trace_events_trigger.c +1 -1
@@ -1049,7 +1049,7 @@ snapshot_trigger(struct event_trigger_data *data, void *rec,struct trace_event_file *file = data->private_data;if (file) -tracing_snapshot_instance (file->tr); +tracing_snapshot_instance (file->tr,NULL );else tracing_snapshot (); }
kernel/trace/trace_sched_wakeup.c +1 -1
@@ -494,7 +494,7 @@ probe_wakeup_sched_switch(void *ignore, bool preempt,if (likely (!is_tracing_stopped ())) { wakeup_trace->max_latency = delta; -update_max_tr (wakeup_trace, wakeup_task, wakeup_cpu); +update_max_tr (wakeup_trace, wakeup_task, wakeup_cpu,NULL ); } out_unlock:
Signature · 1 line
2.14.1
PATCH v6 7/15 tracing: Move hist trigger key printing into a separate function
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
Future patches will want to print a histogram key outside a histogram
- add and use hist_trigger_print_key() for that purpose.
--- kernel/trace/trace_events_hist.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)
kernel/trace/trace_events_hist.c +15 -4
@@ -4849,10 +4849,10 @@ static void hist_trigger_stacktrace_print(struct seq_file *m, } } -static void -hist_trigger_entry_print (struct seq_file *m, -struct hist_trigger_data *hist_data,void *key, -struct tracing_map_elt *elt) +static void hist_trigger_print_key (struct seq_file *m, +struct hist_trigger_data *hist_data, +void *key, +struct tracing_map_elt *elt) {struct hist_field *key_field;char str[KSYM_SYMBOL_LEN ];
@@ -4928,6 +4928,17 @@ hist_trigger_entry_print(struct seq_file *m,seq_puts (m," " );seq_puts (m,"}" ); +} + +static void hist_trigger_entry_print (struct seq_file *m, +struct hist_trigger_data *hist_data, +void *key, +struct tracing_map_elt *elt) +{ +const char *field_name; +unsigned int i; + +hist_trigger_print_key (m, hist_data, key, elt);seq_printf (m," hitcount: %10llu" ,tracing_map_read_sum (elt,HITCOUNT_IDX ));
Signature · 1 line
2.14.1
Masami Hiramatsu
maintainerRe: [PATCH v6 07/15] tracing: Move hist trigger key printing into a separate function
Hi Tom,
Quoted 4 lines · On Thu, 11 Oct 2018 16:02:04 -0500 Tom Zanussi <[email protected]> wrote:
From: Tom Zanussi <[email protected]>
Future patches will want to print a histogram key outside a histogram
- add and usehist_trigger_print_key()for that purpose.
Hmm, I think this change should be done with such user code, because without the user code I can not decide it is good or not.
Thank you,
Quoted 46 lines
Signed-off-by Tom Zanussi <[email protected]>--- kernel/trace/trace_events_hist.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)kernel/trace/trace_events_hist.c +15
-4@@ -4849,10 +4849,10 @@ static void hist_trigger_stacktrace_print(struct seq_file *m, } } -static void -hist_trigger_entry_print (struct seq_file *m, -struct hist_trigger_data *hist_data,void *key, -struct tracing_map_elt *elt) +static void hist_trigger_print_key (struct seq_file *m, +struct hist_trigger_data *hist_data, +void *key, +struct tracing_map_elt *elt) {struct hist_field *key_field;char str[KSYM_SYMBOL_LEN ];@@ -4928,6 +4928,17 @@ hist_trigger_entry_print(struct seq_file *m,seq_puts (m," " );seq_puts (m,"}" ); +} + +static void hist_trigger_entry_print (struct seq_file *m, +struct hist_trigger_data *hist_data, +void *key, +struct tracing_map_elt *elt) +{ +const char *field_name; +unsigned int i; + +hist_trigger_print_key (m, hist_data, key, elt);seq_printf (m," hitcount: %10llu" ,tracing_map_read_sum (elt,HITCOUNT_IDX ));Signature · 1 line
2.14.1
Signature · 1 line
Masami Hiramatsu <[email protected]>
Re: [PATCH v6 07/15] tracing: Move hist trigger key printing into a separate function
Hi Masami,
Quoted 7 lines · Masami Hiramatsu
Hi Tom,
Quoted 2 lines · On Thu, 11 Oct 2018 16:02:04 -0500 Tom Zanussi <[email protected]> wrote:
From: Tom Zanussi <[email protected]>
Quoted 8 lines
Quoted 3 lines
Future patches will want to print a histogram key outside a histogram
- add and usehist_trigger_print_key()for that purpose.Hmm, I think this change should be done with such user code, because without
the user code I can not decide it is good or not.
OK, will move it into the following patch, 'tracing: Add hist trigger snapshot() action'.
Thanks,
Tom
PATCH v6 8/15 tracing: Add hist trigger snapshot() action
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
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().
--- kernel/trace/trace.c | 1 + kernel/trace/trace_events_hist.c | 290 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 283 insertions(+), 8 deletions(-)
kernel/trace/trace.c +1 -0
@@ -4880,6 +4880,7 @@ static const char readme_msg[] ="\t The available actions are:\n\n" "\t <synthetic_event>(param list) - generate synthetic event\n" "\t save(field,...) - save current event fields\n" + "\t snapshot() - snapshot the trace buffer\n"#endif ;
kernel/trace/trace_events_hist.c +282 -8
398 lines not on this page · raw message
Signature · 1 line
2.14.1
PATCH v6 9/15 tracing: Add hist trigger snapshot() action Documentation
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
Add Documentation for the hist:handlerXXX($var).snapshot() action.
--- Documentation/trace/histogram.rst | 110 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+)
Documentation/trace/histogram.rst +110 -0
@@ -1874,6 +1874,7 @@ The available actions are: - <synthetic_event_name>(param list) - generate synthetic event - save(field,...) - save current event fields + - snapshot() - snapshot the trace buffer The following commonly-used handler.action pairs are available:
@@ -2030,6 +2031,115 @@ The following commonly-used handler.action pairs are available: Entries: 2 Dropped: 0 + - onmax(var).snapshot() + + The 'onmax(var).snapshot()' hist trigger action is invoked + whenever the value of 'var' associated with a histogram entry + exceeds the current maximum contained in that variable. + + The end result is that a global snapshot of the trace buffer will + be saved in the tracing/snapshot file if 'var' exceeds the current + maximum for any hist trigger entry. + + Note that in this case the maximum is a global maximum for the + current trace instance, which is the maximum across all buckets of + the histogram. The key of the specific trace event that caused + the global maximum and the global maximum itself are displayed, + along with a message stating that a snapshot has been taken and + where to find it. The user can use the key information displayed + to locate the corresponding bucket in the histogram for even more + detail. + + As an example the below defines a couple of hist triggers, one for + sched_waking and another for sched_switch, keyed on pid. Whenever + a sched_waking event occurs, the timestamp is saved in the entry + corresponding to the current pid, and when the scheduler switches + back to that pid, the timestamp difference is calculated. If the + resulting latency, stored in wakeup_lat, exceeds the current + maximum latency, a snapshot is taken. As part of the setup, all + the scheduler events are also enabled, which are the events that + will show up in the snapshot when it is taken at some point: + + # echo 1 > /sys/kernel/debug/tracing/events/sched/enable + + # echo 'hist:keys=pid:ts0=common_timestamp.usecs \ + if comm=="cyclictest"' >> \ + /sys/kernel/debug/tracing/events/sched/sched_waking/trigger + + # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0: \ + onmax($wakeup_lat).save(next_prio,next_comm,prev_pid,prev_prio, \ + prev_comm):onmax($wakeup_lat).snapshot() \ + if next_comm=="cyclictest"' >> \ + /sys/kernel/debug/tracing/events/sched/sched_switch/trigger + + When the histogram is displayed, for each bucket the max value + and the saved values corresponding to the max are displayed + following the rest of the fields. + + If a snaphot was taken, there is also a message indicating that, + along with the value and event that triggered the global maximum: + + # cat /sys/kernel/debug/tracing/events/sched/sched_switch/hist + { next_pid: 2101 } hitcount: 200 + max: 52 next_prio: 120 next_comm: cyclictest \ + prev_pid: 0 prev_prio: 120 prev_comm: swapper/6 + + { next_pid: 2103 } hitcount: 1326 + max: 572 next_prio: 19 next_comm: cyclictest \ + prev_pid: 0 prev_prio: 120 prev_comm: swapper/1 + + { next_pid: 2102 } hitcount: 1982 \ + max: 74 next_prio: 19 next_comm: cyclictest \ + prev_pid: 0 prev_prio: 120 prev_comm: swapper/5 + + Snapshot taken (see tracing/snapshot). Details: + triggering value { onmax($wakeup_lat) }: 572 \ + triggered by event with key: { next_pid: 2103 } + + Totals: + Hits: 3508 + Entries: 3 + Dropped: 0 + + In the above case, the event that triggered the global maximum has + the key with next_pid == 2103. If you look at the bucket that has + 2103 as the key, you'll find the additional values save()'d along + with the local maximum for that bucket, which should be the same + as the global maximum (since that was the same value that + triggered the global snapshot). + + And finally, looking at the snapshot data should show at or near + the end the event that triggered the snapshot (in this case you + can verify the timestamps between the sched_waking and + sched_switch events, which should match the time displayed in the + global maximum): + + # cat /sys/kernel/debug/tracing/snapshot + + <...>-2103 [005] d..3 309.873125: sched_switch: prev_comm=cyclictest prev_pid=2103 prev_prio=19 prev_state=D ==> next_comm=swapper/5 next_pid=0 next_prio=120 + <idle>-0 [005] d.h3 309.873611: sched_waking: comm=cyclictest pid=2102 prio=19 target_cpu=005 + <idle>-0 [005] dNh4 309.873613: sched_wakeup: comm=cyclictest pid=2102 prio=19 target_cpu=005 + <idle>-0 [005] d..3 309.873616: sched_switch: prev_comm=swapper/5 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=cyclictest next_pid=2102 next_prio=19 + <...>-2102 [005] d..3 309.873625: sched_switch: prev_comm=cyclictest prev_pid=2102 prev_prio=19 prev_state=D ==> next_comm=swapper/5 next_pid=0 next_prio=120 + <idle>-0 [005] d.h3 309.874624: sched_waking: comm=cyclictest pid=2102 prio=19 target_cpu=005 + <idle>-0 [005] dNh4 309.874626: sched_wakeup: comm=cyclictest pid=2102 prio=19 target_cpu=005 + <idle>-0 [005] dNh3 309.874628: sched_waking: comm=cyclictest pid=2103 prio=19 target_cpu=005 + <idle>-0 [005] dNh4 309.874630: sched_wakeup: comm=cyclictest pid=2103 prio=19 target_cpu=005 + <idle>-0 [005] d..3 309.874633: sched_switch: prev_comm=swapper/5 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=cyclictest next_pid=2102 next_prio=19 + <idle>-0 [004] d.h3 309.874757: sched_waking: comm=gnome-terminal- pid=1699 prio=120 target_cpu=004 + <idle>-0 [004] dNh4 309.874762: sched_wakeup: comm=gnome-terminal- pid=1699 prio=120 target_cpu=004 + <idle>-0 [004] d..3 309.874766: sched_switch: prev_comm=swapper/4 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=gnome-terminal- next_pid=1699 next_prio=120 + gnome-terminal--1699 [004] d.h2 309.874941: sched_stat_runtime: comm=gnome-terminal- pid=1699 runtime=180706 [ns] vruntime=1126870572 [ns] + <idle>-0 [003] d.s4 309.874956: sched_waking: comm=rcu_sched pid=9 prio=120 target_cpu=007 + <idle>-0 [003] d.s5 309.874960: sched_wake_idle_without_ipi: cpu=7 + <idle>-0 [003] d.s5 309.874961: sched_wakeup: comm=rcu_sched pid=9 prio=120 target_cpu=007 + <idle>-0 [007] d..3 309.874963: sched_switch: prev_comm=swapper/7 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=rcu_sched next_pid=9 next_prio=120 + rcu_sched-9 [007] d..3 309.874973: sched_stat_runtime: comm=rcu_sched pid=9 runtime=13646 [ns] vruntime=22531430286 [ns] + rcu_sched-9 [007] d..3 309.874978: sched_switch: prev_comm=rcu_sched prev_pid=9 prev_prio=120 prev_state=R+ ==> next_comm=swapper/7 next_pid=0 next_prio=120 + <...>-2102 [005] d..4 309.874994: sched_migrate_task: comm=cyclictest pid=2103 prio=19 orig_cpu=5 dest_cpu=1 + <...>-2102 [005] d..4 309.875185: sched_wake_idle_without_ipi: cpu=1 + <idle>-0 [001] d..3 309.875200: sched_switch: prev_comm=swapper/1 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=cyclictest next_pid=2103 next_prio=19 + 3. User space creating a trigger --------------------------------
Signature · 1 line
2.14.1
PATCH v6 10/15 tracing: Add hist trigger snapshot() action test case
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
Add a test case verifying the basic functionality of the hist:snapshot() action.
--- .../inter-event/trigger-snapshot-action-hist.tc | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc new file +55 -0
@@ -0,0 +1,55 @@ +#!/bin/sh +# description: event trigger - test inter-event histogram trigger snapshot action + +do_reset() { + reset_trigger + echo > set_event + echo 0 > snapshot + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f snapshot ]; then + echo "snapshot is not supported" + exit_unsupported +fi + +grep "onchange(var)" README > /dev/null || exit_unsupported # version issue + +grep "snapshot()" README > /dev/null || exit_unsupported # version issue + +reset_tracer +do_reset + +echo "Test snapshot action" + +echo 1 > /sys/kernel/debug/tracing/events/sched/enable + +echo 'hist:keys=comm:newprio=prio:onchange($newprio).save(comm,prio):onchange($newprio).snapshot() if comm=="ping"' >> /sys/kernel/debug/tracing/events/sched/sched_waking/trigger + +ping localhost -c 3 +nice -n 1 ping localhost -c 3 + +echo 0 > /sys/kernel/debug/tracing/events/sched/enable + +if ! grep -q "changed:" events/sched/sched_waking/hist; then + fail "Failed to create onchange action inter-event histogram" +fi + +if ! grep -q "comm=ping" snapshot; then + fail "Failed to create snapshot action inter-event histogram" +fi + +do_reset + +exit 0
Signature · 1 line
2.14.1
Masami Hiramatsu
maintainerRe: [PATCH v6 10/15] tracing: Add hist trigger snapshot() action test case
Quoted 5 lines · On Thu, 11 Oct 2018 16:02:07 -0500 Tom Zanussi <[email protected]> wrote:
From: Tom Zanussi <[email protected]>
Add a test case verifying the basic functionality of the hist:snapshot() action.
I think this is OK for current tracing tree, but for next kernel version you may need to update it (against the kselftest tree)
Quoted 29 lines
Signed-off-by Tom Zanussi <[email protected]>--- .../inter-event/trigger-snapshot-action-hist.tc | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tctools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc new file +17
-0@@ -0,0 +1,55 @@ +#!/bin/sh +# description: event trigger - test inter-event histogram trigger snapshot action + +do_reset() { + reset_trigger + echo > set_event + echo 0 > snapshot + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc line 27
Quoted 10 lines
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc new file +10
-0+ echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f snapshot ]; then + echo "snapshot is not supported" + exit_unsupported +fi + +grep "onchange(var)" README > /dev/null || exit_unsupported # version issue
grep -q will be better.
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc line 29
Quoted 2 lines
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc new file +2
-0+ +grep "snapshot()" README > /dev/null || exit_unsupported # version issue
Ditto.
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc line 32
Quoted 3 lines
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc new file +3
-0+ +reset_tracer +do_reset
Depends on the merge timing, but I already moved this kind of "reset before/after test" into initialize_ftrace(), so you don't need do_reset() here. It is required only if you reset tracer in between tests.
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc line 41
Quoted 9 lines
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc new file +9
-0+ +echo "Test snapshot action" + +echo 1 > /sys/kernel/debug/tracing/events/sched/enable + +echo 'hist:keys=comm:newprio=prio:onchange($newprio).save(comm,prio):onchange($newprio).snapshot() if comm=="ping"' >> /sys/kernel/debug/tracing/events/sched/sched_waking/trigger + +ping localhost -c 3 +nice -n 1 ping localhost -c 3
Ditto. please use $LOCALHOST if you send this to the latest tree.
http://lkml.kernel.org/r/153563862993.29700.6436770573173736555.stgit@devbox
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc line 53
Quoted 12 lines
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc new file +12
-0+ +echo 0 > /sys/kernel/debug/tracing/events/sched/enable + +if ! grep -q "changed:" events/sched/sched_waking/hist; then + fail "Failed to create onchange action inter-event histogram" +fi + +if ! grep -q "comm=ping" snapshot; then + fail "Failed to create snapshot action inter-event histogram" +fi + +do_reset
Also you don't need this.
BTW, are there no "expected fail" tests? (e.g. passing wrong snapshot command to trigger)
Thank you,
Quoted 5 lines
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc new file +2
-0+ +exit 0Signature · 1 line
2.14.1
Signature · 1 line
Masami Hiramatsu <[email protected]>
Re: [PATCH v6 10/15] tracing: Add hist trigger snapshot() action test case
Hi Masami,
Quoted 5 lines · Masami Hiramatsu
Quoted 2 lines · On Thu, 11 Oct 2018 16:02:07 -0500 Tom Zanussi <[email protected]> wrote:
From: Tom Zanussi <[email protected]>
Quoted 8 lines
Quoted 3 lines
Add a test case verifying the basic functionality of the hist:snapshot() action.
I think this is OK for current tracing tree, but for next kernel version
you may need to update it (against the kselftest tree)
OK.
Quoted 57 lines
Quoted 47 lines
Signed-off-by Tom Zanussi <[email protected]>--- .../inter-event/trigger-snapshot-action-hist.tc | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-snapshot-action-hist.tc(quoted diff) +0
-0event/trigger-snapshot-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter- event/trigger-snapshot-action-hist.tc
new file mode 100644
index 000000000000..f427be989296tools/testing/selftests/ftrace/test.d/trigger/inter- new file +0
-0event/trigger-snapshot-action-hist.tc
tools/testing/selftests/ftrace/test.d/trigger/inter- new file +2
-0@@ -0,0 +1,55 @@ +#!/bin/sh +# description: event trigger - test inter-event histogram triggersnapshot action
tools/testing/selftests/ftrace/test.d/trigger/inter- new file +25
-0+ +do_reset() { + reset_trigger + echo > set_event + echo 0 > snapshot + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f snapshot ]; then + echo "snapshot is not supported" + exit_unsupported +fi + +grep "onchange(var)" README > /dev/null || exit_unsupported #Quoted 1 line
version issue
grep -q will be better.
Quoted 3 lines
tools/testing/selftests/ftrace/test.d/trigger/inter- new file +2
-0+ +grep "snapshot()" README > /dev/null || exit_unsupported # versionissue
Ditto.
Quoted 9 lines
tools/testing/selftests/ftrace/test.d/trigger/inter-
Quoted 3 lines
tools/testing/selftests/ftrace/test.d/trigger/inter- new file +3
-0+ +reset_tracer +do_resetDepends on the merge timing, but I already moved this kind of "reset before/after test" into
initialize_ftrace(), so you don't needdo_reset()
here. It is required only if you reset tracer in between tests.
OK, good to know, thanks. At this point it probably will be the next kernel version, so will make all the suggested changes for that version.
Quoted 15 lines
tools/testing/selftests/ftrace/test.d/trigger/inter-
Quoted 12 lines
tools/testing/selftests/ftrace/test.d/trigger/inter- new file +6
-0+ +echo "Test snapshot action" + +echo 1 > /sys/kernel/debug/tracing/events/sched/enable + +echo'hist:keys=comm:newprio=prio:onchange($newprio).save(comm,prio):onc hange($newprio).snapshot() if comm=="ping"' >>
/sys/kernel/debug/tracing/events/sched/sched_waking/triggertools/testing/selftests/ftrace/test.d/trigger/inter- new file +3
-0+ +ping localhost -c 3 +nice -n 1 ping localhost -c 3Ditto. please use $LOCALHOST if you send this to the latest tree.
Quoted 3 lines
http://lkml.kernel.org/r/153563862993.29700.6436770573173736555.stgit
@devbox
OK, thanks for pointing that out.
Quoted 16 lines
tools/testing/selftests/ftrace/test.d/trigger/inter-
Quoted 12 lines
tools/testing/selftests/ftrace/test.d/trigger/inter- new file +12
-0+ +echo 0 > /sys/kernel/debug/tracing/events/sched/enable + +if ! grep -q "changed:" events/sched/sched_waking/hist; then + fail "Failed to create onchange action inter-event histogram" +fi + +if ! grep -q "comm=ping" snapshot; then + fail "Failed to create snapshot action inter-event histogram" +fi + +do_resetAlso you don't need this.
Quoted 3 lines
BTW, are there no "expected fail" tests? (e.g. passing wrong snapshot command to trigger)
Good point, will add an expected fail for snapshot and not onmax/onchange.
Thanks,
Tom
Quoted 9 lines
Thank you,
Quoted 5 lines
tools/testing/selftests/ftrace/test.d/trigger/inter- new file +2
-0+ +exit 0Signature · 1 line
2.14.1
PATCH v6 11/15 tracing: Add hist trigger onchange() handler
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
Add support for a hist:onchange($var) handler, similar to the onmax() handler but triggering whenever there's any change in $var, not just a max.
--- kernel/trace/trace.c | 3 +- kernel/trace/trace_events_hist.c | 68 ++++++++++++++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 14 deletions(-)
kernel/trace/trace.c +2 -1
@@ -4876,7 +4876,8 @@ static const char readme_msg[] ="\t <handler>.<action>\n\n" "\t The available handlers are:\n\n" "\t onmatch(matching.event) - invoke on addition or update\n" -"\t onmax(var) - invoke if var exceeds current max\n\n" +"\t onmax(var) - invoke if var exceeds current max\n" +"\t onchange(var) - invoke action if var changes\n\n" "\t The available actions are:\n\n" "\t <synthetic_event>(param list) - generate synthetic event\n" "\t save(field,...) - save current event fields\n"
kernel/trace/trace_events_hist.c +55 -13
182 lines not on this page · raw message
Signature · 1 line
2.14.1
PATCH v6 12/15 tracing: Add hist trigger onchange() handler Documentation
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
Add Documentation for the hist:onchange($var) handler.
--- Documentation/trace/histogram.rst | 98 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+)
Documentation/trace/histogram.rst +98 -0
@@ -1869,6 +1869,7 @@ The available handlers are: - onmatch(matching.event) - invoke action on any addition or update - onmax(var) - invoke action if var exceeds current max + - onchange(var) - invoke action if var changes The available actions are:
@@ -2140,6 +2141,103 @@ The following commonly-used handler.action pairs are available: <...>-2102 [005] d..4 309.875185: sched_wake_idle_without_ipi: cpu=1 <idle>-0 [001] d..3 309.875200: sched_switch: prev_comm=swapper/1 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=cyclictest next_pid=2103 next_prio=19 + - onchange(var).save(field,.. .) + + The 'onchange(var).save(field,...)' hist trigger action is invoked + whenever the value of 'var' associated with a histogram entry + changes. + + The end result is that the trace event fields specified as the + onchange.save() params will be saved if 'var' changes for that + hist trigger entry. This allows context from the event that + changed the value to be saved for later reference. When the + histogram is displayed, additional fields displaying the saved + values will be printed. + + - onchange(var).snapshot() + + The 'onchange(var).snapshot()' hist trigger action is invoked + whenever the value of 'var' associated with a histogram entry + changes. + + The end result is that a global snapshot of the trace buffer will + be saved in the tracing/snapshot file if 'var' changes for any + hist trigger entry. + + Note that in this case the changed value is a global variable + associated withe current trace instance. The key of the specific + trace event that caused the value to change and the global value + itself are displayed, along with a message stating that a snapshot + has been taken and where to find it. The user can use the key + information displayed to locate the corresponding bucket in the + histogram for even more detail. + + As an example the below defines a hist trigger on the tcp_probe + event, keyed on dport. Whenever a tcp_probe event occurs, the + cwnd field is checked against the current value stored in the + $cwnd variable. If the value has changed, a snapshot is taken. + As part of the setup, all the scheduler and tcp events are also + enabled, which are the events that will show up in the snapshot + when it is taken at some point: + + # echo 1 > /sys/kernel/debug/tracing/events/sched/enable + # echo 1 > /sys/kernel/debug/tracing/events/tcp/enable + + # echo 'hist:keys=dport:cwnd=snd_cwnd: \ + onchange($cwnd).save(snd_wnd,srtt,rcv_wnd): \ + onchange($cwnd).snapshot()' >> \ + /sys/kernel/debug/tracing/events/tcp/tcp_probe/trigger + + When the histogram is displayed, for each bucket the tracked value + and the saved values corresponding to that value are displayed + following the rest of the fields. + + If a snaphot was taken, there is also a message indicating that, + along with the value and event that triggered the snapshot: + + # cat /sys/kernel/debug/tracing/events/tcp/tcp_probe/hist + { dport: 1521 } hitcount: 8 + changed: 10 snd_wnd: 35456 srtt: 154262 rcv_wnd: 42112 + + { dport: 80 } hitcount: 23 + changed: 10 snd_wnd: 28960 srtt: 19604 rcv_wnd: 29312 + + { dport: 9001 } hitcount: 172 + changed: 10 snd_wnd: 48384 srtt: 260444 rcv_wnd: 55168 + + { dport: 443 } hitcount: 211 + changed: 10 snd_wnd: 26960 srtt: 17379 rcv_wnd: 28800 + + Snapshot taken (see tracing/snapshot). Details: + triggering value { onchange($cwnd) }: 10 + triggered by event with key: { dport: 80 } + + Totals: + Hits: 414 + Entries: 4 + Dropped: 0 + + In the above case, the event that triggered the snapshot has the + key with dport == 80. If you look at the bucket that has 80 as + the key, you'll find the additional values save()'d along with the + changed value for that bucket, which should be the same as the + global changed value (since that was the same value that triggered + the global snapshot). + + And finally, looking at the snapshot data should show at or near + the end the event that triggered the snapshot: + + # cat /sys/kernel/debug/tracing/snapshot + + gnome-shell-1261 [006] dN.3 49.823113: sched_stat_runtime: comm=gnome-shell pid=1261 runtime=49347 [ns] vruntime=1835730389 [ns] + kworker/u16:4-773 [003] d..3 49.823114: sched_switch: prev_comm=kworker/u16:4 prev_pid=773 prev_prio=120 prev_state=R+ ==> next_comm=kworker/3:2 next_pid=135 next_prio=120 + gnome-shell-1261 [006] d..3 49.823114: sched_switch: prev_comm=gnome-shell prev_pid=1261 prev_prio=120 prev_state=R+ ==> next_comm=kworker/6:2 next_pid=387 next_prio=120 + kworker/3:2-135 [003] d..3 49.823118: sched_stat_runtime: comm=kworker/3:2 pid=135 runtime=5339 [ns] vruntime=17815800388 [ns] + kworker/6:2-387 [006] d..3 49.823120: sched_stat_runtime: comm=kworker/6:2 pid=387 runtime=9594 [ns] vruntime=14589605367 [ns] + kworker/6:2-387 [006] d..3 49.823122: sched_switch: prev_comm=kworker/6:2 prev_pid=387 prev_prio=120 prev_state=R+ ==> next_comm=gnome-shell next_pid=1261 next_prio=120 + kworker/3:2-135 [003] d..3 49.823123: sched_switch: prev_comm=kworker/3:2 prev_pid=135 prev_prio=120 prev_state=T ==> next_comm=swapper/3 next_pid=0 next_prio=120 + <idle>-0 [004] ..s7 49.823798: tcp_probe: src=10.0.0.10:54326 dest=23.215.104.193:80 mark=0x0 length=32 snd_nxt=0xe3ae2ff5 snd_una=0xe3ae2ecd snd_cwnd=10 ssthresh=2147483647 snd_wnd=28960 srtt=19604 rcv_wnd=29312 + 3. User space creating a trigger --------------------------------
Signature · 1 line
2.14.1
PATCH v6 13/15 tracing: Add hist trigger onchange() handler test case
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
Add a test case verifying the basic functionality of the hist:onchange($var) handler.
--- .../inter-event/trigger-onchange-action-hist.tc | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onchange-action-hist.tc
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onchange-action-hist.tc new file +39 -0
@@ -0,0 +1,39 @@ +#!/bin/sh +# description: event trigger - test inter-event histogram trigger onchange action + +do_reset() { + reset_trigger + echo > set_event + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +grep "onchange(var)" README > /dev/null || exit_unsupported # version issue + +reset_tracer +do_reset + +echo "Test onchange action" + +echo 'hist:keys=comm:newprio=prio:onchange($newprio).save(comm,prio) if comm=="ping"' >> /sys/kernel/debug/tracing/events/sched/sched_waking/trigger + +ping localhost -c 3 +nice -n 1 ping localhost -c 3 + +if ! grep -q "changed:" events/sched/sched_waking/hist; then + fail "Failed to create onchange action inter-event histogram" +fi + +do_reset + +exit 0
Signature · 1 line
2.14.1
PATCH v6 14/15 tracing: Add alternative synthetic event trace action syntax
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
Add a 'trace(synthetic_event_name, params)' alternative to synthetic_event_name(params).
Currently, the syntax used for generating synthetic events is to invoke synthetic_event_name(params) i.e. use the synthetic event name as a function call.
Users requested a new form that more explicitly shows that the synthetic event is in effect being traced. In this version, a new 'trace()' keyword is used, and the synthetic event name is passed in as the first argument.
--- Documentation/trace/histogram.rst | 21 ++++++++++++++++++++ kernel/trace/trace.c | 1 + kernel/trace/trace_events_hist.c | 42 +++++++++++++++++++++++++++++++++++---- 3 files changed, 60 insertions(+), 4 deletions(-)
Documentation/trace/histogram.rst +21 -0
@@ -1874,6 +1874,7 @@ The available handlers are: The available actions are: - <synthetic_event_name>(param list) - generate synthetic event + - trace(<synthetic_event_name>,(param list)) - generate synthetic event - save(field,...) - save current event fields - snapshot() - snapshot the trace buffer
@@ -1881,6 +1882,10 @@ The following commonly-used handler.action pairs are available: - onmatch(matching.event).<synthetic_event_name>(param list) + or + + - onmatch(matching.event).trace(<synthetic_event_name>,(param list)) + The 'onmatch(matching.event).<synthetic_event_name>(params)' hist trigger action is invoked whenever an event matches and the histogram entry would be added or updated. It causes the named
@@ -1889,6 +1894,16 @@ The following commonly-used handler.action pairs are available: that consists of the values contained in those variables at the time the invoking event was hit. + There are two equivalent forms available for generating synthetic + events. In the first form, the synthetic event name is used as if + it were a function name. For example, if the synthetic event name + is 'wakeup_latency', the wakeup_latency event would be generated + by invoking it as if it were a function call, with the event field + values passed in as arguments: wakeup_latency(arg1,arg2). The + second form simply uses the 'trace' keyword as the function name + and passes in the synthetic event name as the first argument, + followed by the field values: trace(wakeup_latency,arg1,arg2). + The 'param list' consists of one or more parameters which may be either variables or fields defined on either the 'matching.event' or the target event. The variables or fields specified in the
@@ -1928,6 +1943,12 @@ The following commonly-used handler.action pairs are available: wakeup_new_test($testpid) if comm=="cyclictest"' >> \ /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/trigger + Or, equivalently, using the 'trace' keyword syntax: + + # echo 'hist:keys=$testpid:testpid=pid:onmatch(sched.sched_wakeup_new).\ + trace(wakeup_new_test,$testpid) if comm=="cyclictest"' >> \ + /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/trigger + Creating and displaying a histogram based on those events is now just a matter of using the fields and new synthetic event in the tracing/events/synthetic directory, as usual::
kernel/trace/trace.c +1 -0
@@ -4880,6 +4880,7 @@ static const char readme_msg[] ="\t onchange(var) - invoke action if var changes\n\n" "\t The available actions are:\n\n" "\t <synthetic_event>(param list) - generate synthetic event\n" +"\t trace(<synthetic_event>,(param list))- generate synthetic event\n" "\t save(field,...) - save current event fields\n" "\t snapshot() - snapshot the trace buffer\n"#endif
kernel/trace/trace_events_hist.c +38 -4
102 lines not on this page · raw message
Signature · 1 line
2.14.1
PATCH v6 15/15 tracing: Add alternative synthetic event trace action test case
In reply to Tom ZanussiFrom: Tom Zanussi <[email protected]>
Add a test case for the alternative trace(<synthetic_event, params) synthetic event generation syntax.
--- .../inter-event/trigger-trace-action-hist.tc | 52 ++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-trace-action-hist.tc
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-trace-action-hist.tc new file +52 -0
@@ -0,0 +1,52 @@ +#!/bin/sh +# description: event trigger - test inter-event histogram trigger trace action + +do_reset() { + reset_trigger + echo > set_event + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f synthetic_events ]; then + echo "synthetic event is not supported" + exit_unsupported +fi + +grep "trace(<synthetic_event>" README > /dev/null || exit_unsupported # version issue + +clear_synthetic_events +reset_tracer +do_reset + +echo "Test create synthetic event" + +echo 'wakeup_latency u64 lat pid_t pid char comm[16]' > synthetic_events +if [ ! -d events/synthetic/wakeup_latency ]; then + fail "Failed to create wakeup_latency synthetic event" +fi + +echo "Test create histogram for synthetic event using trace action" +echo "Test histogram variables,simple expression support and trace action" + +echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_wakeup/trigger +echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_wakeup).trace(wakeup_latency,$wakeup_lat,next_pid,next_comm) if next_comm=="ping"' > events/sched/sched_switch/trigger +echo 'hist:keys=comm,pid,lat:wakeup_lat=lat:sort=lat' > events/synthetic/wakeup_latency/trigger +ping localhost -c 5 +if ! grep -q "ping" events/synthetic/wakeup_latency/hist; then + fail "Failed to create trace action inter-event histogram" +fi + +do_reset + +exit 0
Signature · 1 line
2.14.1