Browse Source

tracing: Add hist trigger support for clearing a trace

Allow users to append 'clear' to an existing trigger in order to have
the hash table cleared.

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

to this:

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

Link: http://lkml.kernel.org/r/ae15dd0d9b2f7af07a37c1ff682063e2dbcdf160.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>
Tom Zanussi 9 years ago
parent
commit
e86ae9baac
2 changed files with 26 additions and 3 deletions
  1. 4 1
      kernel/trace/trace.c
  2. 22 2
      kernel/trace/trace_events_hist.c

+ 4 - 1
kernel/trace/trace.c

@@ -3837,7 +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            [:pause][:continue][:clear]\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"
@@ -3857,6 +3857,9 @@ static const char readme_msg[] =
 	"\t    trigger or to start a hist trigger but not log any events\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    until told to do so.  'continue' can be used to start or\n"
 	"\t    restart a paused hist trigger.\n\n"
 	"\t    restart a paused hist trigger.\n\n"
+	"\t    The 'clear' parameter will clear the contents of a running\n"
+	"\t    hist trigger and leave its current paused/active state\n"
+	"\t    unchanged.\n\n"
 #endif
 #endif
 ;
 ;
 
 

+ 22 - 2
kernel/trace/trace_events_hist.c

@@ -88,6 +88,7 @@ struct hist_trigger_attrs {
 	char		*sort_key_str;
 	char		*sort_key_str;
 	bool		pause;
 	bool		pause;
 	bool		cont;
 	bool		cont;
+	bool		clear;
 	unsigned int	map_bits;
 	unsigned int	map_bits;
 };
 };
 
 
@@ -200,6 +201,8 @@ static struct hist_trigger_attrs *parse_hist_trigger_attrs(char *trigger_str)
 		else if ((strcmp(str, "cont") == 0) ||
 		else if ((strcmp(str, "cont") == 0) ||
 			 (strcmp(str, "continue") == 0))
 			 (strcmp(str, "continue") == 0))
 			attrs->cont = true;
 			attrs->cont = true;
+		else if (strcmp(str, "clear") == 0)
+			attrs->clear = 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);
 
 
@@ -916,6 +919,21 @@ static struct event_trigger_ops *event_hist_get_trigger_ops(char *cmd,
 	return &event_hist_trigger_ops;
 	return &event_hist_trigger_ops;
 }
 }
 
 
+static void hist_clear(struct event_trigger_data *data)
+{
+	struct hist_trigger_data *hist_data = data->private_data;
+	bool paused;
+
+	paused = data->paused;
+	data->paused = true;
+
+	synchronize_sched();
+
+	tracing_map_clear(hist_data->map);
+
+	data->paused = paused;
+}
+
 static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
 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)
@@ -930,13 +948,15 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
 				test->paused = true;
 				test->paused = true;
 			else if (hist_data->attrs->cont)
 			else if (hist_data->attrs->cont)
 				test->paused = false;
 				test->paused = false;
+			else if (hist_data->attrs->clear)
+				hist_clear(test);
 			else
 			else
 				ret = -EEXIST;
 				ret = -EEXIST;
 			goto out;
 			goto out;
 		}
 		}
 	}
 	}
 
 
-	if (hist_data->attrs->cont) {
+	if (hist_data->attrs->cont || hist_data->attrs->clear) {
 		ret = -ENOENT;
 		ret = -ENOENT;
 		goto out;
 		goto out;
 	}
 	}
@@ -1035,7 +1055,7 @@ 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) {
-		if (!(attrs->pause || attrs->cont))
+		if (!(attrs->pause || attrs->cont || attrs->clear))
 			ret = -ENOENT;
 			ret = -ENOENT;
 		goto out_free;
 		goto out_free;
 	} else if (ret < 0)
 	} else if (ret < 0)