diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-11-28 14:57:40 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-11-28 14:57:40 -0500 |
commit | ee29be625bd7b115d45eba4b0526ff3e24bf3ca0 (patch) | |
tree | 1ef1189e0fe02511642e5f74f463d888dfa34bec /tools/perf/builtin-sched.c | |
parent | e7984b7bee2fca8f582f5bc2bf1e6c93420a5dd5 (diff) |
perf tools: Save some loops using perf_evlist__id2evsel
Since we already ask for PERF_SAMPLE_ID and use it to quickly find the
associated evsel, add handler func + data to struct perf_evsel to avoid
using chains of if(strcmp(event_name)) and also to avoid all the linear
list searches via trace_event_find.
To demonstrate the technique convert 'perf sched' to it:
# perf sched record sleep 5m
And then:
Performance counter stats for '/tmp/oldperf sched lat':
646.929438 task-clock # 0.999 CPUs utilized
9 context-switches # 0.000 M/sec
0 CPU-migrations # 0.000 M/sec
20,901 page-faults # 0.032 M/sec
1,290,144,450 cycles # 1.994 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
1,606,158,439 instructions # 1.24 insns per cycle
339,088,395 branches # 524.151 M/sec
4,550,735 branch-misses # 1.34% of all branches
0.647524759 seconds time elapsed
Versus:
Performance counter stats for 'perf sched lat':
473.564691 task-clock # 0.999 CPUs utilized
9 context-switches # 0.000 M/sec
0 CPU-migrations # 0.000 M/sec
20,903 page-faults # 0.044 M/sec
944,367,984 cycles # 1.994 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
1,442,385,571 instructions # 1.53 insns per cycle
308,383,106 branches # 651.195 M/sec
4,481,784 branch-misses # 1.45% of all branches
0.474215751 seconds time elapsed
[root@emilia ~]#
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-1kbzpl74lwi6lavpqke2u2p3@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-sched.c')
-rw-r--r-- | tools/perf/builtin-sched.c | 149 |
1 files changed, 74 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) |