Commit 83e99914 authored by Tom Zanussi's avatar Tom Zanussi Committed by Steven Rostedt

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.comSigned-off-by: default avatarTom Zanussi <tom.zanussi@linux.intel.com>
Tested-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Reviewed-by: default avatarNamhyung Kim <namhyung@kernel.org>
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent e62347d2
...@@ -3837,6 +3837,7 @@ static const char readme_msg[] = ...@@ -3837,6 +3837,7 @@ static const char readme_msg[] =
"\t [:values=<field1[,field2,...]>]\n" "\t [:values=<field1[,field2,...]>]\n"
"\t [:sort=<field1[,field2,...]>]\n" "\t [:sort=<field1[,field2,...]>]\n"
"\t [:size=#entries]\n" "\t [:size=#entries]\n"
"\t [:pause][:continue]\n"
"\t [if <filter>]\n\n" "\t [if <filter>]\n\n"
"\t When a matching event is hit, an entry is added to a hash\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" "\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[] = ...@@ -3851,7 +3852,11 @@ static const char readme_msg[] =
"\t used to specify more or fewer than the default 2048 entries\n" "\t used to specify more or fewer than the default 2048 entries\n"
"\t for the hashtable size.\n\n" "\t for the hashtable size.\n\n"
"\t Reading the 'hist' file for the event will dump the hash\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 #endif
; ;
......
...@@ -86,6 +86,8 @@ struct hist_trigger_attrs { ...@@ -86,6 +86,8 @@ struct hist_trigger_attrs {
char *keys_str; char *keys_str;
char *vals_str; char *vals_str;
char *sort_key_str; char *sort_key_str;
bool pause;
bool cont;
unsigned int map_bits; unsigned int map_bits;
}; };
...@@ -193,6 +195,11 @@ static struct hist_trigger_attrs *parse_hist_trigger_attrs(char *trigger_str) ...@@ -193,6 +195,11 @@ static struct hist_trigger_attrs *parse_hist_trigger_attrs(char *trigger_str)
attrs->vals_str = kstrdup(str, GFP_KERNEL); attrs->vals_str = kstrdup(str, GFP_KERNEL);
else if (strncmp(str, "sort=", strlen("sort=")) == 0) else if (strncmp(str, "sort=", strlen("sort=")) == 0)
attrs->sort_key_str = kstrdup(str, GFP_KERNEL); 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) { else if (strncmp(str, "size=", strlen("size=")) == 0) {
int map_bits = parse_map_size(str); int map_bits = parse_map_size(str);
...@@ -871,7 +878,10 @@ static int event_hist_trigger_print(struct seq_file *m, ...@@ -871,7 +878,10 @@ static int event_hist_trigger_print(struct seq_file *m,
if (data->filter_str) if (data->filter_str)
seq_printf(m, " if %s", data->filter_str); seq_printf(m, " if %s", data->filter_str);
seq_puts(m, " [active]"); if (data->paused)
seq_puts(m, " [paused]");
else
seq_puts(m, " [active]");
seq_putc(m, '\n'); seq_putc(m, '\n');
...@@ -910,16 +920,30 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops, ...@@ -910,16 +920,30 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
struct event_trigger_data *data, struct event_trigger_data *data,
struct trace_event_file *file) struct trace_event_file *file)
{ {
struct hist_trigger_data *hist_data = data->private_data;
struct event_trigger_data *test; struct event_trigger_data *test;
int ret = 0; int ret = 0;
list_for_each_entry_rcu(test, &file->triggers, list) { list_for_each_entry_rcu(test, &file->triggers, list) {
if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) { if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
ret = -EEXIST; if (hist_data->attrs->pause)
test->paused = true;
else if (hist_data->attrs->cont)
test->paused = false;
else
ret = -EEXIST;
goto out; goto out;
} }
} }
if (hist_data->attrs->cont) {
ret = -ENOENT;
goto out;
}
if (hist_data->attrs->pause)
data->paused = true;
if (data->ops->init) { if (data->ops->init) {
ret = data->ops->init(data->ops, data); ret = data->ops->init(data->ops, data);
if (ret < 0) if (ret < 0)
...@@ -1011,7 +1035,8 @@ static int event_hist_trigger_func(struct event_command *cmd_ops, ...@@ -1011,7 +1035,8 @@ static int event_hist_trigger_func(struct event_command *cmd_ops,
* triggers registered a failure too. * triggers registered a failure too.
*/ */
if (!ret) { if (!ret) {
ret = -ENOENT; if (!(attrs->pause || attrs->cont))
ret = -ENOENT;
goto out_free; goto out_free;
} else if (ret < 0) } else if (ret < 0)
goto out_free; goto out_free;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment