tracing: Add hist trigger support for pausing and continuing a trace

Allow users to append 'pause' or 'continue' to an existing trigger in
order to have it paused or to have a paused trace continue.

This expands the hist trigger syntax from this:
    # echo hist:keys=xxx:vals=yyy:sort=zzz.descending \
          [ if filter] >> event/trigger

to this:

    # echo hist:keys=xxx:vals=yyy:sort=zzz.descending:pause or cont \
          [ if filter] >> event/trigger

Link: http://lkml.kernel.org/r/b672a92c14702cb924cdf6fc27ea1809bed04907.1457029949.git.tom.zanussi@linux.intel.com

Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Tested-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Reviewed-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
Tom Zanussi 2016-03-03 12:54:46 -06:00 committed by Steven Rostedt
parent e62347d245
commit 83e99914c9
2 changed files with 34 additions and 4 deletions

View File

@ -3837,6 +3837,7 @@ static const char readme_msg[] =
"\t [:values=<field1[,field2,...]>]\n"
"\t [:sort=<field1[,field2,...]>]\n"
"\t [:size=#entries]\n"
"\t [:pause][:continue]\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"
@ -3851,7 +3852,11 @@ static const char readme_msg[] =
"\t used to specify more or fewer than the default 2048 entries\n"
"\t for the hashtable size.\n\n"
"\t Reading the 'hist' file for the event will dump the hash\n"
"\t table in its entirety to stdout."
"\t table in its entirety to stdout.\n\n"
"\t The 'pause' parameter can be used to pause an existing hist\n"
"\t trigger or to start a hist trigger but not log any events\n"
"\t until told to do so. 'continue' can be used to start or\n"
"\t restart a paused hist trigger.\n\n"
#endif
;

View File

@ -86,6 +86,8 @@ struct hist_trigger_attrs {
char *keys_str;
char *vals_str;
char *sort_key_str;
bool pause;
bool cont;
unsigned int map_bits;
};
@ -193,6 +195,11 @@ static struct hist_trigger_attrs *parse_hist_trigger_attrs(char *trigger_str)
attrs->vals_str = kstrdup(str, GFP_KERNEL);
else if (strncmp(str, "sort=", strlen("sort=")) == 0)
attrs->sort_key_str = kstrdup(str, GFP_KERNEL);
else if (strcmp(str, "pause") == 0)
attrs->pause = true;
else if ((strcmp(str, "cont") == 0) ||
(strcmp(str, "continue") == 0))
attrs->cont = true;
else if (strncmp(str, "size=", strlen("size=")) == 0) {
int map_bits = parse_map_size(str);
@ -871,6 +878,9 @@ static int event_hist_trigger_print(struct seq_file *m,
if (data->filter_str)
seq_printf(m, " if %s", data->filter_str);
if (data->paused)
seq_puts(m, " [paused]");
else
seq_puts(m, " [active]");
seq_putc(m, '\n');
@ -910,16 +920,30 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
struct event_trigger_data *data,
struct trace_event_file *file)
{
struct hist_trigger_data *hist_data = data->private_data;
struct event_trigger_data *test;
int ret = 0;
list_for_each_entry_rcu(test, &file->triggers, list) {
if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
if (hist_data->attrs->pause)
test->paused = true;
else if (hist_data->attrs->cont)
test->paused = false;
else
ret = -EEXIST;
goto out;
}
}
if (hist_data->attrs->cont) {
ret = -ENOENT;
goto out;
}
if (hist_data->attrs->pause)
data->paused = true;
if (data->ops->init) {
ret = data->ops->init(data->ops, data);
if (ret < 0)
@ -1011,6 +1035,7 @@ static int event_hist_trigger_func(struct event_command *cmd_ops,
* triggers registered a failure too.
*/
if (!ret) {
if (!(attrs->pause || attrs->cont))
ret = -ENOENT;
goto out_free;
} else if (ret < 0)