Skip to content

Commit d0bad49

Browse files
tzanussirostedt
authored andcommitted
tracing: Add enable_hist/disable_hist triggers
Similar to enable_event/disable_event triggers, these triggers enable and disable the aggregation of events into maps rather than enabling and disabling their writing into the trace buffer. They can be used to automatically start and stop hist triggers based on a matching filter condition. If there's a paused hist trigger on system:event, the following would start it when the filter condition was hit: # echo enable_hist:system:event [ if filter] > event/trigger And the following would disable a running system:event hist trigger: # echo disable_hist:system:event [ if filter] > event/trigger See Documentation/trace/events.txt for real examples. Link: http://lkml.kernel.org/r/f812f086e52c8b7c8ad5443487375e03c96a601f.1457029949.git.tom.zanussi@linux.intel.com Signed-off-by: Tom Zanussi <[email protected]> Tested-by: Masami Hiramatsu <[email protected]> Reviewed-by: Namhyung Kim <[email protected]> Signed-off-by: Steven Rostedt <[email protected]>
1 parent 6a475cb commit d0bad49

File tree

5 files changed

+196
-31
lines changed

5 files changed

+196
-31
lines changed

include/linux/trace_events.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ enum event_trigger_type {
408408
ETT_STACKTRACE = (1 << 2),
409409
ETT_EVENT_ENABLE = (1 << 3),
410410
ETT_EVENT_HIST = (1 << 4),
411+
ETT_HIST_ENABLE = (1 << 5),
411412
};
412413

413414
extern int filter_match_preds(struct event_filter *filter, void *rec);

kernel/trace/trace.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3807,6 +3807,10 @@ static const char readme_msg[] =
38073807
"\t trigger: traceon, traceoff\n"
38083808
"\t enable_event:<system>:<event>\n"
38093809
"\t disable_event:<system>:<event>\n"
3810+
#ifdef CONFIG_HIST_TRIGGERS
3811+
"\t enable_hist:<system>:<event>\n"
3812+
"\t disable_hist:<system>:<event>\n"
3813+
#endif
38103814
#ifdef CONFIG_STACKTRACE
38113815
"\t\t stacktrace\n"
38123816
#endif
@@ -3867,6 +3871,10 @@ static const char readme_msg[] =
38673871
"\t The 'clear' parameter will clear the contents of a running\n"
38683872
"\t hist trigger and leave its current paused/active state\n"
38693873
"\t unchanged.\n\n"
3874+
"\t The enable_hist and disable_hist triggers can be used to\n"
3875+
"\t have one event conditionally start and stop another event's\n"
3876+
"\t already-attached hist trigger. The syntax is analagous to\n"
3877+
"\t the enable_event and disable_event triggers.\n"
38703878
#endif
38713879
;
38723880

kernel/trace/trace.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,8 +1166,10 @@ extern const struct file_operations event_hist_fops;
11661166

11671167
#ifdef CONFIG_HIST_TRIGGERS
11681168
extern int register_trigger_hist_cmd(void);
1169+
extern int register_trigger_hist_enable_disable_cmds(void);
11691170
#else
11701171
static inline int register_trigger_hist_cmd(void) { return 0; }
1172+
static inline int register_trigger_hist_enable_disable_cmds(void) { return 0; }
11711173
#endif
11721174

11731175
extern int register_trigger_cmds(void);
@@ -1185,6 +1187,34 @@ struct event_trigger_data {
11851187
struct list_head list;
11861188
};
11871189

1190+
/* Avoid typos */
1191+
#define ENABLE_EVENT_STR "enable_event"
1192+
#define DISABLE_EVENT_STR "disable_event"
1193+
#define ENABLE_HIST_STR "enable_hist"
1194+
#define DISABLE_HIST_STR "disable_hist"
1195+
1196+
struct enable_trigger_data {
1197+
struct trace_event_file *file;
1198+
bool enable;
1199+
bool hist;
1200+
};
1201+
1202+
extern int event_enable_trigger_print(struct seq_file *m,
1203+
struct event_trigger_ops *ops,
1204+
struct event_trigger_data *data);
1205+
extern void event_enable_trigger_free(struct event_trigger_ops *ops,
1206+
struct event_trigger_data *data);
1207+
extern int event_enable_trigger_func(struct event_command *cmd_ops,
1208+
struct trace_event_file *file,
1209+
char *glob, char *cmd, char *param);
1210+
extern int event_enable_register_trigger(char *glob,
1211+
struct event_trigger_ops *ops,
1212+
struct event_trigger_data *data,
1213+
struct trace_event_file *file);
1214+
extern void event_enable_unregister_trigger(char *glob,
1215+
struct event_trigger_ops *ops,
1216+
struct event_trigger_data *test,
1217+
struct trace_event_file *file);
11881218
extern void trigger_data_free(struct event_trigger_data *data);
11891219
extern int event_trigger_init(struct event_trigger_ops *ops,
11901220
struct event_trigger_data *data);
@@ -1198,6 +1228,8 @@ extern int set_trigger_filter(char *filter_str,
11981228
struct event_trigger_data *trigger_data,
11991229
struct trace_event_file *file);
12001230
extern int register_event_command(struct event_command *cmd);
1231+
extern int unregister_event_command(struct event_command *cmd);
1232+
extern int register_trigger_hist_enable_disable_cmds(void);
12011233

12021234
/**
12031235
* struct event_trigger_ops - callbacks for trace event triggers

kernel/trace/trace_events_hist.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,3 +1393,118 @@ __init int register_trigger_hist_cmd(void)
13931393

13941394
return ret;
13951395
}
1396+
1397+
static void
1398+
hist_enable_trigger(struct event_trigger_data *data, void *rec)
1399+
{
1400+
struct enable_trigger_data *enable_data = data->private_data;
1401+
struct event_trigger_data *test;
1402+
1403+
list_for_each_entry_rcu(test, &enable_data->file->triggers, list) {
1404+
if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
1405+
if (enable_data->enable)
1406+
test->paused = false;
1407+
else
1408+
test->paused = true;
1409+
break;
1410+
}
1411+
}
1412+
}
1413+
1414+
static void
1415+
hist_enable_count_trigger(struct event_trigger_data *data, void *rec)
1416+
{
1417+
if (!data->count)
1418+
return;
1419+
1420+
if (data->count != -1)
1421+
(data->count)--;
1422+
1423+
hist_enable_trigger(data, rec);
1424+
}
1425+
1426+
static struct event_trigger_ops hist_enable_trigger_ops = {
1427+
.func = hist_enable_trigger,
1428+
.print = event_enable_trigger_print,
1429+
.init = event_trigger_init,
1430+
.free = event_enable_trigger_free,
1431+
};
1432+
1433+
static struct event_trigger_ops hist_enable_count_trigger_ops = {
1434+
.func = hist_enable_count_trigger,
1435+
.print = event_enable_trigger_print,
1436+
.init = event_trigger_init,
1437+
.free = event_enable_trigger_free,
1438+
};
1439+
1440+
static struct event_trigger_ops hist_disable_trigger_ops = {
1441+
.func = hist_enable_trigger,
1442+
.print = event_enable_trigger_print,
1443+
.init = event_trigger_init,
1444+
.free = event_enable_trigger_free,
1445+
};
1446+
1447+
static struct event_trigger_ops hist_disable_count_trigger_ops = {
1448+
.func = hist_enable_count_trigger,
1449+
.print = event_enable_trigger_print,
1450+
.init = event_trigger_init,
1451+
.free = event_enable_trigger_free,
1452+
};
1453+
1454+
static struct event_trigger_ops *
1455+
hist_enable_get_trigger_ops(char *cmd, char *param)
1456+
{
1457+
struct event_trigger_ops *ops;
1458+
bool enable;
1459+
1460+
enable = (strcmp(cmd, ENABLE_HIST_STR) == 0);
1461+
1462+
if (enable)
1463+
ops = param ? &hist_enable_count_trigger_ops :
1464+
&hist_enable_trigger_ops;
1465+
else
1466+
ops = param ? &hist_disable_count_trigger_ops :
1467+
&hist_disable_trigger_ops;
1468+
1469+
return ops;
1470+
}
1471+
1472+
static struct event_command trigger_hist_enable_cmd = {
1473+
.name = ENABLE_HIST_STR,
1474+
.trigger_type = ETT_HIST_ENABLE,
1475+
.func = event_enable_trigger_func,
1476+
.reg = event_enable_register_trigger,
1477+
.unreg = event_enable_unregister_trigger,
1478+
.get_trigger_ops = hist_enable_get_trigger_ops,
1479+
.set_filter = set_trigger_filter,
1480+
};
1481+
1482+
static struct event_command trigger_hist_disable_cmd = {
1483+
.name = DISABLE_HIST_STR,
1484+
.trigger_type = ETT_HIST_ENABLE,
1485+
.func = event_enable_trigger_func,
1486+
.reg = event_enable_register_trigger,
1487+
.unreg = event_enable_unregister_trigger,
1488+
.get_trigger_ops = hist_enable_get_trigger_ops,
1489+
.set_filter = set_trigger_filter,
1490+
};
1491+
1492+
static __init void unregister_trigger_hist_enable_disable_cmds(void)
1493+
{
1494+
unregister_event_command(&trigger_hist_enable_cmd);
1495+
unregister_event_command(&trigger_hist_disable_cmd);
1496+
}
1497+
1498+
__init int register_trigger_hist_enable_disable_cmds(void)
1499+
{
1500+
int ret;
1501+
1502+
ret = register_event_command(&trigger_hist_enable_cmd);
1503+
if (WARN_ON(ret < 0))
1504+
return ret;
1505+
ret = register_event_command(&trigger_hist_disable_cmd);
1506+
if (WARN_ON(ret < 0))
1507+
unregister_trigger_hist_enable_disable_cmds();
1508+
1509+
return ret;
1510+
}

kernel/trace/trace_events_trigger.c

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ __init int register_event_command(struct event_command *cmd)
347347
* Currently we only unregister event commands from __init, so mark
348348
* this __init too.
349349
*/
350-
static __init int unregister_event_command(struct event_command *cmd)
350+
__init int unregister_event_command(struct event_command *cmd)
351351
{
352352
struct event_command *p, *n;
353353
int ret = -ENODEV;
@@ -1062,15 +1062,6 @@ static __init void unregister_trigger_traceon_traceoff_cmds(void)
10621062
unregister_event_command(&trigger_traceoff_cmd);
10631063
}
10641064

1065-
/* Avoid typos */
1066-
#define ENABLE_EVENT_STR "enable_event"
1067-
#define DISABLE_EVENT_STR "disable_event"
1068-
1069-
struct enable_trigger_data {
1070-
struct trace_event_file *file;
1071-
bool enable;
1072-
};
1073-
10741065
static void
10751066
event_enable_trigger(struct event_trigger_data *data, void *rec)
10761067
{
@@ -1100,14 +1091,16 @@ event_enable_count_trigger(struct event_trigger_data *data, void *rec)
11001091
event_enable_trigger(data, rec);
11011092
}
11021093

1103-
static int
1104-
event_enable_trigger_print(struct seq_file *m, struct event_trigger_ops *ops,
1105-
struct event_trigger_data *data)
1094+
int event_enable_trigger_print(struct seq_file *m,
1095+
struct event_trigger_ops *ops,
1096+
struct event_trigger_data *data)
11061097
{
11071098
struct enable_trigger_data *enable_data = data->private_data;
11081099

11091100
seq_printf(m, "%s:%s:%s",
1110-
enable_data->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
1101+
enable_data->hist ?
1102+
(enable_data->enable ? ENABLE_HIST_STR : DISABLE_HIST_STR) :
1103+
(enable_data->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR),
11111104
enable_data->file->event_call->class->system,
11121105
trace_event_name(enable_data->file->event_call));
11131106

@@ -1124,9 +1117,8 @@ event_enable_trigger_print(struct seq_file *m, struct event_trigger_ops *ops,
11241117
return 0;
11251118
}
11261119

1127-
static void
1128-
event_enable_trigger_free(struct event_trigger_ops *ops,
1129-
struct event_trigger_data *data)
1120+
void event_enable_trigger_free(struct event_trigger_ops *ops,
1121+
struct event_trigger_data *data)
11301122
{
11311123
struct enable_trigger_data *enable_data = data->private_data;
11321124

@@ -1171,10 +1163,9 @@ static struct event_trigger_ops event_disable_count_trigger_ops = {
11711163
.free = event_enable_trigger_free,
11721164
};
11731165

1174-
static int
1175-
event_enable_trigger_func(struct event_command *cmd_ops,
1176-
struct trace_event_file *file,
1177-
char *glob, char *cmd, char *param)
1166+
int event_enable_trigger_func(struct event_command *cmd_ops,
1167+
struct trace_event_file *file,
1168+
char *glob, char *cmd, char *param)
11781169
{
11791170
struct trace_event_file *event_enable_file;
11801171
struct enable_trigger_data *enable_data;
@@ -1183,6 +1174,7 @@ event_enable_trigger_func(struct event_command *cmd_ops,
11831174
struct trace_array *tr = file->tr;
11841175
const char *system;
11851176
const char *event;
1177+
bool hist = false;
11861178
char *trigger;
11871179
char *number;
11881180
bool enable;
@@ -1207,8 +1199,15 @@ event_enable_trigger_func(struct event_command *cmd_ops,
12071199
if (!event_enable_file)
12081200
goto out;
12091201

1210-
enable = strcmp(cmd, ENABLE_EVENT_STR) == 0;
1202+
#ifdef CONFIG_HIST_TRIGGERS
1203+
hist = ((strcmp(cmd, ENABLE_HIST_STR) == 0) ||
1204+
(strcmp(cmd, DISABLE_HIST_STR) == 0));
12111205

1206+
enable = ((strcmp(cmd, ENABLE_EVENT_STR) == 0) ||
1207+
(strcmp(cmd, ENABLE_HIST_STR) == 0));
1208+
#else
1209+
enable = strcmp(cmd, ENABLE_EVENT_STR) == 0;
1210+
#endif
12121211
trigger_ops = cmd_ops->get_trigger_ops(cmd, trigger);
12131212

12141213
ret = -ENOMEM;
@@ -1228,6 +1227,7 @@ event_enable_trigger_func(struct event_command *cmd_ops,
12281227
INIT_LIST_HEAD(&trigger_data->list);
12291228
RCU_INIT_POINTER(trigger_data->filter, NULL);
12301229

1230+
enable_data->hist = hist;
12311231
enable_data->enable = enable;
12321232
enable_data->file = event_enable_file;
12331233
trigger_data->private_data = enable_data;
@@ -1305,10 +1305,10 @@ event_enable_trigger_func(struct event_command *cmd_ops,
13051305
goto out;
13061306
}
13071307

1308-
static int event_enable_register_trigger(char *glob,
1309-
struct event_trigger_ops *ops,
1310-
struct event_trigger_data *data,
1311-
struct trace_event_file *file)
1308+
int event_enable_register_trigger(char *glob,
1309+
struct event_trigger_ops *ops,
1310+
struct event_trigger_data *data,
1311+
struct trace_event_file *file)
13121312
{
13131313
struct enable_trigger_data *enable_data = data->private_data;
13141314
struct enable_trigger_data *test_enable_data;
@@ -1318,6 +1318,8 @@ static int event_enable_register_trigger(char *glob,
13181318
list_for_each_entry_rcu(test, &file->triggers, list) {
13191319
test_enable_data = test->private_data;
13201320
if (test_enable_data &&
1321+
(test->cmd_ops->trigger_type ==
1322+
data->cmd_ops->trigger_type) &&
13211323
(test_enable_data->file == enable_data->file)) {
13221324
ret = -EEXIST;
13231325
goto out;
@@ -1343,10 +1345,10 @@ static int event_enable_register_trigger(char *glob,
13431345
return ret;
13441346
}
13451347

1346-
static void event_enable_unregister_trigger(char *glob,
1347-
struct event_trigger_ops *ops,
1348-
struct event_trigger_data *test,
1349-
struct trace_event_file *file)
1348+
void event_enable_unregister_trigger(char *glob,
1349+
struct event_trigger_ops *ops,
1350+
struct event_trigger_data *test,
1351+
struct trace_event_file *file)
13501352
{
13511353
struct enable_trigger_data *test_enable_data = test->private_data;
13521354
struct enable_trigger_data *enable_data;
@@ -1356,6 +1358,8 @@ static void event_enable_unregister_trigger(char *glob,
13561358
list_for_each_entry_rcu(data, &file->triggers, list) {
13571359
enable_data = data->private_data;
13581360
if (enable_data &&
1361+
(data->cmd_ops->trigger_type ==
1362+
test->cmd_ops->trigger_type) &&
13591363
(enable_data->file == test_enable_data->file)) {
13601364
unregistered = true;
13611365
list_del_rcu(&data->list);
@@ -1375,8 +1379,12 @@ event_enable_get_trigger_ops(char *cmd, char *param)
13751379
struct event_trigger_ops *ops;
13761380
bool enable;
13771381

1382+
#ifdef CONFIG_HIST_TRIGGERS
1383+
enable = ((strcmp(cmd, ENABLE_EVENT_STR) == 0) ||
1384+
(strcmp(cmd, ENABLE_HIST_STR) == 0));
1385+
#else
13781386
enable = strcmp(cmd, ENABLE_EVENT_STR) == 0;
1379-
1387+
#endif
13801388
if (enable)
13811389
ops = param ? &event_enable_count_trigger_ops :
13821390
&event_enable_trigger_ops;
@@ -1447,6 +1455,7 @@ __init int register_trigger_cmds(void)
14471455
register_trigger_snapshot_cmd();
14481456
register_trigger_stacktrace_cmd();
14491457
register_trigger_enable_disable_cmds();
1458+
register_trigger_hist_enable_disable_cmds();
14501459
register_trigger_hist_cmd();
14511460

14521461
return 0;

0 commit comments

Comments
 (0)