aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-script.txt52
-rw-r--r--tools/perf/builtin-script.c171
-rw-r--r--tools/perf/util/probe-finder.c72
-rw-r--r--tools/perf/util/probe-finder.h2
4 files changed, 246 insertions, 51 deletions
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 66f040b30729..86c87e214b11 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -113,13 +113,61 @@ OPTIONS
113 Do various checks like samples ordering and lost events. 113 Do various checks like samples ordering and lost events.
114 114
115-f:: 115-f::
116--fields 116--fields::
117 Comma separated list of fields to print. Options are: 117 Comma separated list of fields to print. Options are:
118 comm, tid, pid, time, cpu, event, trace, sym. Field 118 comm, tid, pid, time, cpu, event, trace, sym. Field
119 list must be prepended with the type, trace, sw or hw, 119 list can be prepended with the type, trace, sw or hw,
120 to indicate to which event type the field list applies. 120 to indicate to which event type the field list applies.
121 e.g., -f sw:comm,tid,time,sym and -f trace:time,cpu,trace 121 e.g., -f sw:comm,tid,time,sym and -f trace:time,cpu,trace
122 122
123 perf script -f <fields>
124
125 is equivalent to:
126
127 perf script -f trace:<fields> -f sw:<fields> -f hw:<fields>
128
129 i.e., the specified fields apply to all event types if the type string
130 is not given.
131
132 The arguments are processed in the order received. A later usage can
133 reset a prior request. e.g.:
134
135 -f trace: -f comm,tid,time,sym
136
137 The first -f suppresses trace events (field list is ""), but then the
138 second invocation sets the fields to comm,tid,time,sym. In this case a
139 warning is given to the user:
140
141 "Overriding previous field request for all events."
142
143 Alternativey, consider the order:
144
145 -f comm,tid,time,sym -f trace:
146
147 The first -f sets the fields for all events and the second -f
148 suppresses trace events. The user is given a warning message about
149 the override, and the result of the above is that only S/W and H/W
150 events are displayed with the given fields.
151
152 For the 'wildcard' option if a user selected field is invalid for an
153 event type, a message is displayed to the user that the option is
154 ignored for that type. For example:
155
156 $ perf script -f comm,tid,trace
157 'trace' not valid for hardware events. Ignoring.
158 'trace' not valid for software events. Ignoring.
159
160 Alternatively, if the type is given an invalid field is specified it
161 is an error. For example:
162
163 perf script -v -f sw:comm,tid,trace
164 'trace' not valid for software events.
165
166 At this point usage is displayed, and perf-script exits.
167
168 Finally, a user may not set fields to none for all event types.
169 i.e., -f "" is not allowed.
170
123-k:: 171-k::
124--vmlinux=<file>:: 172--vmlinux=<file>::
125 vmlinux pathname 173 vmlinux pathname
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index ac574ea23917..6cf811acc41b 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -49,23 +49,52 @@ struct output_option {
49}; 49};
50 50
51/* default set to maintain compatibility with current format */ 51/* default set to maintain compatibility with current format */
52static u64 output_fields[PERF_TYPE_MAX] = { 52static struct {
53 [PERF_TYPE_HARDWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ 53 bool user_set;
54 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ 54 u64 fields;
55 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, 55 u64 invalid_fields;
56 56} output[PERF_TYPE_MAX] = {
57 [PERF_TYPE_SOFTWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ 57
58 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ 58 [PERF_TYPE_HARDWARE] = {
59 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, 59 .user_set = false,
60 60
61 [PERF_TYPE_TRACEPOINT] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ 61 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
62 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ 62 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
63 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, 63 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
64
65 .invalid_fields = PERF_OUTPUT_TRACE,
66 },
67
68 [PERF_TYPE_SOFTWARE] = {
69 .user_set = false,
70
71 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
72 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
73 PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
74
75 .invalid_fields = PERF_OUTPUT_TRACE,
76 },
77
78 [PERF_TYPE_TRACEPOINT] = {
79 .user_set = false,
80
81 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
82 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
83 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE,
84 },
64}; 85};
65 86
66static bool output_set_by_user; 87static bool output_set_by_user(void)
88{
89 int j;
90 for (j = 0; j < PERF_TYPE_MAX; ++j) {
91 if (output[j].user_set)
92 return true;
93 }
94 return false;
95}
67 96
68#define PRINT_FIELD(x) (output_fields[attr->type] & PERF_OUTPUT_##x) 97#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x)
69 98
70static int perf_session__check_attr(struct perf_session *session, 99static int perf_session__check_attr(struct perf_session *session,
71 struct perf_event_attr *attr) 100 struct perf_event_attr *attr)
@@ -168,7 +197,7 @@ static void process_event(union perf_event *event __unused,
168{ 197{
169 struct perf_event_attr *attr = &evsel->attr; 198 struct perf_event_attr *attr = &evsel->attr;
170 199
171 if (output_fields[attr->type] == 0) 200 if (output[attr->type].fields == 0)
172 return; 201 return;
173 202
174 if (perf_session__check_attr(session, attr) < 0) 203 if (perf_session__check_attr(session, attr) < 0)
@@ -451,6 +480,7 @@ static int parse_output_fields(const struct option *opt __used,
451{ 480{
452 char *tok; 481 char *tok;
453 int i, imax = sizeof(all_output_options) / sizeof(struct output_option); 482 int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
483 int j;
454 int rc = 0; 484 int rc = 0;
455 char *str = strdup(arg); 485 char *str = strdup(arg);
456 int type = -1; 486 int type = -1;
@@ -458,52 +488,95 @@ static int parse_output_fields(const struct option *opt __used,
458 if (!str) 488 if (!str)
459 return -ENOMEM; 489 return -ENOMEM;
460 490
461 tok = strtok(str, ":"); 491 /* first word can state for which event type the user is specifying
462 if (!tok) { 492 * the fields. If no type exists, the specified fields apply to all
463 fprintf(stderr, 493 * event types found in the file minus the invalid fields for a type.
464 "Invalid field string - not prepended with type.");
465 return -EINVAL;
466 }
467
468 /* first word should state which event type user
469 * is specifying the fields
470 */ 494 */
471 if (!strcmp(tok, "hw")) 495 tok = strchr(str, ':');
472 type = PERF_TYPE_HARDWARE; 496 if (tok) {
473 else if (!strcmp(tok, "sw")) 497 *tok = '\0';
474 type = PERF_TYPE_SOFTWARE; 498 tok++;
475 else if (!strcmp(tok, "trace")) 499 if (!strcmp(str, "hw"))
476 type = PERF_TYPE_TRACEPOINT; 500 type = PERF_TYPE_HARDWARE;
477 else { 501 else if (!strcmp(str, "sw"))
478 fprintf(stderr, "Invalid event type in field string."); 502 type = PERF_TYPE_SOFTWARE;
479 return -EINVAL; 503 else if (!strcmp(str, "trace"))
504 type = PERF_TYPE_TRACEPOINT;
505 else {
506 fprintf(stderr, "Invalid event type in field string.\n");
507 return -EINVAL;
508 }
509
510 if (output[type].user_set)
511 pr_warning("Overriding previous field request for %s events.\n",
512 event_type(type));
513
514 output[type].fields = 0;
515 output[type].user_set = true;
516
517 } else {
518 tok = str;
519 if (strlen(str) == 0) {
520 fprintf(stderr,
521 "Cannot set fields to 'none' for all event types.\n");
522 rc = -EINVAL;
523 goto out;
524 }
525
526 if (output_set_by_user())
527 pr_warning("Overriding previous field request for all events.\n");
528
529 for (j = 0; j < PERF_TYPE_MAX; ++j) {
530 output[j].fields = 0;
531 output[j].user_set = true;
532 }
480 } 533 }
481 534
482 output_fields[type] = 0; 535 tok = strtok(tok, ",");
483 while (1) { 536 while (tok) {
484 tok = strtok(NULL, ",");
485 if (!tok)
486 break;
487 for (i = 0; i < imax; ++i) { 537 for (i = 0; i < imax; ++i) {
488 if (strcmp(tok, all_output_options[i].str) == 0) { 538 if (strcmp(tok, all_output_options[i].str) == 0)
489 output_fields[type] |= all_output_options[i].field;
490 break; 539 break;
491 }
492 } 540 }
493 if (i == imax) { 541 if (i == imax) {
494 fprintf(stderr, "Invalid field requested."); 542 fprintf(stderr, "Invalid field requested.\n");
495 rc = -EINVAL; 543 rc = -EINVAL;
496 break; 544 goto out;
497 } 545 }
498 }
499 546
500 if (output_fields[type] == 0) { 547 if (type == -1) {
501 pr_debug("No fields requested for %s type. " 548 /* add user option to all events types for
502 "Events will not be displayed\n", event_type(type)); 549 * which it is valid
550 */
551 for (j = 0; j < PERF_TYPE_MAX; ++j) {
552 if (output[j].invalid_fields & all_output_options[i].field) {
553 pr_warning("\'%s\' not valid for %s events. Ignoring.\n",
554 all_output_options[i].str, event_type(j));
555 } else
556 output[j].fields |= all_output_options[i].field;
557 }
558 } else {
559 if (output[type].invalid_fields & all_output_options[i].field) {
560 fprintf(stderr, "\'%s\' not valid for %s events.\n",
561 all_output_options[i].str, event_type(type));
562
563 rc = -EINVAL;
564 goto out;
565 }
566 output[type].fields |= all_output_options[i].field;
567 }
568
569 tok = strtok(NULL, ",");
503 } 570 }
504 571
505 output_set_by_user = true; 572 if (type >= 0) {
573 if (output[type].fields == 0) {
574 pr_debug("No fields requested for %s type. "
575 "Events will not be displayed.\n", event_type(type));
576 }
577 }
506 578
579out:
507 free(str); 580 free(str);
508 return rc; 581 return rc;
509} 582}
@@ -1020,7 +1093,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
1020 struct stat perf_stat; 1093 struct stat perf_stat;
1021 int input; 1094 int input;
1022 1095
1023 if (output_set_by_user) { 1096 if (output_set_by_user()) {
1024 fprintf(stderr, 1097 fprintf(stderr,
1025 "custom fields not supported for generated scripts"); 1098 "custom fields not supported for generated scripts");
1026 return -1; 1099 return -1;
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index b7c85ce466a1..a7c7145a8d4f 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1471,6 +1471,38 @@ static int find_probe_point_by_func(struct probe_finder *pf)
1471 return _param.retval; 1471 return _param.retval;
1472} 1472}
1473 1473
1474struct pubname_callback_param {
1475 char *function;
1476 char *file;
1477 Dwarf_Die *cu_die;
1478 Dwarf_Die *sp_die;
1479 int found;
1480};
1481
1482static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
1483{
1484 struct pubname_callback_param *param = data;
1485
1486 if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) {
1487 if (dwarf_tag(param->sp_die) != DW_TAG_subprogram)
1488 return DWARF_CB_OK;
1489
1490 if (die_compare_name(param->sp_die, param->function)) {
1491 if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die))
1492 return DWARF_CB_OK;
1493
1494 if (param->file &&
1495 strtailcmp(param->file, dwarf_decl_file(param->sp_die)))
1496 return DWARF_CB_OK;
1497
1498 param->found = 1;
1499 return DWARF_CB_ABORT;
1500 }
1501 }
1502
1503 return DWARF_CB_OK;
1504}
1505
1474/* Find probe points from debuginfo */ 1506/* Find probe points from debuginfo */
1475static int find_probes(int fd, struct probe_finder *pf) 1507static int find_probes(int fd, struct probe_finder *pf)
1476{ 1508{
@@ -1498,6 +1530,27 @@ static int find_probes(int fd, struct probe_finder *pf)
1498 1530
1499 off = 0; 1531 off = 0;
1500 line_list__init(&pf->lcache); 1532 line_list__init(&pf->lcache);
1533
1534 /* Fastpath: lookup by function name from .debug_pubnames section */
1535 if (pp->function) {
1536 struct pubname_callback_param pubname_param = {
1537 .function = pp->function,
1538 .file = pp->file,
1539 .cu_die = &pf->cu_die,
1540 .sp_die = &pf->sp_die,
1541 };
1542 struct dwarf_callback_param probe_param = {
1543 .data = pf,
1544 };
1545
1546 dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0);
1547 if (pubname_param.found) {
1548 ret = probe_point_search_cb(&pf->sp_die, &probe_param);
1549 if (ret)
1550 goto found;
1551 }
1552 }
1553
1501 /* Loop on CUs (Compilation Unit) */ 1554 /* Loop on CUs (Compilation Unit) */
1502 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 1555 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
1503 /* Get the DIE(Debugging Information Entry) of this CU */ 1556 /* Get the DIE(Debugging Information Entry) of this CU */
@@ -1525,6 +1578,8 @@ static int find_probes(int fd, struct probe_finder *pf)
1525 } 1578 }
1526 off = noff; 1579 off = noff;
1527 } 1580 }
1581
1582found:
1528 line_list__free(&pf->lcache); 1583 line_list__free(&pf->lcache);
1529 if (dwfl) 1584 if (dwfl)
1530 dwfl_end(dwfl); 1585 dwfl_end(dwfl);
@@ -1946,6 +2001,22 @@ int find_line_range(int fd, struct line_range *lr)
1946 return -EBADF; 2001 return -EBADF;
1947 } 2002 }
1948 2003
2004 /* Fastpath: lookup by function name from .debug_pubnames section */
2005 if (lr->function) {
2006 struct pubname_callback_param pubname_param = {
2007 .function = lr->function, .file = lr->file,
2008 .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0};
2009 struct dwarf_callback_param line_range_param = {
2010 .data = (void *)&lf, .retval = 0};
2011
2012 dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0);
2013 if (pubname_param.found) {
2014 line_range_search_cb(&lf.sp_die, &line_range_param);
2015 if (lf.found)
2016 goto found;
2017 }
2018 }
2019
1949 /* Loop on CUs (Compilation Unit) */ 2020 /* Loop on CUs (Compilation Unit) */
1950 while (!lf.found && ret >= 0) { 2021 while (!lf.found && ret >= 0) {
1951 if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) 2022 if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0)
@@ -1974,6 +2045,7 @@ int find_line_range(int fd, struct line_range *lr)
1974 off = noff; 2045 off = noff;
1975 } 2046 }
1976 2047
2048found:
1977 /* Store comp_dir */ 2049 /* Store comp_dir */
1978 if (lf.found) { 2050 if (lf.found) {
1979 comp_dir = cu_get_comp_dir(&lf.cu_die); 2051 comp_dir = cu_get_comp_dir(&lf.cu_die);
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index beaefc3c1223..605730a366db 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -49,6 +49,7 @@ struct probe_finder {
49 Dwarf_Addr addr; /* Address */ 49 Dwarf_Addr addr; /* Address */
50 const char *fname; /* Real file name */ 50 const char *fname; /* Real file name */
51 Dwarf_Die cu_die; /* Current CU */ 51 Dwarf_Die cu_die; /* Current CU */
52 Dwarf_Die sp_die;
52 struct list_head lcache; /* Line cache for lazy match */ 53 struct list_head lcache; /* Line cache for lazy match */
53 54
54 /* For variable searching */ 55 /* For variable searching */
@@ -83,6 +84,7 @@ struct line_finder {
83 int lno_s; /* Start line number */ 84 int lno_s; /* Start line number */
84 int lno_e; /* End line number */ 85 int lno_e; /* End line number */
85 Dwarf_Die cu_die; /* Current CU */ 86 Dwarf_Die cu_die; /* Current CU */
87 Dwarf_Die sp_die;
86 int found; 88 int found;
87}; 89};
88 90