aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-11-28 14:57:40 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-11-28 14:57:40 -0500
commitee29be625bd7b115d45eba4b0526ff3e24bf3ca0 (patch)
tree1ef1189e0fe02511642e5f74f463d888dfa34bec /tools/perf
parente7984b7bee2fca8f582f5bc2bf1e6c93420a5dd5 (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')
-rw-r--r--tools/perf/builtin-sched.c149
-rw-r--r--tools/perf/util/evlist.c42
-rw-r--r--tools/perf/util/evlist.h11
-rw-r--r--tools/perf/util/evsel.h4
-rw-r--r--tools/perf/util/tool.h5
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)
1358static struct trace_sched_handler *trace_handler; 1359static struct trace_sched_handler *trace_handler;
1359 1360
1360static void 1361static void
1361process_sched_wakeup_event(void *data, struct machine *machine, 1362process_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
1475static void 1476static void
1476process_sched_switch_event(void *data, struct machine *machine, 1477process_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
1509static void 1512static void
1510process_sched_runtime_event(void *data, struct machine *machine, 1513process_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
1527static void 1532static void
1528process_sched_fork_event(void *data, 1533process_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
1548static void 1554static void
1549process_sched_exit_event(struct event *event, 1555process_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
1558static void 1565static void
1559process_sched_migrate_task_event(void *data, struct machine *machine, 1566process_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
1579static void process_raw_event(union perf_event *raw_event __used, 1588typedef 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
1606static int process_sample_event(struct perf_tool *tool __used, 1593static 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
1635static struct perf_tool perf_sched = { 1622static 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 = {
1643static void read_events(bool destroy, struct perf_session **psession) 1630static 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
210static 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
224int 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;
248out:
249 return err;
250}
251
210void perf_evlist__disable(struct perf_evlist *evlist) 252void 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
39struct perf_evsel_str_handler {
40 const char *name;
41 void *handler;
42};
43
39struct perf_evsel; 44struct perf_evsel;
40 45
41struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 46struct 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);
52int perf_evlist__add_tracepoints(struct perf_evlist *evlist, 57int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
53 const char *tracepoints[], size_t nr_tracepoints); 58 const char *tracepoints[], size_t nr_tracepoints);
59int 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
61void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, 72void 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
4struct perf_session; 6struct perf_session;
7union perf_event;
8struct perf_evlist;
5struct perf_evsel; 9struct perf_evsel;
10struct perf_sample;
6struct perf_tool; 11struct perf_tool;
7struct machine; 12struct machine;
8 13