diff options
-rw-r--r-- | tools/perf/builtin-sched.c | 149 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 42 | ||||
-rw-r--r-- | tools/perf/util/evlist.h | 11 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 4 | ||||
-rw-r--r-- | tools/perf/util/tool.h | 5 |
5 files changed, 136 insertions, 75 deletions
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 0ee868e6f63b..6284ed2317f2 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include "perf.h" | 2 | #include "perf.h" |
3 | 3 | ||
4 | #include "util/util.h" | 4 | #include "util/util.h" |
5 | #include "util/evlist.h" | ||
5 | #include "util/cache.h" | 6 | #include "util/cache.h" |
6 | #include "util/evsel.h" | 7 | #include "util/evsel.h" |
7 | #include "util/symbol.h" | 8 | #include "util/symbol.h" |
@@ -1358,12 +1359,13 @@ static void sort_lat(void) | |||
1358 | static struct trace_sched_handler *trace_handler; | 1359 | static struct trace_sched_handler *trace_handler; |
1359 | 1360 | ||
1360 | static void | 1361 | static void |
1361 | process_sched_wakeup_event(void *data, struct machine *machine, | 1362 | process_sched_wakeup_event(struct perf_tool *tool __used, |
1362 | struct event *event, | 1363 | struct event *event, |
1363 | int cpu __used, | 1364 | struct perf_sample *sample, |
1364 | u64 timestamp __used, | 1365 | struct machine *machine, |
1365 | struct thread *thread __used) | 1366 | struct thread *thread) |
1366 | { | 1367 | { |
1368 | void *data = sample->raw_data; | ||
1367 | struct trace_wakeup_event wakeup_event; | 1369 | struct trace_wakeup_event wakeup_event; |
1368 | 1370 | ||
1369 | FILL_COMMON_FIELDS(wakeup_event, event, data); | 1371 | FILL_COMMON_FIELDS(wakeup_event, event, data); |
@@ -1376,7 +1378,7 @@ process_sched_wakeup_event(void *data, struct machine *machine, | |||
1376 | 1378 | ||
1377 | if (trace_handler->wakeup_event) | 1379 | if (trace_handler->wakeup_event) |
1378 | trace_handler->wakeup_event(&wakeup_event, machine, event, | 1380 | trace_handler->wakeup_event(&wakeup_event, machine, event, |
1379 | cpu, timestamp, thread); | 1381 | sample->cpu, sample->time, thread); |
1380 | } | 1382 | } |
1381 | 1383 | ||
1382 | /* | 1384 | /* |
@@ -1471,14 +1473,15 @@ map_switch_event(struct trace_switch_event *switch_event, | |||
1471 | } | 1473 | } |
1472 | } | 1474 | } |
1473 | 1475 | ||
1474 | |||
1475 | static void | 1476 | static void |
1476 | process_sched_switch_event(void *data, struct machine *machine, | 1477 | process_sched_switch_event(struct perf_tool *tool __used, |
1477 | struct event *event, | 1478 | struct event *event, |
1478 | int this_cpu, | 1479 | struct perf_sample *sample, |
1479 | u64 timestamp __used, | 1480 | struct machine *machine, |
1480 | struct thread *thread __used) | 1481 | struct thread *thread) |
1481 | { | 1482 | { |
1483 | int this_cpu = sample->cpu; | ||
1484 | void *data = sample->raw_data; | ||
1482 | struct trace_switch_event switch_event; | 1485 | struct trace_switch_event switch_event; |
1483 | 1486 | ||
1484 | FILL_COMMON_FIELDS(switch_event, event, data); | 1487 | FILL_COMMON_FIELDS(switch_event, event, data); |
@@ -1501,18 +1504,19 @@ process_sched_switch_event(void *data, struct machine *machine, | |||
1501 | } | 1504 | } |
1502 | if (trace_handler->switch_event) | 1505 | if (trace_handler->switch_event) |
1503 | trace_handler->switch_event(&switch_event, machine, event, | 1506 | trace_handler->switch_event(&switch_event, machine, event, |
1504 | this_cpu, timestamp, thread); | 1507 | this_cpu, sample->time, thread); |
1505 | 1508 | ||
1506 | curr_pid[this_cpu] = switch_event.next_pid; | 1509 | curr_pid[this_cpu] = switch_event.next_pid; |
1507 | } | 1510 | } |
1508 | 1511 | ||
1509 | static void | 1512 | static void |
1510 | process_sched_runtime_event(void *data, struct machine *machine, | 1513 | process_sched_runtime_event(struct perf_tool *tool __used, |
1511 | struct event *event, | 1514 | struct event *event, |
1512 | int cpu __used, | 1515 | struct perf_sample *sample, |
1513 | u64 timestamp __used, | 1516 | struct machine *machine, |
1514 | struct thread *thread __used) | 1517 | struct thread *thread) |
1515 | { | 1518 | { |
1519 | void *data = sample->raw_data; | ||
1516 | struct trace_runtime_event runtime_event; | 1520 | struct trace_runtime_event runtime_event; |
1517 | 1521 | ||
1518 | FILL_ARRAY(runtime_event, comm, event, data); | 1522 | FILL_ARRAY(runtime_event, comm, event, data); |
@@ -1521,16 +1525,18 @@ process_sched_runtime_event(void *data, struct machine *machine, | |||
1521 | FILL_FIELD(runtime_event, vruntime, event, data); | 1525 | FILL_FIELD(runtime_event, vruntime, event, data); |
1522 | 1526 | ||
1523 | if (trace_handler->runtime_event) | 1527 | if (trace_handler->runtime_event) |
1524 | trace_handler->runtime_event(&runtime_event, machine, event, cpu, timestamp, thread); | 1528 | trace_handler->runtime_event(&runtime_event, machine, event, |
1529 | sample->cpu, sample->time, thread); | ||
1525 | } | 1530 | } |
1526 | 1531 | ||
1527 | static void | 1532 | static void |
1528 | process_sched_fork_event(void *data, | 1533 | process_sched_fork_event(struct perf_tool *tool __used, |
1529 | struct event *event, | 1534 | struct event *event, |
1530 | int cpu __used, | 1535 | struct perf_sample *sample, |
1531 | u64 timestamp __used, | 1536 | struct machine *machine __used, |
1532 | struct thread *thread __used) | 1537 | struct thread *thread) |
1533 | { | 1538 | { |
1539 | void *data = sample->raw_data; | ||
1534 | struct trace_fork_event fork_event; | 1540 | struct trace_fork_event fork_event; |
1535 | 1541 | ||
1536 | FILL_COMMON_FIELDS(fork_event, event, data); | 1542 | FILL_COMMON_FIELDS(fork_event, event, data); |
@@ -1542,13 +1548,14 @@ process_sched_fork_event(void *data, | |||
1542 | 1548 | ||
1543 | if (trace_handler->fork_event) | 1549 | if (trace_handler->fork_event) |
1544 | trace_handler->fork_event(&fork_event, event, | 1550 | trace_handler->fork_event(&fork_event, event, |
1545 | cpu, timestamp, thread); | 1551 | sample->cpu, sample->time, thread); |
1546 | } | 1552 | } |
1547 | 1553 | ||
1548 | static void | 1554 | static void |
1549 | process_sched_exit_event(struct event *event, | 1555 | process_sched_exit_event(struct perf_tool *tool __used, |
1550 | int cpu __used, | 1556 | struct event *event, |
1551 | u64 timestamp __used, | 1557 | struct perf_sample *sample __used, |
1558 | struct machine *machine __used, | ||
1552 | struct thread *thread __used) | 1559 | struct thread *thread __used) |
1553 | { | 1560 | { |
1554 | if (verbose) | 1561 | if (verbose) |
@@ -1556,12 +1563,13 @@ process_sched_exit_event(struct event *event, | |||
1556 | } | 1563 | } |
1557 | 1564 | ||
1558 | static void | 1565 | static void |
1559 | process_sched_migrate_task_event(void *data, struct machine *machine, | 1566 | process_sched_migrate_task_event(struct perf_tool *tool __used, |
1560 | struct event *event, | 1567 | struct event *event, |
1561 | int cpu __used, | 1568 | struct perf_sample *sample, |
1562 | u64 timestamp __used, | 1569 | struct machine *machine, |
1563 | struct thread *thread __used) | 1570 | struct thread *thread) |
1564 | { | 1571 | { |
1572 | void *data = sample->raw_data; | ||
1565 | struct trace_migrate_task_event migrate_task_event; | 1573 | struct trace_migrate_task_event migrate_task_event; |
1566 | 1574 | ||
1567 | FILL_COMMON_FIELDS(migrate_task_event, event, data); | 1575 | FILL_COMMON_FIELDS(migrate_task_event, event, data); |
@@ -1573,67 +1581,46 @@ process_sched_migrate_task_event(void *data, struct machine *machine, | |||
1573 | 1581 | ||
1574 | if (trace_handler->migrate_task_event) | 1582 | if (trace_handler->migrate_task_event) |
1575 | trace_handler->migrate_task_event(&migrate_task_event, machine, | 1583 | trace_handler->migrate_task_event(&migrate_task_event, machine, |
1576 | event, cpu, timestamp, thread); | 1584 | event, sample->cpu, |
1585 | sample->time, thread); | ||
1577 | } | 1586 | } |
1578 | 1587 | ||
1579 | static void process_raw_event(union perf_event *raw_event __used, | 1588 | typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event *event, |
1580 | struct machine *machine, void *data, int cpu, | 1589 | struct perf_sample *sample, |
1581 | u64 timestamp, struct thread *thread) | 1590 | struct machine *machine, |
1582 | { | 1591 | struct thread *thread); |
1583 | struct event *event; | ||
1584 | int type; | ||
1585 | |||
1586 | |||
1587 | type = trace_parse_common_type(data); | ||
1588 | event = trace_find_event(type); | ||
1589 | |||
1590 | if (!strcmp(event->name, "sched_switch")) | ||
1591 | process_sched_switch_event(data, machine, event, cpu, timestamp, thread); | ||
1592 | if (!strcmp(event->name, "sched_stat_runtime")) | ||
1593 | process_sched_runtime_event(data, machine, event, cpu, timestamp, thread); | ||
1594 | if (!strcmp(event->name, "sched_wakeup")) | ||
1595 | process_sched_wakeup_event(data, machine, event, cpu, timestamp, thread); | ||
1596 | if (!strcmp(event->name, "sched_wakeup_new")) | ||
1597 | process_sched_wakeup_event(data, machine, event, cpu, timestamp, thread); | ||
1598 | if (!strcmp(event->name, "sched_process_fork")) | ||
1599 | process_sched_fork_event(data, event, cpu, timestamp, thread); | ||
1600 | if (!strcmp(event->name, "sched_process_exit")) | ||
1601 | process_sched_exit_event(event, cpu, timestamp, thread); | ||
1602 | if (!strcmp(event->name, "sched_migrate_task")) | ||
1603 | process_sched_migrate_task_event(data, machine, event, cpu, timestamp, thread); | ||
1604 | } | ||
1605 | 1592 | ||
1606 | static int process_sample_event(struct perf_tool *tool __used, | 1593 | static int perf_sched__process_tracepoint_sample(struct perf_tool *tool, |
1607 | union perf_event *event, | 1594 | union perf_event *event __used, |
1608 | struct perf_sample *sample, | 1595 | struct perf_sample *sample, |
1609 | struct perf_evsel *evsel, | 1596 | struct perf_evsel *evsel, |
1610 | struct machine *machine) | 1597 | struct machine *machine) |
1611 | { | 1598 | { |
1612 | struct thread *thread; | 1599 | struct thread *thread = machine__findnew_thread(machine, sample->pid); |
1613 | |||
1614 | if (!(evsel->attr.sample_type & PERF_SAMPLE_RAW)) | ||
1615 | return 0; | ||
1616 | 1600 | ||
1617 | thread = machine__findnew_thread(machine, sample->pid); | ||
1618 | if (thread == NULL) { | 1601 | if (thread == NULL) { |
1619 | pr_debug("problem processing %d event, skipping it.\n", | 1602 | pr_debug("problem processing %s event, skipping it.\n", |
1620 | event->header.type); | 1603 | evsel->name); |
1621 | return -1; | 1604 | return -1; |
1622 | } | 1605 | } |
1623 | 1606 | ||
1624 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 1607 | evsel->hists.stats.total_period += sample->period; |
1608 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | ||
1625 | 1609 | ||
1626 | if (profile_cpu != -1 && profile_cpu != (int)sample->cpu) | 1610 | if (evsel->handler.func != NULL) { |
1627 | return 0; | 1611 | tracepoint_handler f = evsel->handler.func; |
1628 | 1612 | ||
1629 | process_raw_event(event, machine, sample->raw_data, sample->cpu, | 1613 | if (evsel->handler.data == NULL) |
1630 | sample->time, thread); | 1614 | evsel->handler.data = trace_find_event(evsel->attr.config); |
1615 | |||
1616 | f(tool, evsel->handler.data, sample, machine, thread); | ||
1617 | } | ||
1631 | 1618 | ||
1632 | return 0; | 1619 | return 0; |
1633 | } | 1620 | } |
1634 | 1621 | ||
1635 | static struct perf_tool perf_sched = { | 1622 | static struct perf_tool perf_sched = { |
1636 | .sample = process_sample_event, | 1623 | .sample = perf_sched__process_tracepoint_sample, |
1637 | .comm = perf_event__process_comm, | 1624 | .comm = perf_event__process_comm, |
1638 | .lost = perf_event__process_lost, | 1625 | .lost = perf_event__process_lost, |
1639 | .fork = perf_event__process_task, | 1626 | .fork = perf_event__process_task, |
@@ -1643,11 +1630,23 @@ static struct perf_tool perf_sched = { | |||
1643 | static void read_events(bool destroy, struct perf_session **psession) | 1630 | static void read_events(bool destroy, struct perf_session **psession) |
1644 | { | 1631 | { |
1645 | int err = -EINVAL; | 1632 | int err = -EINVAL; |
1633 | const struct perf_evsel_str_handler handlers[] = { | ||
1634 | { "sched:sched_switch", process_sched_switch_event, }, | ||
1635 | { "sched:sched_stat_runtime", process_sched_runtime_event, }, | ||
1636 | { "sched:sched_wakeup", process_sched_wakeup_event, }, | ||
1637 | { "sched:sched_wakeup_new", process_sched_wakeup_event, }, | ||
1638 | { "sched:sched_process_fork", process_sched_fork_event, }, | ||
1639 | { "sched:sched_process_exit", process_sched_exit_event, }, | ||
1640 | { "sched:sched_migrate_task", process_sched_migrate_task_event, }, | ||
1641 | }; | ||
1646 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, | 1642 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, |
1647 | 0, false, &perf_sched); | 1643 | 0, false, &perf_sched); |
1648 | if (session == NULL) | 1644 | if (session == NULL) |
1649 | die("No Memory"); | 1645 | die("No Memory"); |
1650 | 1646 | ||
1647 | err = perf_evlist__set_tracepoints_handlers_array(session->evlist, handlers); | ||
1648 | assert(err == 0); | ||
1649 | |||
1651 | if (perf_session__has_traces(session, "record -R")) { | 1650 | if (perf_session__has_traces(session, "record -R")) { |
1652 | err = perf_session__process_events(session, &perf_sched); | 1651 | err = perf_session__process_events(session, &perf_sched); |
1653 | if (err) | 1652 | if (err) |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index d44e3df13a8f..b36f26fe767a 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -207,6 +207,48 @@ out_free_attrs: | |||
207 | return err; | 207 | return err; |
208 | } | 208 | } |
209 | 209 | ||
210 | static struct perf_evsel * | ||
211 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) | ||
212 | { | ||
213 | struct perf_evsel *evsel; | ||
214 | |||
215 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
216 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && | ||
217 | (int)evsel->attr.config == id) | ||
218 | return evsel; | ||
219 | } | ||
220 | |||
221 | return NULL; | ||
222 | } | ||
223 | |||
224 | int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, | ||
225 | const struct perf_evsel_str_handler *assocs, | ||
226 | size_t nr_assocs) | ||
227 | { | ||
228 | struct perf_evsel *evsel; | ||
229 | int err; | ||
230 | size_t i; | ||
231 | |||
232 | for (i = 0; i < nr_assocs; i++) { | ||
233 | err = trace_event__id(assocs[i].name); | ||
234 | if (err < 0) | ||
235 | goto out; | ||
236 | |||
237 | evsel = perf_evlist__find_tracepoint_by_id(evlist, err); | ||
238 | if (evsel == NULL) | ||
239 | continue; | ||
240 | |||
241 | err = -EEXIST; | ||
242 | if (evsel->handler.func != NULL) | ||
243 | goto out; | ||
244 | evsel->handler.func = assocs[i].handler; | ||
245 | } | ||
246 | |||
247 | err = 0; | ||
248 | out: | ||
249 | return err; | ||
250 | } | ||
251 | |||
210 | void perf_evlist__disable(struct perf_evlist *evlist) | 252 | void perf_evlist__disable(struct perf_evlist *evlist) |
211 | { | 253 | { |
212 | int cpu, thread; | 254 | int cpu, thread; |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 2202e7b04103..f94ed7e0d987 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -36,6 +36,11 @@ struct perf_evlist { | |||
36 | struct perf_evsel *selected; | 36 | struct perf_evsel *selected; |
37 | }; | 37 | }; |
38 | 38 | ||
39 | struct perf_evsel_str_handler { | ||
40 | const char *name; | ||
41 | void *handler; | ||
42 | }; | ||
43 | |||
39 | struct perf_evsel; | 44 | struct perf_evsel; |
40 | 45 | ||
41 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, | 46 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, |
@@ -51,6 +56,9 @@ int perf_evlist__add_attrs(struct perf_evlist *evlist, | |||
51 | struct perf_event_attr *attrs, size_t nr_attrs); | 56 | struct perf_event_attr *attrs, size_t nr_attrs); |
52 | int perf_evlist__add_tracepoints(struct perf_evlist *evlist, | 57 | int perf_evlist__add_tracepoints(struct perf_evlist *evlist, |
53 | const char *tracepoints[], size_t nr_tracepoints); | 58 | const char *tracepoints[], size_t nr_tracepoints); |
59 | int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, | ||
60 | const struct perf_evsel_str_handler *assocs, | ||
61 | size_t nr_assocs); | ||
54 | 62 | ||
55 | #define perf_evlist__add_attrs_array(evlist, array) \ | 63 | #define perf_evlist__add_attrs_array(evlist, array) \ |
56 | perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) | 64 | perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) |
@@ -58,6 +66,9 @@ int perf_evlist__add_tracepoints(struct perf_evlist *evlist, | |||
58 | #define perf_evlist__add_tracepoints_array(evlist, array) \ | 66 | #define perf_evlist__add_tracepoints_array(evlist, array) \ |
59 | perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) | 67 | perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) |
60 | 68 | ||
69 | #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ | ||
70 | perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) | ||
71 | |||
61 | void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, | 72 | void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, |
62 | int cpu, int thread, u64 id); | 73 | int cpu, int thread, u64 id); |
63 | 74 | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6421c07f5015..326b8e4d5035 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -61,6 +61,10 @@ struct perf_evsel { | |||
61 | off_t id_offset; | 61 | off_t id_offset; |
62 | }; | 62 | }; |
63 | struct cgroup_sel *cgrp; | 63 | struct cgroup_sel *cgrp; |
64 | struct { | ||
65 | void *func; | ||
66 | void *data; | ||
67 | } handler; | ||
64 | bool supported; | 68 | bool supported; |
65 | }; | 69 | }; |
66 | 70 | ||
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 89ff1b551a74..b0e1aadba8d5 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h | |||
@@ -1,8 +1,13 @@ | |||
1 | #ifndef __PERF_TOOL_H | 1 | #ifndef __PERF_TOOL_H |
2 | #define __PERF_TOOL_H | 2 | #define __PERF_TOOL_H |
3 | 3 | ||
4 | #include <stdbool.h> | ||
5 | |||
4 | struct perf_session; | 6 | struct perf_session; |
7 | union perf_event; | ||
8 | struct perf_evlist; | ||
5 | struct perf_evsel; | 9 | struct perf_evsel; |
10 | struct perf_sample; | ||
6 | struct perf_tool; | 11 | struct perf_tool; |
7 | struct machine; | 12 | struct machine; |
8 | 13 | ||