aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-script.c
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2017-06-21 06:17:19 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2017-06-27 11:03:09 -0400
commit1405720d4f2669e5ebaed192bd727aca74f64732 (patch)
tree4a456ee00f46ffc7847764c3945ca6a96a016d19 /tools/perf/builtin-script.c
parentd5b1a5f660b8594125ea2a372286d767e756102f (diff)
perf script: Add 'synth' event type for synthesized events
Instruction trace decoders such as Intel PT may have additional information recorded in the trace. For example, Intel PT has power information and a there is a new instruction 'ptwrite' that can write a value into a PTWRITE trace packet. Such information may be associated with an IP and so can be treated as a sample (PERF_RECORD_SAMPLE). Custom data can be incorporated in the sample as raw_data (PERF_SAMPLE_RAW). However a means of identifying the raw data format is needed. That will be done by synthesizing an attribute for it. So add an attribute type for custom synthesized events. Different synthesized events will be identified by the attribute 'config'. Committer notes: Start those PERF_TYPE_ after the PMU range, i.e. after (INT_MAX + 1U), i.e. after perf_pmu_register() -> idr_alloc(end=0). Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: Andi Kleen <ak@linux.intel.com> Link: http://lkml.kernel.org/r/1498040239-32418-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r--tools/perf/builtin-script.c74
1 files changed, 58 insertions, 16 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 4bce7d8679cb..2999e7e425f6 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -119,6 +119,11 @@ struct output_option {
119 {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, 119 {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF},
120}; 120};
121 121
122enum {
123 OUTPUT_TYPE_SYNTH = PERF_TYPE_MAX,
124 OUTPUT_TYPE_MAX
125};
126
122/* default set to maintain compatibility with current format */ 127/* default set to maintain compatibility with current format */
123static struct { 128static struct {
124 bool user_set; 129 bool user_set;
@@ -126,7 +131,7 @@ static struct {
126 unsigned int print_ip_opts; 131 unsigned int print_ip_opts;
127 u64 fields; 132 u64 fields;
128 u64 invalid_fields; 133 u64 invalid_fields;
129} output[PERF_TYPE_MAX] = { 134} output[OUTPUT_TYPE_MAX] = {
130 135
131 [PERF_TYPE_HARDWARE] = { 136 [PERF_TYPE_HARDWARE] = {
132 .user_set = false, 137 .user_set = false,
@@ -184,12 +189,43 @@ static struct {
184 189
185 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, 190 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
186 }, 191 },
192
193 [OUTPUT_TYPE_SYNTH] = {
194 .user_set = false,
195
196 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
197 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
198 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
199 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
200
201 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
202 },
187}; 203};
188 204
205static inline int output_type(unsigned int type)
206{
207 switch (type) {
208 case PERF_TYPE_SYNTH:
209 return OUTPUT_TYPE_SYNTH;
210 default:
211 return type;
212 }
213}
214
215static inline unsigned int attr_type(unsigned int type)
216{
217 switch (type) {
218 case OUTPUT_TYPE_SYNTH:
219 return PERF_TYPE_SYNTH;
220 default:
221 return type;
222 }
223}
224
189static bool output_set_by_user(void) 225static bool output_set_by_user(void)
190{ 226{
191 int j; 227 int j;
192 for (j = 0; j < PERF_TYPE_MAX; ++j) { 228 for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
193 if (output[j].user_set) 229 if (output[j].user_set)
194 return true; 230 return true;
195 } 231 }
@@ -210,7 +246,7 @@ static const char *output_field2str(enum perf_output_field field)
210 return str; 246 return str;
211} 247}
212 248
213#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) 249#define PRINT_FIELD(x) (output[output_type(attr->type)].fields & PERF_OUTPUT_##x)
214 250
215static int perf_evsel__do_check_stype(struct perf_evsel *evsel, 251static int perf_evsel__do_check_stype(struct perf_evsel *evsel,
216 u64 sample_type, const char *sample_msg, 252 u64 sample_type, const char *sample_msg,
@@ -218,7 +254,7 @@ static int perf_evsel__do_check_stype(struct perf_evsel *evsel,
218 bool allow_user_set) 254 bool allow_user_set)
219{ 255{
220 struct perf_event_attr *attr = &evsel->attr; 256 struct perf_event_attr *attr = &evsel->attr;
221 int type = attr->type; 257 int type = output_type(attr->type);
222 const char *evname; 258 const char *evname;
223 259
224 if (attr->sample_type & sample_type) 260 if (attr->sample_type & sample_type)
@@ -348,7 +384,7 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
348 384
349static void set_print_ip_opts(struct perf_event_attr *attr) 385static void set_print_ip_opts(struct perf_event_attr *attr)
350{ 386{
351 unsigned int type = attr->type; 387 unsigned int type = output_type(attr->type);
352 388
353 output[type].print_ip_opts = 0; 389 output[type].print_ip_opts = 0;
354 if (PRINT_FIELD(IP)) 390 if (PRINT_FIELD(IP))
@@ -376,14 +412,15 @@ static int perf_session__check_output_opt(struct perf_session *session)
376 unsigned int j; 412 unsigned int j;
377 struct perf_evsel *evsel; 413 struct perf_evsel *evsel;
378 414
379 for (j = 0; j < PERF_TYPE_MAX; ++j) { 415 for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
380 evsel = perf_session__find_first_evtype(session, j); 416 evsel = perf_session__find_first_evtype(session, attr_type(j));
381 417
382 /* 418 /*
383 * even if fields is set to 0 (ie., show nothing) event must 419 * even if fields is set to 0 (ie., show nothing) event must
384 * exist if user explicitly includes it on the command line 420 * exist if user explicitly includes it on the command line
385 */ 421 */
386 if (!evsel && output[j].user_set && !output[j].wildcard_set) { 422 if (!evsel && output[j].user_set && !output[j].wildcard_set &&
423 j != OUTPUT_TYPE_SYNTH) {
387 pr_err("%s events do not exist. " 424 pr_err("%s events do not exist. "
388 "Remove corresponding -F option to proceed.\n", 425 "Remove corresponding -F option to proceed.\n",
389 event_type(j)); 426 event_type(j));
@@ -989,6 +1026,7 @@ static void print_sample_bts(struct perf_sample *sample,
989 struct machine *machine) 1026 struct machine *machine)
990{ 1027{
991 struct perf_event_attr *attr = &evsel->attr; 1028 struct perf_event_attr *attr = &evsel->attr;
1029 unsigned int type = output_type(attr->type);
992 bool print_srcline_last = false; 1030 bool print_srcline_last = false;
993 1031
994 if (PRINT_FIELD(CALLINDENT)) 1032 if (PRINT_FIELD(CALLINDENT))
@@ -996,7 +1034,7 @@ static void print_sample_bts(struct perf_sample *sample,
996 1034
997 /* print branch_from information */ 1035 /* print branch_from information */
998 if (PRINT_FIELD(IP)) { 1036 if (PRINT_FIELD(IP)) {
999 unsigned int print_opts = output[attr->type].print_ip_opts; 1037 unsigned int print_opts = output[type].print_ip_opts;
1000 struct callchain_cursor *cursor = NULL; 1038 struct callchain_cursor *cursor = NULL;
1001 1039
1002 if (symbol_conf.use_callchain && sample->callchain && 1040 if (symbol_conf.use_callchain && sample->callchain &&
@@ -1019,7 +1057,7 @@ static void print_sample_bts(struct perf_sample *sample,
1019 /* print branch_to information */ 1057 /* print branch_to information */
1020 if (PRINT_FIELD(ADDR) || 1058 if (PRINT_FIELD(ADDR) ||
1021 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 1059 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
1022 !output[attr->type].user_set)) { 1060 !output[type].user_set)) {
1023 printf(" => "); 1061 printf(" => ");
1024 print_sample_addr(sample, thread, attr); 1062 print_sample_addr(sample, thread, attr);
1025 } 1063 }
@@ -1215,8 +1253,9 @@ static void process_event(struct perf_script *script,
1215{ 1253{
1216 struct thread *thread = al->thread; 1254 struct thread *thread = al->thread;
1217 struct perf_event_attr *attr = &evsel->attr; 1255 struct perf_event_attr *attr = &evsel->attr;
1256 unsigned int type = output_type(attr->type);
1218 1257
1219 if (output[attr->type].fields == 0) 1258 if (output[type].fields == 0)
1220 return; 1259 return;
1221 1260
1222 print_sample_start(sample, thread, evsel); 1261 print_sample_start(sample, thread, evsel);
@@ -1263,7 +1302,7 @@ static void process_event(struct perf_script *script,
1263 cursor = &callchain_cursor; 1302 cursor = &callchain_cursor;
1264 1303
1265 putchar(cursor ? '\n' : ' '); 1304 putchar(cursor ? '\n' : ' ');
1266 sample__fprintf_sym(sample, al, 0, output[attr->type].print_ip_opts, cursor, stdout); 1305 sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, stdout);
1267 } 1306 }
1268 1307
1269 if (PRINT_FIELD(IREGS)) 1308 if (PRINT_FIELD(IREGS))
@@ -1410,7 +1449,8 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
1410 evlist = *pevlist; 1449 evlist = *pevlist;
1411 evsel = perf_evlist__last(*pevlist); 1450 evsel = perf_evlist__last(*pevlist);
1412 1451
1413 if (evsel->attr.type >= PERF_TYPE_MAX) 1452 if (evsel->attr.type >= PERF_TYPE_MAX &&
1453 evsel->attr.type != PERF_TYPE_SYNTH)
1414 return 0; 1454 return 0;
1415 1455
1416 evlist__for_each_entry(evlist, pos) { 1456 evlist__for_each_entry(evlist, pos) {
@@ -1835,6 +1875,8 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
1835 type = PERF_TYPE_RAW; 1875 type = PERF_TYPE_RAW;
1836 else if (!strcmp(str, "break")) 1876 else if (!strcmp(str, "break"))
1837 type = PERF_TYPE_BREAKPOINT; 1877 type = PERF_TYPE_BREAKPOINT;
1878 else if (!strcmp(str, "synth"))
1879 type = OUTPUT_TYPE_SYNTH;
1838 else { 1880 else {
1839 fprintf(stderr, "Invalid event type in field string.\n"); 1881 fprintf(stderr, "Invalid event type in field string.\n");
1840 rc = -EINVAL; 1882 rc = -EINVAL;
@@ -1865,7 +1907,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
1865 if (output_set_by_user()) 1907 if (output_set_by_user())
1866 pr_warning("Overriding previous field request for all events.\n"); 1908 pr_warning("Overriding previous field request for all events.\n");
1867 1909
1868 for (j = 0; j < PERF_TYPE_MAX; ++j) { 1910 for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
1869 output[j].fields = 0; 1911 output[j].fields = 0;
1870 output[j].user_set = true; 1912 output[j].user_set = true;
1871 output[j].wildcard_set = true; 1913 output[j].wildcard_set = true;
@@ -1908,7 +1950,7 @@ parse:
1908 /* add user option to all events types for 1950 /* add user option to all events types for
1909 * which it is valid 1951 * which it is valid
1910 */ 1952 */
1911 for (j = 0; j < PERF_TYPE_MAX; ++j) { 1953 for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
1912 if (output[j].invalid_fields & all_output_options[i].field) { 1954 if (output[j].invalid_fields & all_output_options[i].field) {
1913 pr_warning("\'%s\' not valid for %s events. Ignoring.\n", 1955 pr_warning("\'%s\' not valid for %s events. Ignoring.\n",
1914 all_output_options[i].str, event_type(j)); 1956 all_output_options[i].str, event_type(j));
@@ -2560,7 +2602,7 @@ int cmd_script(int argc, const char **argv)
2560 OPT_CALLBACK('F', "fields", NULL, "str", 2602 OPT_CALLBACK('F', "fields", NULL, "str",
2561 "comma separated output fields prepend with 'type:'. " 2603 "comma separated output fields prepend with 'type:'. "
2562 "+field to add and -field to remove." 2604 "+field to add and -field to remove."
2563 "Valid types: hw,sw,trace,raw. " 2605 "Valid types: hw,sw,trace,raw,synth. "
2564 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," 2606 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
2565 "addr,symoff,period,iregs,brstack,brstacksym,flags," 2607 "addr,symoff,period,iregs,brstack,brstacksym,flags,"
2566 "bpf-output,callindent,insn,insnlen,brstackinsn", 2608 "bpf-output,callindent,insn,insnlen,brstackinsn",