aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile15
-rw-r--r--tools/hv/hv_kvp_daemon.c29
-rw-r--r--tools/hv/hv_vss_daemon.c8
-rw-r--r--tools/lib/traceevent/Makefile18
-rw-r--r--tools/lib/traceevent/event-parse.c178
-rw-r--r--tools/lib/traceevent/event-parse.h14
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/Documentation/Makefile79
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt13
-rw-r--r--tools/perf/Documentation/perf-kvm.txt4
-rw-r--r--tools/perf/Documentation/perf-lock.txt2
-rw-r--r--tools/perf/Documentation/perf-record.txt31
-rw-r--r--tools/perf/Documentation/perf-report.txt16
-rw-r--r--tools/perf/Documentation/perf-stat.txt5
-rw-r--r--tools/perf/Documentation/perf-timechart.txt15
-rw-r--r--tools/perf/Documentation/perf-top.txt33
-rw-r--r--tools/perf/Documentation/perf-trace.txt37
-rw-r--r--tools/perf/Makefile848
-rw-r--r--tools/perf/Makefile.perf892
-rw-r--r--tools/perf/arch/arm/Makefile3
-rw-r--r--tools/perf/arch/arm/include/perf_regs.h54
-rw-r--r--tools/perf/arch/arm/util/unwind.c48
-rw-r--r--tools/perf/arch/x86/include/perf_regs.h6
-rw-r--r--tools/perf/arch/x86/util/unwind.c4
-rw-r--r--tools/perf/bash_completion106
-rw-r--r--tools/perf/bench/mem-memcpy-arch.h2
-rw-r--r--tools/perf/bench/mem-memcpy.c2
-rw-r--r--tools/perf/bench/mem-memset-arch.h2
-rw-r--r--tools/perf/bench/mem-memset.c2
-rw-r--r--tools/perf/bench/numa.c38
-rw-r--r--tools/perf/bench/sched-pipe.c115
-rw-r--r--tools/perf/builtin-annotate.c45
-rw-r--r--tools/perf/builtin-bench.c245
-rw-r--r--tools/perf/builtin-buildid-cache.c156
-rw-r--r--tools/perf/builtin-buildid-list.c11
-rw-r--r--tools/perf/builtin-diff.c31
-rw-r--r--tools/perf/builtin-evlist.c7
-rw-r--r--tools/perf/builtin-inject.c46
-rw-r--r--tools/perf/builtin-kmem.c13
-rw-r--r--tools/perf/builtin-kvm.c57
-rw-r--r--tools/perf/builtin-list.c84
-rw-r--r--tools/perf/builtin-lock.c137
-rw-r--r--tools/perf/builtin-mem.c9
-rw-r--r--tools/perf/builtin-probe.c16
-rw-r--r--tools/perf/builtin-record.c274
-rw-r--r--tools/perf/builtin-report.c124
-rw-r--r--tools/perf/builtin-sched.c70
-rw-r--r--tools/perf/builtin-script.c127
-rw-r--r--tools/perf/builtin-stat.c224
-rw-r--r--tools/perf/builtin-timechart.c14
-rw-r--r--tools/perf/builtin-top.c122
-rw-r--r--tools/perf/builtin-trace.c1488
-rw-r--r--tools/perf/config/Makefile389
-rw-r--r--tools/perf/config/feature-checks/Makefile152
-rw-r--r--tools/perf/config/feature-checks/test-all.c111
-rw-r--r--tools/perf/config/feature-checks/test-backtrace.c13
-rw-r--r--tools/perf/config/feature-checks/test-bionic.c6
-rw-r--r--tools/perf/config/feature-checks/test-cplus-demangle.c14
-rw-r--r--tools/perf/config/feature-checks/test-dwarf.c10
-rw-r--r--tools/perf/config/feature-checks/test-fortify-source.c6
-rw-r--r--tools/perf/config/feature-checks/test-glibc.c8
-rw-r--r--tools/perf/config/feature-checks/test-gtk2-infobar.c11
-rw-r--r--tools/perf/config/feature-checks/test-gtk2.c10
-rw-r--r--tools/perf/config/feature-checks/test-hello.c6
-rw-r--r--tools/perf/config/feature-checks/test-libaudit.c10
-rw-r--r--tools/perf/config/feature-checks/test-libbfd.c15
-rw-r--r--tools/perf/config/feature-checks/test-libelf-getphdrnum.c8
-rw-r--r--tools/perf/config/feature-checks/test-libelf-mmap.c8
-rw-r--r--tools/perf/config/feature-checks/test-libelf.c8
-rw-r--r--tools/perf/config/feature-checks/test-libnuma.c9
-rw-r--r--tools/perf/config/feature-checks/test-libperl.c9
-rw-r--r--tools/perf/config/feature-checks/test-libpython-version.c10
-rw-r--r--tools/perf/config/feature-checks/test-libpython.c8
-rw-r--r--tools/perf/config/feature-checks/test-libslang.c6
-rw-r--r--tools/perf/config/feature-checks/test-libunwind-debug-frame.c16
-rw-r--r--tools/perf/config/feature-checks/test-libunwind.c27
-rw-r--r--tools/perf/config/feature-checks/test-on-exit.c16
-rw-r--r--tools/perf/config/feature-checks/test-stackprotector-all.c6
-rw-r--r--tools/perf/config/feature-checks/test-stackprotector.c6
-rw-r--r--tools/perf/config/feature-checks/test-timerfd.c18
-rw-r--r--tools/perf/config/feature-checks/test-volatile-register-var.c6
-rw-r--r--tools/perf/config/feature-tests.mak246
-rw-r--r--tools/perf/config/utilities.mak17
-rw-r--r--tools/perf/perf.c14
-rw-r--r--tools/perf/perf.h67
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/Context.c6
-rw-r--r--tools/perf/tests/attr/README6
-rw-r--r--tools/perf/tests/attr/test-record-graph-default2
-rw-r--r--tools/perf/tests/attr/test-record-graph-dwarf2
-rw-r--r--tools/perf/tests/attr/test-record-graph-fp2
-rw-r--r--tools/perf/tests/code-reading.c18
-rw-r--r--tools/perf/tests/dso-data.c1
-rw-r--r--tools/perf/tests/evsel-tp-sched.c4
-rw-r--r--tools/perf/tests/hists_link.c14
-rw-r--r--tools/perf/tests/keep-tracking.c1
-rw-r--r--tools/perf/tests/mmap-basic.c3
-rw-r--r--tools/perf/tests/open-syscall-all-cpus.c2
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c6
-rw-r--r--tools/perf/tests/open-syscall.c2
-rw-r--r--tools/perf/tests/parse-events.c9
-rw-r--r--tools/perf/tests/perf-record.c14
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c4
-rw-r--r--tools/perf/tests/rdpmc.c2
-rw-r--r--tools/perf/tests/sample-parsing.c11
-rw-r--r--tools/perf/tests/sw-clock.c19
-rw-r--r--tools/perf/tests/task-exit.c22
-rw-r--r--tools/perf/ui/browser.c4
-rw-r--r--tools/perf/ui/browser.h32
-rw-r--r--tools/perf/ui/browsers/annotate.c24
-rw-r--r--tools/perf/ui/browsers/hists.c23
-rw-r--r--tools/perf/ui/browsers/map.c40
-rw-r--r--tools/perf/ui/browsers/map.h2
-rw-r--r--tools/perf/ui/browsers/scripts.c8
-rw-r--r--tools/perf/ui/gtk/annotate.c13
-rw-r--r--tools/perf/ui/gtk/browser.c2
-rw-r--r--tools/perf/ui/gtk/gtk.h22
-rw-r--r--tools/perf/ui/gtk/progress.c20
-rw-r--r--tools/perf/ui/gtk/setup.c2
-rw-r--r--tools/perf/ui/gtk/util.c4
-rw-r--r--tools/perf/ui/hist.c2
-rw-r--r--tools/perf/ui/progress.c32
-rw-r--r--tools/perf/ui/progress.h19
-rw-r--r--tools/perf/ui/setup.c61
-rw-r--r--tools/perf/ui/stdio/hist.c23
-rw-r--r--tools/perf/ui/tui/progress.c18
-rw-r--r--tools/perf/ui/tui/setup.c3
-rw-r--r--tools/perf/ui/tui/tui.h6
-rw-r--r--tools/perf/ui/ui.h14
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN5
-rw-r--r--tools/perf/util/annotate.c76
-rw-r--r--tools/perf/util/annotate.h26
-rw-r--r--tools/perf/util/build-id.c6
-rw-r--r--tools/perf/util/build-id.h3
-rw-r--r--tools/perf/util/cache.h3
-rw-r--r--tools/perf/util/callchain.c147
-rw-r--r--tools/perf/util/callchain.h14
-rw-r--r--tools/perf/util/color.c11
-rw-r--r--tools/perf/util/color.h2
-rw-r--r--tools/perf/util/comm.c121
-rw-r--r--tools/perf/util/comm.h21
-rw-r--r--tools/perf/util/cpumap.c6
-rw-r--r--tools/perf/util/data.c120
-rw-r--r--tools/perf/util/data.h48
-rw-r--r--tools/perf/util/dso.c50
-rw-r--r--tools/perf/util/dso.h3
-rw-r--r--tools/perf/util/event.c124
-rw-r--r--tools/perf/util/event.h18
-rw-r--r--tools/perf/util/evlist.c301
-rw-r--r--tools/perf/util/evlist.h26
-rw-r--r--tools/perf/util/evsel.c43
-rw-r--r--tools/perf/util/evsel.h34
-rw-r--r--tools/perf/util/fs.c119
-rw-r--r--tools/perf/util/fs.h7
-rwxr-xr-xtools/perf/util/generate-cmdlist.sh4
-rw-r--r--tools/perf/util/header.c26
-rw-r--r--tools/perf/util/hist.c95
-rw-r--r--tools/perf/util/hist.h88
-rw-r--r--tools/perf/util/include/dwarf-regs.h2
-rw-r--r--tools/perf/util/include/linux/compiler.h19
-rw-r--r--tools/perf/util/include/linux/magic.h4
-rw-r--r--tools/perf/util/intlist.c23
-rw-r--r--tools/perf/util/intlist.h2
-rw-r--r--tools/perf/util/machine.c180
-rw-r--r--tools/perf/util/machine.h41
-rw-r--r--tools/perf/util/map.c50
-rw-r--r--tools/perf/util/map.h7
-rw-r--r--tools/perf/util/parse-events.c10
-rw-r--r--tools/perf/util/parse-events.l63
-rw-r--r--tools/perf/util/parse-options.c218
-rw-r--r--tools/perf/util/parse-options.h4
-rw-r--r--tools/perf/util/path.c10
-rw-r--r--tools/perf/util/perf_regs.h4
-rw-r--r--tools/perf/util/pmu.c33
-rw-r--r--tools/perf/util/pmu.h1
-rw-r--r--tools/perf/util/probe-event.c5
-rw-r--r--tools/perf/util/probe-finder.c250
-rw-r--r--tools/perf/util/probe-finder.h15
-rw-r--r--tools/perf/util/pstack.h10
-rw-r--r--tools/perf/util/python-ext-sources2
-rw-r--r--tools/perf/util/python.c10
-rw-r--r--tools/perf/util/rblist.c27
-rw-r--r--tools/perf/util/rblist.h1
-rw-r--r--tools/perf/util/record.c71
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c4
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c41
-rw-r--r--tools/perf/util/session.c278
-rw-r--r--tools/perf/util/session.h38
-rw-r--r--tools/perf/util/sort.c331
-rw-r--r--tools/perf/util/sort.h8
-rw-r--r--tools/perf/util/srcline.c265
-rw-r--r--tools/perf/util/strfilter.c72
-rw-r--r--tools/perf/util/strfilter.h12
-rw-r--r--tools/perf/util/symbol-elf.c607
-rw-r--r--tools/perf/util/symbol-minimal.c15
-rw-r--r--tools/perf/util/symbol.c449
-rw-r--r--tools/perf/util/symbol.h29
-rw-r--r--tools/perf/util/sysfs.c60
-rw-r--r--tools/perf/util/sysfs.h6
-rw-r--r--tools/perf/util/target.c54
-rw-r--r--tools/perf/util/target.h45
-rw-r--r--tools/perf/util/thread.c137
-rw-r--r--tools/perf/util/thread.h20
-rw-r--r--tools/perf/util/top.c2
-rw-r--r--tools/perf/util/top.h1
-rw-r--r--tools/perf/util/trace-event-parse.c36
-rw-r--r--tools/perf/util/trace-event.h9
-rw-r--r--tools/perf/util/unwind.c84
-rw-r--r--tools/perf/util/unwind.h9
-rw-r--r--tools/perf/util/util.c66
-rw-r--r--tools/perf/util/util.h26
-rw-r--r--tools/power/cpupower/man/cpupower-idle-info.13
-rw-r--r--tools/power/cpupower/man/cpupower-idle-set.171
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c4
-rw-r--r--tools/power/x86/turbostat/turbostat.c197
-rw-r--r--tools/scripts/Makefile.include23
-rw-r--r--tools/testing/ktest/examples/crosstests.conf6
-rw-r--r--tools/testing/selftests/timers/posix_timers.c2
-rw-r--r--tools/thermal/tmon/Makefile47
-rw-r--r--tools/thermal/tmon/README50
-rw-r--r--tools/thermal/tmon/pid.c131
-rw-r--r--tools/thermal/tmon/sysfs.c596
-rw-r--r--tools/thermal/tmon/tmon.8142
-rw-r--r--tools/thermal/tmon/tmon.c352
-rw-r--r--tools/thermal/tmon/tmon.h204
-rw-r--r--tools/thermal/tmon/tui.c638
-rw-r--r--tools/virtio/virtio_test.c6
-rw-r--r--tools/virtio/vringh_test.c13
-rw-r--r--tools/vm/page-types.c32
228 files changed, 11542 insertions, 3998 deletions
diff --git a/tools/Makefile b/tools/Makefile
index 41067f304215..a9b02008443c 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -15,6 +15,7 @@ help:
15 @echo ' net - misc networking tools' 15 @echo ' net - misc networking tools'
16 @echo ' vm - misc vm tools' 16 @echo ' vm - misc vm tools'
17 @echo ' x86_energy_perf_policy - Intel energy policy tool' 17 @echo ' x86_energy_perf_policy - Intel energy policy tool'
18 @echo ' tmon - thermal monitoring and tuning tool'
18 @echo '' 19 @echo ''
19 @echo 'You can do:' 20 @echo 'You can do:'
20 @echo ' $$ make -C tools/ <tool>_install' 21 @echo ' $$ make -C tools/ <tool>_install'
@@ -50,6 +51,9 @@ selftests: FORCE
50turbostat x86_energy_perf_policy: FORCE 51turbostat x86_energy_perf_policy: FORCE
51 $(call descend,power/x86/$@) 52 $(call descend,power/x86/$@)
52 53
54tmon: FORCE
55 $(call descend,thermal/$@)
56
53cpupower_install: 57cpupower_install:
54 $(call descend,power/$(@:_install=),install) 58 $(call descend,power/$(@:_install=),install)
55 59
@@ -62,9 +66,13 @@ selftests_install:
62turbostat_install x86_energy_perf_policy_install: 66turbostat_install x86_energy_perf_policy_install:
63 $(call descend,power/x86/$(@:_install=),install) 67 $(call descend,power/x86/$(@:_install=),install)
64 68
69tmon_install:
70 $(call descend,thermal/$(@:_install=),install)
71
65install: cgroup_install cpupower_install firewire_install lguest_install \ 72install: cgroup_install cpupower_install firewire_install lguest_install \
66 perf_install selftests_install turbostat_install usb_install \ 73 perf_install selftests_install turbostat_install usb_install \
67 virtio_install vm_install net_install x86_energy_perf_policy_install 74 virtio_install vm_install net_install x86_energy_perf_policy_install \
75 tmon
68 76
69cpupower_clean: 77cpupower_clean:
70 $(call descend,power/cpupower,clean) 78 $(call descend,power/cpupower,clean)
@@ -84,8 +92,11 @@ selftests_clean:
84turbostat_clean x86_energy_perf_policy_clean: 92turbostat_clean x86_energy_perf_policy_clean:
85 $(call descend,power/x86/$(@:_clean=),clean) 93 $(call descend,power/x86/$(@:_clean=),clean)
86 94
95tmon_clean:
96 $(call descend,thermal/tmon,clean)
97
87clean: cgroup_clean cpupower_clean firewire_clean lguest_clean perf_clean \ 98clean: cgroup_clean cpupower_clean firewire_clean lguest_clean perf_clean \
88 selftests_clean turbostat_clean usb_clean virtio_clean \ 99 selftests_clean turbostat_clean usb_clean virtio_clean \
89 vm_clean net_clean x86_energy_perf_policy_clean 100 vm_clean net_clean x86_energy_perf_policy_clean tmon_clean
90 101
91.PHONY: FORCE 102.PHONY: FORCE
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 8fd9ec66121c..b8d6d541d854 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -89,6 +89,7 @@ static char *processor_arch;
89static char *os_build; 89static char *os_build;
90static char *os_version; 90static char *os_version;
91static char *lic_version = "Unknown version"; 91static char *lic_version = "Unknown version";
92static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
92static struct utsname uts_buf; 93static struct utsname uts_buf;
93 94
94/* 95/*
@@ -1367,7 +1368,7 @@ setval_error:
1367} 1368}
1368 1369
1369 1370
1370static int 1371static void
1371kvp_get_domain_name(char *buffer, int length) 1372kvp_get_domain_name(char *buffer, int length)
1372{ 1373{
1373 struct addrinfo hints, *info ; 1374 struct addrinfo hints, *info ;
@@ -1381,12 +1382,12 @@ kvp_get_domain_name(char *buffer, int length)
1381 1382
1382 error = getaddrinfo(buffer, NULL, &hints, &info); 1383 error = getaddrinfo(buffer, NULL, &hints, &info);
1383 if (error != 0) { 1384 if (error != 0) {
1384 strcpy(buffer, "getaddrinfo failed\n"); 1385 snprintf(buffer, length, "getaddrinfo failed: 0x%x %s",
1385 return error; 1386 error, gai_strerror(error));
1387 return;
1386 } 1388 }
1387 strcpy(buffer, info->ai_canonname); 1389 snprintf(buffer, length, "%s", info->ai_canonname);
1388 freeaddrinfo(info); 1390 freeaddrinfo(info);
1389 return error;
1390} 1391}
1391 1392
1392static int 1393static int
@@ -1433,7 +1434,6 @@ int main(void)
1433 int pool; 1434 int pool;
1434 char *if_name; 1435 char *if_name;
1435 struct hv_kvp_ipaddr_value *kvp_ip_val; 1436 struct hv_kvp_ipaddr_value *kvp_ip_val;
1436 char *kvp_send_buffer;
1437 char *kvp_recv_buffer; 1437 char *kvp_recv_buffer;
1438 size_t kvp_recv_buffer_len; 1438 size_t kvp_recv_buffer_len;
1439 1439
@@ -1442,17 +1442,21 @@ int main(void)
1442 openlog("KVP", 0, LOG_USER); 1442 openlog("KVP", 0, LOG_USER);
1443 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); 1443 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1444 1444
1445 kvp_recv_buffer_len = NLMSG_HDRLEN + sizeof(struct cn_msg) + sizeof(struct hv_kvp_msg); 1445 kvp_recv_buffer_len = NLMSG_LENGTH(0) + sizeof(struct cn_msg) + sizeof(struct hv_kvp_msg);
1446 kvp_send_buffer = calloc(1, kvp_recv_buffer_len);
1447 kvp_recv_buffer = calloc(1, kvp_recv_buffer_len); 1446 kvp_recv_buffer = calloc(1, kvp_recv_buffer_len);
1448 if (!(kvp_send_buffer && kvp_recv_buffer)) { 1447 if (!kvp_recv_buffer) {
1449 syslog(LOG_ERR, "Failed to allocate netlink buffers"); 1448 syslog(LOG_ERR, "Failed to allocate netlink buffer");
1450 exit(EXIT_FAILURE); 1449 exit(EXIT_FAILURE);
1451 } 1450 }
1452 /* 1451 /*
1453 * Retrieve OS release information. 1452 * Retrieve OS release information.
1454 */ 1453 */
1455 kvp_get_os_info(); 1454 kvp_get_os_info();
1455 /*
1456 * Cache Fully Qualified Domain Name because getaddrinfo takes an
1457 * unpredictable amount of time to finish.
1458 */
1459 kvp_get_domain_name(full_domain_name, sizeof(full_domain_name));
1456 1460
1457 if (kvp_file_init()) { 1461 if (kvp_file_init()) {
1458 syslog(LOG_ERR, "Failed to initialize the pools"); 1462 syslog(LOG_ERR, "Failed to initialize the pools");
@@ -1488,7 +1492,7 @@ int main(void)
1488 /* 1492 /*
1489 * Register ourselves with the kernel. 1493 * Register ourselves with the kernel.
1490 */ 1494 */
1491 message = (struct cn_msg *)kvp_send_buffer; 1495 message = (struct cn_msg *)kvp_recv_buffer;
1492 message->id.idx = CN_KVP_IDX; 1496 message->id.idx = CN_KVP_IDX;
1493 message->id.val = CN_KVP_VAL; 1497 message->id.val = CN_KVP_VAL;
1494 1498
@@ -1671,8 +1675,7 @@ int main(void)
1671 1675
1672 switch (hv_msg->body.kvp_enum_data.index) { 1676 switch (hv_msg->body.kvp_enum_data.index) {
1673 case FullyQualifiedDomainName: 1677 case FullyQualifiedDomainName:
1674 kvp_get_domain_name(key_value, 1678 strcpy(key_value, full_domain_name);
1675 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1676 strcpy(key_name, "FullyQualifiedDomainName"); 1679 strcpy(key_name, "FullyQualifiedDomainName");
1677 break; 1680 break;
1678 case IntegrationServicesVersion: 1681 case IntegrationServicesVersion:
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index 8611962c672c..8bcb04096eb2 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -140,7 +140,6 @@ int main(void)
140 struct cn_msg *incoming_cn_msg; 140 struct cn_msg *incoming_cn_msg;
141 int op; 141 int op;
142 struct hv_vss_msg *vss_msg; 142 struct hv_vss_msg *vss_msg;
143 char *vss_send_buffer;
144 char *vss_recv_buffer; 143 char *vss_recv_buffer;
145 size_t vss_recv_buffer_len; 144 size_t vss_recv_buffer_len;
146 145
@@ -150,10 +149,9 @@ int main(void)
150 openlog("Hyper-V VSS", 0, LOG_USER); 149 openlog("Hyper-V VSS", 0, LOG_USER);
151 syslog(LOG_INFO, "VSS starting; pid is:%d", getpid()); 150 syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
152 151
153 vss_recv_buffer_len = NLMSG_HDRLEN + sizeof(struct cn_msg) + sizeof(struct hv_vss_msg); 152 vss_recv_buffer_len = NLMSG_LENGTH(0) + sizeof(struct cn_msg) + sizeof(struct hv_vss_msg);
154 vss_send_buffer = calloc(1, vss_recv_buffer_len);
155 vss_recv_buffer = calloc(1, vss_recv_buffer_len); 153 vss_recv_buffer = calloc(1, vss_recv_buffer_len);
156 if (!(vss_send_buffer && vss_recv_buffer)) { 154 if (!vss_recv_buffer) {
157 syslog(LOG_ERR, "Failed to allocate netlink buffers"); 155 syslog(LOG_ERR, "Failed to allocate netlink buffers");
158 exit(EXIT_FAILURE); 156 exit(EXIT_FAILURE);
159 } 157 }
@@ -185,7 +183,7 @@ int main(void)
185 /* 183 /*
186 * Register ourselves with the kernel. 184 * Register ourselves with the kernel.
187 */ 185 */
188 message = (struct cn_msg *)vss_send_buffer; 186 message = (struct cn_msg *)vss_recv_buffer;
189 message->id.idx = CN_VSS_IDX; 187 message->id.idx = CN_VSS_IDX;
190 message->id.val = CN_VSS_VAL; 188 message->id.val = CN_VSS_VAL;
191 message->ack = 0; 189 message->ack = 0;
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index ca6cb779876a..fc1502098595 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -134,14 +134,14 @@ ifeq ($(VERBOSE),1)
134 print_install = 134 print_install =
135else 135else
136 Q = @ 136 Q = @
137 print_compile = echo ' CC '$(OBJ); 137 print_compile = echo ' CC '$(OBJ);
138 print_app_build = echo ' BUILD '$(OBJ); 138 print_app_build = echo ' BUILD '$(OBJ);
139 print_fpic_compile = echo ' CC FPIC '$(OBJ); 139 print_fpic_compile = echo ' CC FPIC '$(OBJ);
140 print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ); 140 print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
141 print_plugin_obj_compile = echo ' CC PLUGIN OBJ '$(OBJ); 141 print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ);
142 print_plugin_build = echo ' CC PLUGI '$(OBJ); 142 print_plugin_build = echo ' BUILD PLUGIN '$(OBJ);
143 print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ); 143 print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ);
144 print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; 144 print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2';
145endif 145endif
146 146
147do_fpic_compile = \ 147do_fpic_compile = \
@@ -268,7 +268,7 @@ TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE)
268TRACEEVENT-CFLAGS: force 268TRACEEVENT-CFLAGS: force
269 @FLAGS='$(TRACK_CFLAGS)'; \ 269 @FLAGS='$(TRACK_CFLAGS)'; \
270 if test x"$$FLAGS" != x"`cat TRACEEVENT-CFLAGS 2>/dev/null`" ; then \ 270 if test x"$$FLAGS" != x"`cat TRACEEVENT-CFLAGS 2>/dev/null`" ; then \
271 echo 1>&2 " * new build flags or cross compiler"; \ 271 echo 1>&2 " FLAGS: * new build flags or cross compiler"; \
272 echo "$$FLAGS" >TRACEEVENT-CFLAGS; \ 272 echo "$$FLAGS" >TRACEEVENT-CFLAGS; \
273 fi 273 fi
274 274
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index d1c2a6a4cd32..0362d575de7d 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -305,6 +305,11 @@ int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
305 return 0; 305 return 0;
306} 306}
307 307
308void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock)
309{
310 pevent->trace_clock = trace_clock;
311}
312
308struct func_map { 313struct func_map {
309 unsigned long long addr; 314 unsigned long long addr;
310 char *func; 315 char *func;
@@ -599,10 +604,11 @@ find_printk(struct pevent *pevent, unsigned long long addr)
599 * This registers a string by the address it was stored in the kernel. 604 * This registers a string by the address it was stored in the kernel.
600 * The @fmt passed in is duplicated. 605 * The @fmt passed in is duplicated.
601 */ 606 */
602int pevent_register_print_string(struct pevent *pevent, char *fmt, 607int pevent_register_print_string(struct pevent *pevent, const char *fmt,
603 unsigned long long addr) 608 unsigned long long addr)
604{ 609{
605 struct printk_list *item = malloc(sizeof(*item)); 610 struct printk_list *item = malloc(sizeof(*item));
611 char *p;
606 612
607 if (!item) 613 if (!item)
608 return -1; 614 return -1;
@@ -610,10 +616,21 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt,
610 item->next = pevent->printklist; 616 item->next = pevent->printklist;
611 item->addr = addr; 617 item->addr = addr;
612 618
619 /* Strip off quotes and '\n' from the end */
620 if (fmt[0] == '"')
621 fmt++;
613 item->printk = strdup(fmt); 622 item->printk = strdup(fmt);
614 if (!item->printk) 623 if (!item->printk)
615 goto out_free; 624 goto out_free;
616 625
626 p = item->printk + strlen(item->printk) - 1;
627 if (*p == '"')
628 *p = 0;
629
630 p -= 2;
631 if (strcmp(p, "\\n") == 0)
632 *p = 0;
633
617 pevent->printklist = item; 634 pevent->printklist = item;
618 pevent->printk_count++; 635 pevent->printk_count++;
619 636
@@ -3418,6 +3435,19 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg
3418 goto out_warning_op; 3435 goto out_warning_op;
3419 } 3436 }
3420 break; 3437 break;
3438 case PRINT_DYNAMIC_ARRAY:
3439 /* Without [], we pass the address to the dynamic data */
3440 offset = pevent_read_number(pevent,
3441 data + arg->dynarray.field->offset,
3442 arg->dynarray.field->size);
3443 /*
3444 * The actual length of the dynamic array is stored
3445 * in the top half of the field, and the offset
3446 * is in the bottom half of the 32 bit field.
3447 */
3448 offset &= 0xffff;
3449 val = (unsigned long long)(data + offset);
3450 break;
3421 default: /* not sure what to do there */ 3451 default: /* not sure what to do there */
3422 return 0; 3452 return 0;
3423 } 3453 }
@@ -3488,6 +3518,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
3488 struct pevent *pevent = event->pevent; 3518 struct pevent *pevent = event->pevent;
3489 struct print_flag_sym *flag; 3519 struct print_flag_sym *flag;
3490 struct format_field *field; 3520 struct format_field *field;
3521 struct printk_map *printk;
3491 unsigned long long val, fval; 3522 unsigned long long val, fval;
3492 unsigned long addr; 3523 unsigned long addr;
3493 char *str; 3524 char *str;
@@ -3523,7 +3554,12 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
3523 if (!(field->flags & FIELD_IS_ARRAY) && 3554 if (!(field->flags & FIELD_IS_ARRAY) &&
3524 field->size == pevent->long_size) { 3555 field->size == pevent->long_size) {
3525 addr = *(unsigned long *)(data + field->offset); 3556 addr = *(unsigned long *)(data + field->offset);
3526 trace_seq_printf(s, "%lx", addr); 3557 /* Check if it matches a print format */
3558 printk = find_printk(pevent, addr);
3559 if (printk)
3560 trace_seq_puts(s, printk->printk);
3561 else
3562 trace_seq_printf(s, "%lx", addr);
3527 break; 3563 break;
3528 } 3564 }
3529 str = malloc(len + 1); 3565 str = malloc(len + 1);
@@ -3565,15 +3601,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
3565 } 3601 }
3566 break; 3602 break;
3567 case PRINT_HEX: 3603 case PRINT_HEX:
3568 field = arg->hex.field->field.field; 3604 if (arg->hex.field->type == PRINT_DYNAMIC_ARRAY) {
3569 if (!field) { 3605 unsigned long offset;
3570 str = arg->hex.field->field.name; 3606 offset = pevent_read_number(pevent,
3571 field = pevent_find_any_field(event, str); 3607 data + arg->hex.field->dynarray.field->offset,
3572 if (!field) 3608 arg->hex.field->dynarray.field->size);
3573 goto out_warning_field; 3609 hex = data + (offset & 0xffff);
3574 arg->hex.field->field.field = field; 3610 } else {
3611 field = arg->hex.field->field.field;
3612 if (!field) {
3613 str = arg->hex.field->field.name;
3614 field = pevent_find_any_field(event, str);
3615 if (!field)
3616 goto out_warning_field;
3617 arg->hex.field->field.field = field;
3618 }
3619 hex = data + field->offset;
3575 } 3620 }
3576 hex = data + field->offset;
3577 len = eval_num_arg(data, size, event, arg->hex.size); 3621 len = eval_num_arg(data, size, event, arg->hex.size);
3578 for (i = 0; i < len; i++) { 3622 for (i = 0; i < len; i++) {
3579 if (i) 3623 if (i)
@@ -3771,8 +3815,8 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
3771 if (asprintf(&arg->atom.atom, "%lld", ip) < 0) 3815 if (asprintf(&arg->atom.atom, "%lld", ip) < 0)
3772 goto out_free; 3816 goto out_free;
3773 3817
3774 /* skip the first "%pf : " */ 3818 /* skip the first "%pf: " */
3775 for (ptr = fmt + 6, bptr = data + field->offset; 3819 for (ptr = fmt + 5, bptr = data + field->offset;
3776 bptr < data + size && *ptr; ptr++) { 3820 bptr < data + size && *ptr; ptr++) {
3777 int ls = 0; 3821 int ls = 0;
3778 3822
@@ -3882,7 +3926,6 @@ get_bprint_format(void *data, int size __maybe_unused,
3882 struct format_field *field; 3926 struct format_field *field;
3883 struct printk_map *printk; 3927 struct printk_map *printk;
3884 char *format; 3928 char *format;
3885 char *p;
3886 3929
3887 field = pevent->bprint_fmt_field; 3930 field = pevent->bprint_fmt_field;
3888 3931
@@ -3899,25 +3942,13 @@ get_bprint_format(void *data, int size __maybe_unused,
3899 3942
3900 printk = find_printk(pevent, addr); 3943 printk = find_printk(pevent, addr);
3901 if (!printk) { 3944 if (!printk) {
3902 if (asprintf(&format, "%%pf : (NO FORMAT FOUND at %llx)\n", addr) < 0) 3945 if (asprintf(&format, "%%pf: (NO FORMAT FOUND at %llx)\n", addr) < 0)
3903 return NULL; 3946 return NULL;
3904 return format; 3947 return format;
3905 } 3948 }
3906 3949
3907 p = printk->printk; 3950 if (asprintf(&format, "%s: %s", "%pf", printk->printk) < 0)
3908 /* Remove any quotes. */
3909 if (*p == '"')
3910 p++;
3911 if (asprintf(&format, "%s : %s", "%pf", p) < 0)
3912 return NULL; 3951 return NULL;
3913 /* remove ending quotes and new line since we will add one too */
3914 p = format + strlen(format) - 1;
3915 if (*p == '"')
3916 *p = 0;
3917
3918 p -= 2;
3919 if (strcmp(p, "\\n") == 0)
3920 *p = 0;
3921 3952
3922 return format; 3953 return format;
3923} 3954}
@@ -3963,7 +3994,7 @@ static int is_printable_array(char *p, unsigned int len)
3963 unsigned int i; 3994 unsigned int i;
3964 3995
3965 for (i = 0; i < len && p[i]; i++) 3996 for (i = 0; i < len && p[i]; i++)
3966 if (!isprint(p[i])) 3997 if (!isprint(p[i]) && !isspace(p[i]))
3967 return 0; 3998 return 0;
3968 return 1; 3999 return 1;
3969} 4000}
@@ -4428,11 +4459,11 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
4428{ 4459{
4429 int print_pretty = 1; 4460 int print_pretty = 1;
4430 4461
4431 if (event->pevent->print_raw) 4462 if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW))
4432 print_event_fields(s, record->data, record->size, event); 4463 print_event_fields(s, record->data, record->size, event);
4433 else { 4464 else {
4434 4465
4435 if (event->handler) 4466 if (event->handler && !(event->flags & EVENT_FL_NOHANDLE))
4436 print_pretty = event->handler(s, record, event, 4467 print_pretty = event->handler(s, record, event,
4437 event->context); 4468 event->context);
4438 4469
@@ -4443,8 +4474,21 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
4443 trace_seq_terminate(s); 4474 trace_seq_terminate(s);
4444} 4475}
4445 4476
4477static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock)
4478{
4479 if (!use_trace_clock)
4480 return true;
4481
4482 if (!strcmp(trace_clock, "local") || !strcmp(trace_clock, "global")
4483 || !strcmp(trace_clock, "uptime") || !strcmp(trace_clock, "perf"))
4484 return true;
4485
4486 /* trace_clock is setting in tsc or counter mode */
4487 return false;
4488}
4489
4446void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 4490void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
4447 struct pevent_record *record) 4491 struct pevent_record *record, bool use_trace_clock)
4448{ 4492{
4449 static const char *spaces = " "; /* 20 spaces */ 4493 static const char *spaces = " "; /* 20 spaces */
4450 struct event_format *event; 4494 struct event_format *event;
@@ -4457,9 +4501,14 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
4457 int pid; 4501 int pid;
4458 int len; 4502 int len;
4459 int p; 4503 int p;
4504 bool use_usec_format;
4460 4505
4461 secs = record->ts / NSECS_PER_SEC; 4506 use_usec_format = is_timestamp_in_us(pevent->trace_clock,
4462 nsecs = record->ts - secs * NSECS_PER_SEC; 4507 use_trace_clock);
4508 if (use_usec_format) {
4509 secs = record->ts / NSECS_PER_SEC;
4510 nsecs = record->ts - secs * NSECS_PER_SEC;
4511 }
4463 4512
4464 if (record->size < 0) { 4513 if (record->size < 0) {
4465 do_warning("ug! negative record size %d", record->size); 4514 do_warning("ug! negative record size %d", record->size);
@@ -4484,15 +4533,20 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
4484 } else 4533 } else
4485 trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu); 4534 trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
4486 4535
4487 if (pevent->flags & PEVENT_NSEC_OUTPUT) { 4536 if (use_usec_format) {
4488 usecs = nsecs; 4537 if (pevent->flags & PEVENT_NSEC_OUTPUT) {
4489 p = 9; 4538 usecs = nsecs;
4490 } else { 4539 p = 9;
4491 usecs = (nsecs + 500) / NSECS_PER_USEC; 4540 } else {
4492 p = 6; 4541 usecs = (nsecs + 500) / NSECS_PER_USEC;
4493 } 4542 p = 6;
4543 }
4494 4544
4495 trace_seq_printf(s, " %5lu.%0*lu: %s: ", secs, p, usecs, event->name); 4545 trace_seq_printf(s, " %5lu.%0*lu: %s: ",
4546 secs, p, usecs, event->name);
4547 } else
4548 trace_seq_printf(s, " %12llu: %s: ",
4549 record->ts, event->name);
4496 4550
4497 /* Space out the event names evenly. */ 4551 /* Space out the event names evenly. */
4498 len = strlen(event->name); 4552 len = strlen(event->name);
@@ -5326,6 +5380,48 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
5326 return -1; 5380 return -1;
5327} 5381}
5328 5382
5383/**
5384 * pevent_print_func_field - print a field and a format for function pointers
5385 * @s: The seq to print to
5386 * @fmt: The printf format to print the field with.
5387 * @event: the event that the field is for
5388 * @name: The name of the field
5389 * @record: The record with the field name.
5390 * @err: print default error if failed.
5391 *
5392 * Returns: 0 on success, -1 field not found, or 1 if buffer is full.
5393 */
5394int pevent_print_func_field(struct trace_seq *s, const char *fmt,
5395 struct event_format *event, const char *name,
5396 struct pevent_record *record, int err)
5397{
5398 struct format_field *field = pevent_find_field(event, name);
5399 struct pevent *pevent = event->pevent;
5400 unsigned long long val;
5401 struct func_map *func;
5402 char tmp[128];
5403
5404 if (!field)
5405 goto failed;
5406
5407 if (pevent_read_number_field(field, record->data, &val))
5408 goto failed;
5409
5410 func = find_func(pevent, val);
5411
5412 if (func)
5413 snprintf(tmp, 128, "%s/0x%llx", func->func, func->addr - val);
5414 else
5415 sprintf(tmp, "0x%08llx", val);
5416
5417 return trace_seq_printf(s, fmt, tmp);
5418
5419 failed:
5420 if (err)
5421 trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
5422 return -1;
5423}
5424
5329static void free_func_handle(struct pevent_function_handler *func) 5425static void free_func_handle(struct pevent_function_handler *func)
5330{ 5426{
5331 struct pevent_func_params *params; 5427 struct pevent_func_params *params;
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index c37b2026d04a..8d73d2594f65 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -20,6 +20,7 @@
20#ifndef _PARSE_EVENTS_H 20#ifndef _PARSE_EVENTS_H
21#define _PARSE_EVENTS_H 21#define _PARSE_EVENTS_H
22 22
23#include <stdbool.h>
23#include <stdarg.h> 24#include <stdarg.h>
24#include <regex.h> 25#include <regex.h>
25 26
@@ -307,6 +308,8 @@ enum {
307 EVENT_FL_ISBPRINT = 0x04, 308 EVENT_FL_ISBPRINT = 0x04,
308 EVENT_FL_ISFUNCENT = 0x10, 309 EVENT_FL_ISFUNCENT = 0x10,
309 EVENT_FL_ISFUNCRET = 0x20, 310 EVENT_FL_ISFUNCRET = 0x20,
311 EVENT_FL_NOHANDLE = 0x40,
312 EVENT_FL_PRINTRAW = 0x80,
310 313
311 EVENT_FL_FAILED = 0x80000000 314 EVENT_FL_FAILED = 0x80000000
312}; 315};
@@ -450,6 +453,8 @@ struct pevent {
450 453
451 /* cache */ 454 /* cache */
452 struct event_format *last_event; 455 struct event_format *last_event;
456
457 char *trace_clock;
453}; 458};
454 459
455static inline void pevent_set_flag(struct pevent *pevent, int flag) 460static inline void pevent_set_flag(struct pevent *pevent, int flag)
@@ -527,14 +532,15 @@ enum trace_flag_type {
527}; 532};
528 533
529int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); 534int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
535void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock);
530int pevent_register_function(struct pevent *pevent, char *name, 536int pevent_register_function(struct pevent *pevent, char *name,
531 unsigned long long addr, char *mod); 537 unsigned long long addr, char *mod);
532int pevent_register_print_string(struct pevent *pevent, char *fmt, 538int pevent_register_print_string(struct pevent *pevent, const char *fmt,
533 unsigned long long addr); 539 unsigned long long addr);
534int pevent_pid_is_registered(struct pevent *pevent, int pid); 540int pevent_pid_is_registered(struct pevent *pevent, int pid);
535 541
536void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 542void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
537 struct pevent_record *record); 543 struct pevent_record *record, bool use_trace_clock);
538 544
539int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size, 545int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
540 int long_size); 546 int long_size);
@@ -563,6 +569,10 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
563 struct event_format *event, const char *name, 569 struct event_format *event, const char *name,
564 struct pevent_record *record, int err); 570 struct pevent_record *record, int err);
565 571
572int pevent_print_func_field(struct trace_seq *s, const char *fmt,
573 struct event_format *event, const char *name,
574 struct pevent_record *record, int err);
575
566int pevent_register_event_handler(struct pevent *pevent, int id, 576int pevent_register_event_handler(struct pevent *pevent, int id,
567 const char *sys_name, const char *event_name, 577 const char *sys_name, const char *event_name,
568 pevent_event_handler_func func, void *context); 578 pevent_event_handler_func func, void *context);
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 8f8fbc227a46..782d86e961b9 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -13,6 +13,7 @@ perf*.html
13common-cmds.h 13common-cmds.h
14perf.data 14perf.data
15perf.data.old 15perf.data.old
16output.svg
16perf-archive 17perf-archive
17tags 18tags
18TAGS 19TAGS
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index 5a37a7c84e69..3ba1c0b09908 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -145,16 +145,17 @@ endif
145 145
146ifneq ($(findstring $(MAKEFLAGS),s),s) 146ifneq ($(findstring $(MAKEFLAGS),s),s)
147ifneq ($(V),1) 147ifneq ($(V),1)
148 QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@; 148 QUIET_ASCIIDOC = @echo ' ASCIIDOC '$@;
149 QUIET_XMLTO = @echo ' ' XMLTO $@; 149 QUIET_XMLTO = @echo ' XMLTO '$@;
150 QUIET_DB2TEXI = @echo ' ' DB2TEXI $@; 150 QUIET_DB2TEXI = @echo ' DB2TEXI '$@;
151 QUIET_MAKEINFO = @echo ' ' MAKEINFO $@; 151 QUIET_MAKEINFO = @echo ' MAKEINFO '$@;
152 QUIET_DBLATEX = @echo ' ' DBLATEX $@; 152 QUIET_DBLATEX = @echo ' DBLATEX '$@;
153 QUIET_XSLTPROC = @echo ' ' XSLTPROC $@; 153 QUIET_XSLTPROC = @echo ' XSLTPROC '$@;
154 QUIET_GEN = @echo ' ' GEN $@; 154 QUIET_GEN = @echo ' GEN '$@;
155 QUIET_STDERR = 2> /dev/null 155 QUIET_STDERR = 2> /dev/null
156 QUIET_SUBDIR0 = +@subdir= 156 QUIET_SUBDIR0 = +@subdir=
157 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ 157 QUIET_SUBDIR1 = ;$(NO_SUBDIR) \
158 echo ' SUBDIR ' $$subdir; \
158 $(MAKE) $(PRINT_DIR) -C $$subdir 159 $(MAKE) $(PRINT_DIR) -C $$subdir
159 export V 160 export V
160endif 161endif
@@ -183,47 +184,43 @@ ifdef missing_tools
183endif 184endif
184 185
185do-install-man: man 186do-install-man: man
186 $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir) 187 $(call QUIET_INSTALL, Documentation-man) \
187# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir) 188 $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir); \
188# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir) 189# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir); \
189 $(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(man1dir) 190# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir); \
190# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir) 191 $(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(man1dir); \
191# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir) 192# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir); \
193# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
192 194
193install-man: check-man-tools man 195install-man: check-man-tools man
194 196
195try-install-man:
196ifdef missing_tools 197ifdef missing_tools
197 $(warning Please install $(missing_tools) to have the man pages installed) 198 DO_INSTALL_MAN = $(warning Please install $(missing_tools) to have the man pages installed)
198else 199else
199 $(MAKE) do-install-man 200 DO_INSTALL_MAN = do-install-man
200endif 201endif
201 202
203try-install-man: $(DO_INSTALL_MAN)
204
202install-info: info 205install-info: info
203 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir) 206 $(call QUIET_INSTALL, Documentation-info) \
204 $(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir) 207 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir); \
208 $(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir); \
205 if test -r $(DESTDIR)$(infodir)/dir; then \ 209 if test -r $(DESTDIR)$(infodir)/dir; then \
206 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\ 210 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\
207 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\ 211 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\
208 else \ 212 else \
209 echo "No directory found in $(DESTDIR)$(infodir)" >&2 ; \ 213 echo "No directory found in $(DESTDIR)$(infodir)" >&2 ; \
210 fi 214 fi
211 215
212install-pdf: pdf 216install-pdf: pdf
213 $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir) 217 $(call QUIET_INSTALL, Documentation-pdf) \
214 $(INSTALL) -m 644 $(OUTPUT)user-manual.pdf $(DESTDIR)$(pdfdir) 218 $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir); \
219 $(INSTALL) -m 644 $(OUTPUT)user-manual.pdf $(DESTDIR)$(pdfdir)
215 220
216#install-html: html 221#install-html: html
217# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) 222# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
218 223
219ifneq ($(MAKECMDGOALS),clean)
220ifneq ($(MAKECMDGOALS),tags)
221$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
222 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE
223
224-include $(OUTPUT)PERF-VERSION-FILE
225endif
226endif
227 224
228# 225#
229# Determine "include::" file references in asciidoc files. 226# Determine "include::" file references in asciidoc files.
@@ -253,15 +250,17 @@ $(OUTPUT)cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
253 $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \ 250 $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
254 date >$@ 251 date >$@
255 252
253CLEAN_FILES = \
254 $(MAN_XML) $(addsuffix +,$(MAN_XML)) \
255 $(MAN_HTML) $(addsuffix +,$(MAN_HTML)) \
256 $(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7) \
257 $(OUTPUT)*.texi $(OUTPUT)*.texi+ $(OUTPUT)*.texi++ \
258 $(OUTPUT)perf.info $(OUTPUT)perfman.info \
259 $(OUTPUT)howto-index.txt $(OUTPUT)howto/*.html $(OUTPUT)doc.dep \
260 $(OUTPUT)technical/api-*.html $(OUTPUT)technical/api-index.txt \
261 $(cmds_txt) $(OUTPUT)*.made
256clean: 262clean:
257 $(RM) $(MAN_XML) $(addsuffix +,$(MAN_XML)) 263 $(call QUIET_CLEAN, Documentation) $(RM) $(CLEAN_FILES)
258 $(RM) $(MAN_HTML) $(addsuffix +,$(MAN_HTML))
259 $(RM) $(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7)
260 $(RM) $(OUTPUT)*.texi $(OUTPUT)*.texi+ $(OUTPUT)*.texi++
261 $(RM) $(OUTPUT)perf.info $(OUTPUT)perfman.info
262 $(RM) $(OUTPUT)howto-index.txt $(OUTPUT)howto/*.html $(OUTPUT)doc.dep
263 $(RM) $(OUTPUT)technical/api-*.html $(OUTPUT)technical/api-index.txt
264 $(RM) $(cmds_txt) $(OUTPUT)*.made
265 264
266$(MAN_HTML): $(OUTPUT)%.html : %.txt 265$(MAN_HTML): $(OUTPUT)%.html : %.txt
267 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ 266 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
@@ -342,5 +341,3 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
342 341
343#quick-install-html: 342#quick-install-html:
344# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir) 343# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
345
346.PHONY: .FORCE-PERF-VERSION-FILE
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
index e9a8349a7172..fd77d81ea748 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -21,6 +21,19 @@ OPTIONS
21-a:: 21-a::
22--add=:: 22--add=::
23 Add specified file to the cache. 23 Add specified file to the cache.
24-k::
25--kcore::
26 Add specified kcore file to the cache. For the current host that is
27 /proc/kcore which requires root permissions to read. Be aware that
28 running 'perf buildid-cache' as root may update root's build-id cache
29 not the user's. Use the -v option to see where the file is created.
30 Note that the copied file contains only code sections not the whole core
31 image. Note also that files "kallsyms" and "modules" must also be in the
32 same directory and are also copied. All 3 files are created with read
33 permissions for root only. kcore will not be added if there is already a
34 kcore in the cache (with the same build-id) that has the same modules at
35 the same addresses. Use the -v option to see if a copy of kcore is
36 actually made.
24-r:: 37-r::
25--remove=:: 38--remove=::
26 Remove specified file from the cache. 39 Remove specified file from the cache.
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index ac84db2d2334..6a06cefe9642 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -109,7 +109,9 @@ STAT LIVE OPTIONS
109 109
110-m:: 110-m::
111--mmap-pages=:: 111--mmap-pages=::
112 Number of mmap data pages. Must be a power of two. 112 Number of mmap data pages (must be a power of two) or size
113 specification with appended unit character - B/K/M/G. The
114 size is rounded up to have nearest pages power of two value.
113 115
114-a:: 116-a::
115--all-cpus:: 117--all-cpus::
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt
index c7f5f55634ac..ab25be28c9dc 100644
--- a/tools/perf/Documentation/perf-lock.txt
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -48,7 +48,7 @@ REPORT OPTIONS
48-k:: 48-k::
49--key=<value>:: 49--key=<value>::
50 Sorting key. Possible values: acquired (default), contended, 50 Sorting key. Possible values: acquired (default), contended,
51 wait_total, wait_max, wait_min. 51 avg_wait, wait_total, wait_max, wait_min.
52 52
53INFO OPTIONS 53INFO OPTIONS
54------------ 54------------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index e297b74471b8..43b42c4f4a91 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -87,11 +87,25 @@ OPTIONS
87 87
88-m:: 88-m::
89--mmap-pages=:: 89--mmap-pages=::
90 Number of mmap data pages. Must be a power of two. 90 Number of mmap data pages (must be a power of two) or size
91 specification with appended unit character - B/K/M/G. The
92 size is rounded up to have nearest pages power of two value.
91 93
92-g:: 94-g::
95 Enables call-graph (stack chain/backtrace) recording.
96
93--call-graph:: 97--call-graph::
94 Do call-graph (stack chain/backtrace) recording. 98 Setup and enable call-graph (stack chain/backtrace) recording,
99 implies -g.
100
101 Allows specifying "fp" (frame pointer) or "dwarf"
102 (DWARF's CFI - Call Frame Information) as the method to collect
103 the information used to show the call graphs.
104
105 In some systems, where binaries are build with gcc
106 --fomit-frame-pointer, using the "fp" method will produce bogus
107 call graphs, using "dwarf", if available (perf tools linked to
108 the libunwind library) should be used instead.
95 109
96-q:: 110-q::
97--quiet:: 111--quiet::
@@ -166,6 +180,9 @@ following filters are defined:
166 - u: only when the branch target is at the user level 180 - u: only when the branch target is at the user level
167 - k: only when the branch target is in the kernel 181 - k: only when the branch target is in the kernel
168 - hv: only when the target is at the hypervisor level 182 - hv: only when the target is at the hypervisor level
183 - in_tx: only when the target is in a hardware transaction
184 - no_tx: only when the target is not in a hardware transaction
185 - abort_tx: only when the target is a hardware transaction abort
169 186
170+ 187+
171The option requires at least one branch type among any, any_call, any_ret, ind_call. 188The option requires at least one branch type among any, any_call, any_ret, ind_call.
@@ -176,12 +193,20 @@ is enabled for all the sampling events. The sampled branch type is the same for
176The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k 193The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
177Note that this feature may not be available on all processors. 194Note that this feature may not be available on all processors.
178 195
179-W::
180--weight:: 196--weight::
181Enable weightened sampling. An additional weight is recorded per sample and can be 197Enable weightened sampling. An additional weight is recorded per sample and can be
182displayed with the weight and local_weight sort keys. This currently works for TSX 198displayed with the weight and local_weight sort keys. This currently works for TSX
183abort events and some memory events in precise mode on modern Intel CPUs. 199abort events and some memory events in precise mode on modern Intel CPUs.
184 200
201--transaction::
202Record transaction flags for transaction related events.
203
204--force-per-cpu::
205Force the use of per-cpu mmaps. By default, when tasks are specified (i.e. -p,
206-t or -u options) per-thread mmaps are created. This option overrides that and
207forces per-cpu mmaps. A side-effect of that is that inheritance is
208automatically enabled. Add the -i option also to disable inheritance.
209
185SEE ALSO 210SEE ALSO
186-------- 211--------
187linkperf:perf-stat[1], linkperf:perf-list[1] 212linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 2b8097ee39d8..10a279871251 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -71,7 +71,11 @@ OPTIONS
71 entries are displayed as "[other]". 71 entries are displayed as "[other]".
72 - cpu: cpu number the task ran at the time of sample 72 - cpu: cpu number the task ran at the time of sample
73 - srcline: filename and line number executed at the time of sample. The 73 - srcline: filename and line number executed at the time of sample. The
74 DWARF debuggin info must be provided. 74 DWARF debugging info must be provided.
75 - weight: Event specific weight, e.g. memory latency or transaction
76 abort cost. This is the global weight.
77 - local_weight: Local weight version of the weight above.
78 - transaction: Transaction abort flags.
75 79
76 By default, comm, dso and symbol keys are used. 80 By default, comm, dso and symbol keys are used.
77 (i.e. --sort comm,dso,symbol) 81 (i.e. --sort comm,dso,symbol)
@@ -85,6 +89,8 @@ OPTIONS
85 - symbol_from: name of function branched from 89 - symbol_from: name of function branched from
86 - symbol_to: name of function branched to 90 - symbol_to: name of function branched to
87 - mispredict: "N" for predicted branch, "Y" for mispredicted branch 91 - mispredict: "N" for predicted branch, "Y" for mispredicted branch
92 - in_tx: branch in TSX transaction
93 - abort: TSX transaction abort.
88 94
89 And default sort keys are changed to comm, dso_from, symbol_from, dso_to 95 And default sort keys are changed to comm, dso_from, symbol_from, dso_to
90 and symbol_to, see '--branch-stack'. 96 and symbol_to, see '--branch-stack'.
@@ -135,6 +141,14 @@ OPTIONS
135 141
136 Default: fractal,0.5,callee,function. 142 Default: fractal,0.5,callee,function.
137 143
144--max-stack::
145 Set the stack depth limit when parsing the callchain, anything
146 beyond the specified depth will be ignored. This is a trade-off
147 between information loss and faster processing especially for
148 workloads that can have a very long callchain stack.
149
150 Default: 127
151
138-G:: 152-G::
139--inverted:: 153--inverted::
140 alias for inverted caller based call graph. 154 alias for inverted caller based call graph.
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 73c9759005a3..80c7da6732f2 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -137,6 +137,11 @@ core number and the number of online logical processors on that physical process
137After starting the program, wait msecs before measuring. This is useful to 137After starting the program, wait msecs before measuring. This is useful to
138filter out the startup phase of the program, which is often very different. 138filter out the startup phase of the program, which is often very different.
139 139
140-T::
141--transaction::
142
143Print statistics of transactional execution if supported.
144
140EXAMPLES 145EXAMPLES
141-------- 146--------
142 147
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 1632b0efc757..3ff8bd4f0b4d 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -8,7 +8,8 @@ perf-timechart - Tool to visualize total system behavior during a workload
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf timechart' {record} 11'perf timechart' record <command>
12'perf timechart' [<options>]
12 13
13DESCRIPTION 14DESCRIPTION
14----------- 15-----------
@@ -41,6 +42,18 @@ OPTIONS
41--symfs=<directory>:: 42--symfs=<directory>::
42 Look for files with symbols relative to this directory. 43 Look for files with symbols relative to this directory.
43 44
45EXAMPLES
46--------
47
48$ perf timechart record git pull
49
50 [ perf record: Woken up 13 times to write data ]
51 [ perf record: Captured and wrote 4.253 MB perf.data (~185801 samples) ]
52
53$ perf timechart
54
55 Written 10.2 seconds of trace to output.svg.
56
44SEE ALSO 57SEE ALSO
45-------- 58--------
46linkperf:perf-record[1] 59linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 58d6598a9686..7de01dd79688 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -68,7 +68,9 @@ Default is to monitor all CPUS.
68 68
69-m <pages>:: 69-m <pages>::
70--mmap-pages=<pages>:: 70--mmap-pages=<pages>::
71 Number of mmapped data pages. 71 Number of mmap data pages (must be a power of two) or size
72 specification with appended unit character - B/K/M/G. The
73 size is rounded up to have nearest pages power of two value.
72 74
73-p <pid>:: 75-p <pid>::
74--pid=<pid>:: 76--pid=<pid>::
@@ -112,7 +114,8 @@ Default is to monitor all CPUS.
112 114
113-s:: 115-s::
114--sort:: 116--sort::
115 Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight, local_weight. 117 Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight,
118 local_weight, abort, in_tx, transaction
116 119
117-n:: 120-n::
118--show-nr-samples:: 121--show-nr-samples::
@@ -140,20 +143,20 @@ Default is to monitor all CPUS.
140--asm-raw:: 143--asm-raw::
141 Show raw instruction encoding of assembly instructions. 144 Show raw instruction encoding of assembly instructions.
142 145
143-G [type,min,order]:: 146-G::
147 Enables call-graph (stack chain/backtrace) recording.
148
144--call-graph:: 149--call-graph::
145 Display call chains using type, min percent threshold and order. 150 Setup and enable call-graph (stack chain/backtrace) recording,
146 type can be either: 151 implies -G.
147 - flat: single column, linear exposure of call chains. 152
148 - graph: use a graph tree, displaying absolute overhead rates. 153--max-stack::
149 - fractal: like graph, but displays relative rates. Each branch of 154 Set the stack depth limit when parsing the callchain, anything
150 the tree is considered as a new profiled object. 155 beyond the specified depth will be ignored. This is a trade-off
151 156 between information loss and faster processing especially for
152 order can be either: 157 workloads that can have a very long callchain stack.
153 - callee: callee based call graph. 158
154 - caller: inverted caller based call graph. 159 Default: 127
155
156 Default: fractal,0.5,callee.
157 160
158--ignore-callees=<regex>:: 161--ignore-callees=<regex>::
159 Ignore callees of the function(s) matching the given regex. 162 Ignore callees of the function(s) matching the given regex.
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index daccd2c0a48f..fae38d9a44a4 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -9,6 +9,7 @@ SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' 11'perf trace'
12'perf trace record'
12 13
13DESCRIPTION 14DESCRIPTION
14----------- 15-----------
@@ -16,9 +17,14 @@ This command will show the events associated with the target, initially
16syscalls, but other system events like pagefaults, task lifetime events, 17syscalls, but other system events like pagefaults, task lifetime events,
17scheduling events, etc. 18scheduling events, etc.
18 19
19Initially this is a live mode only tool, but eventually will work with 20This is a live mode tool in addition to working with perf.data files like
20perf.data files like the other tools, allowing a detached 'record' from 21the other perf tools. Files can be generated using the 'perf record' command
21analysis phases. 22but the session needs to include the raw_syscalls events (-e 'raw_syscalls:*').
23Alernatively, the 'perf trace record' can be used as a shortcut to
24automatically include the raw_syscalls events when writing events to a file.
25
26The following options apply to perf trace; options to perf trace record are
27found in the perf record man page.
22 28
23OPTIONS 29OPTIONS
24------- 30-------
@@ -59,7 +65,9 @@ OPTIONS
59 65
60-m:: 66-m::
61--mmap-pages=:: 67--mmap-pages=::
62 Number of mmap data pages. Must be a power of two. 68 Number of mmap data pages (must be a power of two) or size
69 specification with appended unit character - B/K/M/G. The
70 size is rounded up to have nearest pages power of two value.
63 71
64-C:: 72-C::
65--cpu:: 73--cpu::
@@ -78,6 +86,27 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
78--input 86--input
79 Process events from a given perf data file. 87 Process events from a given perf data file.
80 88
89-T
90--time
91 Print full timestamp rather time relative to first sample.
92
93--comm::
94 Show process COMM right beside its ID, on by default, disable with --no-comm.
95
96-s::
97--summary::
98 Show only a summary of syscalls by thread with min, max, and average times
99 (in msec) and relative stddev.
100
101-S::
102--with-summary::
103 Show all syscalls followed by a summary by thread with min, max, and
104 average times (in msec) and relative stddev.
105
106--tool_stats::
107 Show tool stats such as number of times fd->pathname was discovered thru
108 hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc.
109
81SEE ALSO 110SEE ALSO
82-------- 111--------
83linkperf:perf-record[1], linkperf:perf-script[1] 112linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 64c043b7a438..4835618a5608 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -1,819 +1,79 @@
1include ../scripts/Makefile.include
2
3# The default target of this Makefile is...
4all:
5
6include config/utilities.mak
7
8# Define V to have a more verbose compile.
9#
10# Define O to save output files in a separate directory.
11#
12# Define ARCH as name of target architecture if you want cross-builds.
13#
14# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
15#
16# Define NO_LIBPERL to disable perl script extension.
17#
18# Define NO_LIBPYTHON to disable python script extension.
19#
20# Define PYTHON to point to the python binary if the default
21# `python' is not correct; for example: PYTHON=python2
22#
23# Define PYTHON_CONFIG to point to the python-config binary if
24# the default `$(PYTHON)-config' is not correct.
25# 1#
26# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 2# This is a simple wrapper Makefile that calls the main Makefile.perf
3# with a -j option to do parallel builds
27# 4#
28# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. 5# If you want to invoke the perf build in some non-standard way then
6# you can use the 'make -f Makefile.perf' method to invoke it.
29# 7#
30# Define LDFLAGS=-static to build a static binary. 8
31#
32# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
33#
34# Define NO_DWARF if you do not want debug-info analysis feature at all.
35#
36# Define WERROR=0 to disable treating any warnings as errors.
37#
38# Define NO_NEWT if you do not want TUI support. (deprecated)
39#
40# Define NO_SLANG if you do not want TUI support.
41#
42# Define NO_GTK2 if you do not want GTK+ GUI support.
43# 9#
44# Define NO_DEMANGLE if you do not want C++ symbol demangling. 10# Clear out the built-in rules GNU make defines by default (such as .o targets),
11# so that we pass through all targets to Makefile.perf:
45# 12#
46# Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds) 13.SUFFIXES:
14
47# 15#
48# Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf 16# We don't want to pass along options like -j:
49# backtrace post unwind.
50# 17#
51# Define NO_BACKTRACE if you do not want stack backtrace debug feature 18unexport MAKEFLAGS
19
52# 20#
53# Define NO_LIBNUMA if you do not want numa perf benchmark 21# Do a parallel build with multiple jobs, based on the number of CPUs online
22# in this system: 'make -j8' on a 8-CPU system, etc.
54# 23#
55# Define NO_LIBAUDIT if you do not want libaudit support 24# (To override it, run 'make JOBS=1' and similar.)
56# 25#
57# Define NO_LIBBIONIC if you do not want bionic support 26ifeq ($(JOBS),)
58 27 JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
59ifeq ($(srctree),) 28 ifeq ($(JOBS),)
60srctree := $(patsubst %/,%,$(dir $(shell pwd))) 29 JOBS := 1
61srctree := $(patsubst %/,%,$(dir $(srctree))) 30 endif
62#$(info Determined 'srctree' to be $(srctree))
63endif
64
65ifneq ($(objtree),)
66#$(info Determined 'objtree' to be $(objtree))
67endif
68
69ifneq ($(OUTPUT),)
70#$(info Determined 'OUTPUT' to be $(OUTPUT))
71endif
72
73$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
74 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
75
76CC = $(CROSS_COMPILE)gcc
77AR = $(CROSS_COMPILE)ar
78
79RM = rm -f
80MKDIR = mkdir
81FIND = find
82INSTALL = install
83FLEX = flex
84BISON = bison
85STRIP = strip
86
87LK_DIR = $(srctree)/tools/lib/lk/
88TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
89
90# include config/Makefile by default and rule out
91# non-config cases
92config := 1
93
94NON_CONFIG_TARGETS := clean TAGS tags cscope help
95
96ifdef MAKECMDGOALS
97ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
98 config := 0
99endif
100endif 31endif
101 32
102ifeq ($(config),1) 33#
103include config/Makefile 34# Only pass canonical directory names as the output directory:
35#
36ifneq ($(O),)
37 FULL_O := $(shell readlink -f $(O) || echo $(O))
104endif 38endif
105 39
106export prefix bindir sharedir sysconfdir 40#
107 41# Only accept the 'DEBUG' variable from the command line:
108# sparse is architecture-neutral, which means that we need to tell it 42#
109# explicitly what architecture to check for. Fix this up for yours.. 43ifeq ("$(origin DEBUG)", "command line")
110SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 44 ifeq ($(DEBUG),)
111 45 override DEBUG = 0
112# Guard against environment variables 46 else
113BUILTIN_OBJS = 47 SET_DEBUG = "DEBUG=$(DEBUG)"
114LIB_H = 48 endif
115LIB_OBJS =
116PYRF_OBJS =
117SCRIPT_SH =
118
119SCRIPT_SH += perf-archive.sh
120
121grep-libs = $(filter -l%,$(1))
122strip-libs = $(filter-out -l%,$(1))
123
124ifneq ($(OUTPUT),)
125 TE_PATH=$(OUTPUT)
126ifneq ($(subdir),)
127 LK_PATH=$(OUTPUT)/../lib/lk/
128else
129 LK_PATH=$(OUTPUT)
130endif
131else 49else
132 TE_PATH=$(TRACE_EVENT_DIR) 50 override DEBUG = 0
133 LK_PATH=$(LK_DIR)
134endif 51endif
135 52
136LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 53define print_msg
137export LIBTRACEEVENT 54 @printf ' BUILD: Doing '\''make \033[33m-j'$(JOBS)'\033[m'\'' parallel build\n'
138 55endef
139LIBLK = $(LK_PATH)liblk.a
140export LIBLK
141
142# python extension build directories
143PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
144PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
145PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
146export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
147 56
148python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so 57define make
58 @$(MAKE) -f Makefile.perf --no-print-directory -j$(JOBS) O=$(FULL_O) $(SET_DEBUG) $@
59endef
149 60
150PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
151PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK)
152
153$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
154 $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
155 --quiet build_ext; \
156 mkdir -p $(OUTPUT)python && \
157 cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
158# 61#
159# No Perl scripts right now: 62# Needed if no target specified:
160# 63#
161 64all:
162SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) 65 $(print_msg)
66 $(make)
163 67
164# 68#
165# Single 'perf' binary right now: 69# The clean target is not really parallel, don't print the jobs info:
166# 70#
167PROGRAMS += $(OUTPUT)perf 71clean:
168 72 $(make)
169# what 'all' will build and 'install' will install, in perfexecdir
170ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
171
172# what 'all' will build but not install in perfexecdir
173OTHER_PROGRAMS = $(OUTPUT)perf
174
175# Set paths to tools early so that they can be used for version tests.
176ifndef SHELL_PATH
177 SHELL_PATH = /bin/sh
178endif
179ifndef PERL_PATH
180 PERL_PATH = /usr/bin/perl
181endif
182
183export PERL_PATH
184
185$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
186 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
187
188$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
189 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_
190
191$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
192 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
193
194$(OUTPUT)util/pmu-bison.c: util/pmu.y
195 $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_
196
197$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
198$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
199
200LIB_FILE=$(OUTPUT)libperf.a
201
202LIB_H += ../../include/uapi/linux/perf_event.h
203LIB_H += ../../include/linux/rbtree.h
204LIB_H += ../../include/linux/list.h
205LIB_H += ../../include/uapi/linux/const.h
206LIB_H += ../../include/linux/hash.h
207LIB_H += ../../include/linux/stringify.h
208LIB_H += util/include/linux/bitmap.h
209LIB_H += util/include/linux/bitops.h
210LIB_H += util/include/linux/compiler.h
211LIB_H += util/include/linux/const.h
212LIB_H += util/include/linux/ctype.h
213LIB_H += util/include/linux/kernel.h
214LIB_H += util/include/linux/list.h
215LIB_H += util/include/linux/export.h
216LIB_H += util/include/linux/magic.h
217LIB_H += util/include/linux/poison.h
218LIB_H += util/include/linux/prefetch.h
219LIB_H += util/include/linux/rbtree.h
220LIB_H += util/include/linux/rbtree_augmented.h
221LIB_H += util/include/linux/string.h
222LIB_H += util/include/linux/types.h
223LIB_H += util/include/linux/linkage.h
224LIB_H += util/include/asm/asm-offsets.h
225LIB_H += util/include/asm/bug.h
226LIB_H += util/include/asm/byteorder.h
227LIB_H += util/include/asm/hweight.h
228LIB_H += util/include/asm/swab.h
229LIB_H += util/include/asm/system.h
230LIB_H += util/include/asm/uaccess.h
231LIB_H += util/include/dwarf-regs.h
232LIB_H += util/include/asm/dwarf2.h
233LIB_H += util/include/asm/cpufeature.h
234LIB_H += util/include/asm/unistd_32.h
235LIB_H += util/include/asm/unistd_64.h
236LIB_H += perf.h
237LIB_H += util/annotate.h
238LIB_H += util/cache.h
239LIB_H += util/callchain.h
240LIB_H += util/build-id.h
241LIB_H += util/debug.h
242LIB_H += util/sysfs.h
243LIB_H += util/pmu.h
244LIB_H += util/event.h
245LIB_H += util/evsel.h
246LIB_H += util/evlist.h
247LIB_H += util/exec_cmd.h
248LIB_H += util/types.h
249LIB_H += util/levenshtein.h
250LIB_H += util/machine.h
251LIB_H += util/map.h
252LIB_H += util/parse-options.h
253LIB_H += util/parse-events.h
254LIB_H += util/quote.h
255LIB_H += util/util.h
256LIB_H += util/xyarray.h
257LIB_H += util/header.h
258LIB_H += util/help.h
259LIB_H += util/session.h
260LIB_H += util/strbuf.h
261LIB_H += util/strlist.h
262LIB_H += util/strfilter.h
263LIB_H += util/svghelper.h
264LIB_H += util/tool.h
265LIB_H += util/run-command.h
266LIB_H += util/sigchain.h
267LIB_H += util/dso.h
268LIB_H += util/symbol.h
269LIB_H += util/color.h
270LIB_H += util/values.h
271LIB_H += util/sort.h
272LIB_H += util/hist.h
273LIB_H += util/thread.h
274LIB_H += util/thread_map.h
275LIB_H += util/trace-event.h
276LIB_H += util/probe-finder.h
277LIB_H += util/dwarf-aux.h
278LIB_H += util/probe-event.h
279LIB_H += util/pstack.h
280LIB_H += util/cpumap.h
281LIB_H += util/top.h
282LIB_H += $(ARCH_INCLUDE)
283LIB_H += util/cgroup.h
284LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
285LIB_H += util/target.h
286LIB_H += util/rblist.h
287LIB_H += util/intlist.h
288LIB_H += util/perf_regs.h
289LIB_H += util/unwind.h
290LIB_H += util/vdso.h
291LIB_H += ui/helpline.h
292LIB_H += ui/progress.h
293LIB_H += ui/util.h
294LIB_H += ui/ui.h
295
296LIB_OBJS += $(OUTPUT)util/abspath.o
297LIB_OBJS += $(OUTPUT)util/alias.o
298LIB_OBJS += $(OUTPUT)util/annotate.o
299LIB_OBJS += $(OUTPUT)util/build-id.o
300LIB_OBJS += $(OUTPUT)util/config.o
301LIB_OBJS += $(OUTPUT)util/ctype.o
302LIB_OBJS += $(OUTPUT)util/sysfs.o
303LIB_OBJS += $(OUTPUT)util/pmu.o
304LIB_OBJS += $(OUTPUT)util/environment.o
305LIB_OBJS += $(OUTPUT)util/event.o
306LIB_OBJS += $(OUTPUT)util/evlist.o
307LIB_OBJS += $(OUTPUT)util/evsel.o
308LIB_OBJS += $(OUTPUT)util/exec_cmd.o
309LIB_OBJS += $(OUTPUT)util/help.o
310LIB_OBJS += $(OUTPUT)util/levenshtein.o
311LIB_OBJS += $(OUTPUT)util/parse-options.o
312LIB_OBJS += $(OUTPUT)util/parse-events.o
313LIB_OBJS += $(OUTPUT)util/path.o
314LIB_OBJS += $(OUTPUT)util/rbtree.o
315LIB_OBJS += $(OUTPUT)util/bitmap.o
316LIB_OBJS += $(OUTPUT)util/hweight.o
317LIB_OBJS += $(OUTPUT)util/run-command.o
318LIB_OBJS += $(OUTPUT)util/quote.o
319LIB_OBJS += $(OUTPUT)util/strbuf.o
320LIB_OBJS += $(OUTPUT)util/string.o
321LIB_OBJS += $(OUTPUT)util/strlist.o
322LIB_OBJS += $(OUTPUT)util/strfilter.o
323LIB_OBJS += $(OUTPUT)util/top.o
324LIB_OBJS += $(OUTPUT)util/usage.o
325LIB_OBJS += $(OUTPUT)util/wrapper.o
326LIB_OBJS += $(OUTPUT)util/sigchain.o
327LIB_OBJS += $(OUTPUT)util/dso.o
328LIB_OBJS += $(OUTPUT)util/symbol.o
329LIB_OBJS += $(OUTPUT)util/symbol-elf.o
330LIB_OBJS += $(OUTPUT)util/color.o
331LIB_OBJS += $(OUTPUT)util/pager.o
332LIB_OBJS += $(OUTPUT)util/header.o
333LIB_OBJS += $(OUTPUT)util/callchain.o
334LIB_OBJS += $(OUTPUT)util/values.o
335LIB_OBJS += $(OUTPUT)util/debug.o
336LIB_OBJS += $(OUTPUT)util/machine.o
337LIB_OBJS += $(OUTPUT)util/map.o
338LIB_OBJS += $(OUTPUT)util/pstack.o
339LIB_OBJS += $(OUTPUT)util/session.o
340LIB_OBJS += $(OUTPUT)util/thread.o
341LIB_OBJS += $(OUTPUT)util/thread_map.o
342LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
343LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
344LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
345LIB_OBJS += $(OUTPUT)util/pmu-flex.o
346LIB_OBJS += $(OUTPUT)util/pmu-bison.o
347LIB_OBJS += $(OUTPUT)util/trace-event-read.o
348LIB_OBJS += $(OUTPUT)util/trace-event-info.o
349LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
350LIB_OBJS += $(OUTPUT)util/svghelper.o
351LIB_OBJS += $(OUTPUT)util/sort.o
352LIB_OBJS += $(OUTPUT)util/hist.o
353LIB_OBJS += $(OUTPUT)util/probe-event.o
354LIB_OBJS += $(OUTPUT)util/util.o
355LIB_OBJS += $(OUTPUT)util/xyarray.o
356LIB_OBJS += $(OUTPUT)util/cpumap.o
357LIB_OBJS += $(OUTPUT)util/cgroup.o
358LIB_OBJS += $(OUTPUT)util/target.o
359LIB_OBJS += $(OUTPUT)util/rblist.o
360LIB_OBJS += $(OUTPUT)util/intlist.o
361LIB_OBJS += $(OUTPUT)util/vdso.o
362LIB_OBJS += $(OUTPUT)util/stat.o
363LIB_OBJS += $(OUTPUT)util/record.o
364
365LIB_OBJS += $(OUTPUT)ui/setup.o
366LIB_OBJS += $(OUTPUT)ui/helpline.o
367LIB_OBJS += $(OUTPUT)ui/progress.o
368LIB_OBJS += $(OUTPUT)ui/util.o
369LIB_OBJS += $(OUTPUT)ui/hist.o
370LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
371
372LIB_OBJS += $(OUTPUT)arch/common.o
373
374LIB_OBJS += $(OUTPUT)tests/parse-events.o
375LIB_OBJS += $(OUTPUT)tests/dso-data.o
376LIB_OBJS += $(OUTPUT)tests/attr.o
377LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o
378LIB_OBJS += $(OUTPUT)tests/open-syscall.o
379LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o
380LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o
381LIB_OBJS += $(OUTPUT)tests/mmap-basic.o
382LIB_OBJS += $(OUTPUT)tests/perf-record.o
383LIB_OBJS += $(OUTPUT)tests/rdpmc.o
384LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
385LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
386LIB_OBJS += $(OUTPUT)tests/pmu.o
387LIB_OBJS += $(OUTPUT)tests/hists_link.o
388LIB_OBJS += $(OUTPUT)tests/python-use.o
389LIB_OBJS += $(OUTPUT)tests/bp_signal.o
390LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
391LIB_OBJS += $(OUTPUT)tests/task-exit.o
392LIB_OBJS += $(OUTPUT)tests/sw-clock.o
393ifeq ($(ARCH),x86)
394LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o
395endif
396LIB_OBJS += $(OUTPUT)tests/code-reading.o
397LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
398LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
399
400BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
401BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
402# Benchmark modules
403BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
404BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
405ifeq ($(RAW_ARCH),x86_64)
406BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
407BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
408endif
409BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
410BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
411
412BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
413BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
414BUILTIN_OBJS += $(OUTPUT)builtin-help.o
415BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
416BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
417BUILTIN_OBJS += $(OUTPUT)builtin-buildid-cache.o
418BUILTIN_OBJS += $(OUTPUT)builtin-list.o
419BUILTIN_OBJS += $(OUTPUT)builtin-record.o
420BUILTIN_OBJS += $(OUTPUT)builtin-report.o
421BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
422BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
423BUILTIN_OBJS += $(OUTPUT)builtin-top.o
424BUILTIN_OBJS += $(OUTPUT)builtin-script.o
425BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
426BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
427BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
428BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
429BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
430BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
431BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
432
433PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
434
435# We choose to avoid "if .. else if .. else .. endif endif"
436# because maintaining the nesting to match is a pain. If
437# we had "elif" things would have been much nicer...
438
439-include arch/$(ARCH)/Makefile
440
441ifneq ($(OUTPUT),)
442 CFLAGS += -I$(OUTPUT)
443endif
444
445ifdef NO_LIBELF
446EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
447
448# Remove ELF/DWARF dependent codes
449LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS))
450LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS))
451LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS))
452LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS))
453
454BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
455
456# Use minimal symbol handling
457LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
458
459else # NO_LIBELF
460ifndef NO_DWARF
461 LIB_OBJS += $(OUTPUT)util/probe-finder.o
462 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
463endif # NO_DWARF
464endif # NO_LIBELF
465
466ifndef NO_LIBUNWIND
467 LIB_OBJS += $(OUTPUT)util/unwind.o
468endif
469LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
470
471ifndef NO_LIBAUDIT
472 BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
473endif
474
475ifndef NO_SLANG
476 LIB_OBJS += $(OUTPUT)ui/browser.o
477 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
478 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
479 LIB_OBJS += $(OUTPUT)ui/browsers/map.o
480 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
481 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
482 LIB_OBJS += $(OUTPUT)ui/tui/util.o
483 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
484 LIB_OBJS += $(OUTPUT)ui/tui/progress.o
485 LIB_H += ui/browser.h
486 LIB_H += ui/browsers/map.h
487 LIB_H += ui/keysyms.h
488 LIB_H += ui/libslang.h
489endif
490
491ifndef NO_GTK2
492 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
493 LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
494 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
495 LIB_OBJS += $(OUTPUT)ui/gtk/util.o
496 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
497 LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
498 LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
499endif
500
501ifndef NO_LIBPERL
502 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
503 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
504endif
505
506ifndef NO_LIBPYTHON
507 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
508 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
509endif
510
511ifeq ($(NO_PERF_REGS),0)
512 ifeq ($(ARCH),x86)
513 LIB_H += arch/x86/include/perf_regs.h
514 endif
515endif
516
517ifndef NO_LIBNUMA
518 BUILTIN_OBJS += $(OUTPUT)bench/numa.o
519endif
520
521ifdef ASCIIDOC8
522 export ASCIIDOC8
523endif
524
525LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
526
527export INSTALL SHELL_PATH
528
529### Build rules
530
531SHELL = $(SHELL_PATH)
532
533all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
534
535please_set_SHELL_PATH_to_a_more_modern_shell:
536 @$$(:)
537
538shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
539
540strip: $(PROGRAMS) $(OUTPUT)perf
541 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
542
543$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
544 $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
545 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
546 $(CFLAGS) -c $(filter %.c,$^) -o $@
547
548$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
549 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \
550 $(BUILTIN_OBJS) $(LIBS) -o $@
551
552$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
553 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
554 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
555 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
556 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
557
558$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
559 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
560 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
561 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
562 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
563
564$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
565
566$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
567 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
568
569$(SCRIPTS) : % : %.sh
570 $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
571
572# These can record PERF_VERSION
573$(OUTPUT)perf.o perf.spec \
574 $(SCRIPTS) \
575 : $(OUTPUT)PERF-VERSION-FILE
576
577.SUFFIXES:
578.SUFFIXES: .o .c .S .s
579
580# These two need to be here so that when O= is not used they take precedence
581# over the general rule for .o
582
583$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
584 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $<
585
586$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
587 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
588
589$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
590 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
591$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
592 $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
593$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
594 $(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $<
595$(OUTPUT)%.o: %.S
596 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
597$(OUTPUT)%.s: %.S
598 $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
599
600$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
601 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
602 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
603 '-DPREFIX="$(prefix_SQ)"' \
604 $<
605
606$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
607 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
608 '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
609 $<
610
611$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
612 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
613 -DPYTHONPATH='"$(OUTPUT)python"' \
614 -DPYTHON='"$(PYTHON_WORD)"' \
615 $<
616
617$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
618 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
619
620$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
621 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
622
623$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
624 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
625 73
626$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 74#
627 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< 75# All other targets get passed through:
628 76#
629$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS 77%:
630 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< 78 $(print_msg)
631 79 $(make)
632$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
633 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
634
635$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
636 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
637
638$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
639 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
640
641$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
642 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $<
643
644$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
645 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $<
646
647$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
648 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
649
650$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
651 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
652
653$(OUTPUT)perf-%: %.o $(PERFLIBS)
654 $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
655
656$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
657$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
658
659# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
660# we depend the various files onto their directories.
661DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
662$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
663# In the second step, we make a rule to actually create these directories
664$(sort $(dir $(DIRECTORY_DEPS))):
665 $(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
666
667$(LIB_FILE): $(LIB_OBJS)
668 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
669
670# libtraceevent.a
671$(LIBTRACEEVENT):
672 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libtraceevent.a
673
674$(LIBTRACEEVENT)-clean:
675 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
676
677# if subdir is set, we've been called from above so target has been built
678# already
679$(LIBLK):
680ifeq ($(subdir),)
681 $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a
682endif
683
684$(LIBLK)-clean:
685ifeq ($(subdir),)
686 $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
687endif
688
689help:
690 @echo 'Perf make targets:'
691 @echo ' doc - make *all* documentation (see below)'
692 @echo ' man - make manpage documentation (access with man <foo>)'
693 @echo ' html - make html documentation'
694 @echo ' info - make GNU info documentation (access with info <foo>)'
695 @echo ' pdf - make pdf documentation'
696 @echo ' TAGS - use etags to make tag information for source browsing'
697 @echo ' tags - use ctags to make tag information for source browsing'
698 @echo ' cscope - use cscope to make interactive browsing database'
699 @echo ''
700 @echo 'Perf install targets:'
701 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
702 @echo ' HINT: use "make prefix=<path> <install target>" to install to a particular'
703 @echo ' path like make prefix=/usr/local install install-doc'
704 @echo ' install - install compiled binaries'
705 @echo ' install-doc - install *all* documentation'
706 @echo ' install-man - install manpage documentation'
707 @echo ' install-html - install html documentation'
708 @echo ' install-info - install GNU info documentation'
709 @echo ' install-pdf - install pdf documentation'
710 @echo ''
711 @echo ' quick-install-doc - alias for quick-install-man'
712 @echo ' quick-install-man - install the documentation quickly'
713 @echo ' quick-install-html - install the html documentation quickly'
714 @echo ''
715 @echo 'Perf maintainer targets:'
716 @echo ' clean - clean all binary objects and build output'
717
718
719DOC_TARGETS := doc man html info pdf
720
721INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man
722INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
723
724# 'make doc' should call 'make -C Documentation all'
725$(DOC_TARGETS):
726 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
727
728TAGS:
729 $(RM) TAGS
730 $(FIND) . -name '*.[hcS]' -print | xargs etags -a
731
732tags:
733 $(RM) tags
734 $(FIND) . -name '*.[hcS]' -print | xargs ctags -a
735
736cscope:
737 $(RM) cscope*
738 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b
739
740### Detect prefix changes
741TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
742 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
743
744$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
745 @FLAGS='$(TRACK_CFLAGS)'; \
746 if test x"$$FLAGS" != x"`cat $(OUTPUT)PERF-CFLAGS 2>/dev/null`" ; then \
747 echo 1>&2 " * new build flags or prefix"; \
748 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
749 fi
750
751### Testing rules
752
753# GNU make supports exporting all variables by "export" without parameters.
754# However, the environment gets quite big, and some programs have problems
755# with that.
756
757check: $(OUTPUT)common-cmds.h
758 if sparse; \
759 then \
760 for i in *.c */*.c; \
761 do \
762 sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
763 done; \
764 else \
765 exit 1; \
766 fi
767
768### Installation rules
769
770install-bin: all
771 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
772 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
773 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
774 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
775ifndef NO_LIBPERL
776 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
777 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
778 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
779 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
780 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
781endif
782ifndef NO_LIBPYTHON
783 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
784 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
785 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
786 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
787 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
788endif
789 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'
790 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
791 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
792 $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
793 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
794 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
795
796install: install-bin try-install-man
797
798install-python_ext:
799 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
800
801# 'make install-doc' should call 'make -C Documentation install'
802$(INSTALL_DOC_TARGETS):
803 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=)
804
805### Cleaning rules
806
807clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean
808 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
809 $(RM) $(ALL_PROGRAMS) perf
810 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
811 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
812 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
813 $(RM) $(OUTPUT)util/*-bison*
814 $(RM) $(OUTPUT)util/*-flex*
815 $(python-clean)
816
817.PHONY: all install clean strip $(LIBTRACEEVENT) $(LIBLK)
818.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
819.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
new file mode 100644
index 000000000000..7fc8f179cae7
--- /dev/null
+++ b/tools/perf/Makefile.perf
@@ -0,0 +1,892 @@
1include ../scripts/Makefile.include
2
3# The default target of this Makefile is...
4all:
5
6include config/utilities.mak
7
8# Define V to have a more verbose compile.
9#
10# Define O to save output files in a separate directory.
11#
12# Define ARCH as name of target architecture if you want cross-builds.
13#
14# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
15#
16# Define NO_LIBPERL to disable perl script extension.
17#
18# Define NO_LIBPYTHON to disable python script extension.
19#
20# Define PYTHON to point to the python binary if the default
21# `python' is not correct; for example: PYTHON=python2
22#
23# Define PYTHON_CONFIG to point to the python-config binary if
24# the default `$(PYTHON)-config' is not correct.
25#
26# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
27#
28# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
29#
30# Define LDFLAGS=-static to build a static binary.
31#
32# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
33#
34# Define NO_DWARF if you do not want debug-info analysis feature at all.
35#
36# Define WERROR=0 to disable treating any warnings as errors.
37#
38# Define NO_NEWT if you do not want TUI support. (deprecated)
39#
40# Define NO_SLANG if you do not want TUI support.
41#
42# Define NO_GTK2 if you do not want GTK+ GUI support.
43#
44# Define NO_DEMANGLE if you do not want C++ symbol demangling.
45#
46# Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds)
47#
48# Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf
49# backtrace post unwind.
50#
51# Define NO_BACKTRACE if you do not want stack backtrace debug feature
52#
53# Define NO_LIBNUMA if you do not want numa perf benchmark
54#
55# Define NO_LIBAUDIT if you do not want libaudit support
56#
57# Define NO_LIBBIONIC if you do not want bionic support
58
59ifeq ($(srctree),)
60srctree := $(patsubst %/,%,$(dir $(shell pwd)))
61srctree := $(patsubst %/,%,$(dir $(srctree)))
62#$(info Determined 'srctree' to be $(srctree))
63endif
64
65ifneq ($(objtree),)
66#$(info Determined 'objtree' to be $(objtree))
67endif
68
69ifneq ($(OUTPUT),)
70#$(info Determined 'OUTPUT' to be $(OUTPUT))
71endif
72
73$(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD
74 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
75 @touch $(OUTPUT)PERF-VERSION-FILE
76
77CC = $(CROSS_COMPILE)gcc
78AR = $(CROSS_COMPILE)ar
79
80RM = rm -f
81LN = ln -f
82MKDIR = mkdir
83FIND = find
84INSTALL = install
85FLEX = flex
86BISON = bison
87STRIP = strip
88
89LK_DIR = $(srctree)/tools/lib/lk/
90TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
91
92# include config/Makefile by default and rule out
93# non-config cases
94config := 1
95
96NON_CONFIG_TARGETS := clean TAGS tags cscope help
97
98ifdef MAKECMDGOALS
99ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
100 config := 0
101endif
102endif
103
104ifeq ($(config),1)
105include config/Makefile
106endif
107
108export prefix bindir sharedir sysconfdir
109
110# sparse is architecture-neutral, which means that we need to tell it
111# explicitly what architecture to check for. Fix this up for yours..
112SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
113
114# Guard against environment variables
115BUILTIN_OBJS =
116LIB_H =
117LIB_OBJS =
118GTK_OBJS =
119PYRF_OBJS =
120SCRIPT_SH =
121
122SCRIPT_SH += perf-archive.sh
123
124grep-libs = $(filter -l%,$(1))
125strip-libs = $(filter-out -l%,$(1))
126
127ifneq ($(OUTPUT),)
128 TE_PATH=$(OUTPUT)
129ifneq ($(subdir),)
130 LK_PATH=$(OUTPUT)/../lib/lk/
131else
132 LK_PATH=$(OUTPUT)
133endif
134else
135 TE_PATH=$(TRACE_EVENT_DIR)
136 LK_PATH=$(LK_DIR)
137endif
138
139LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
140export LIBTRACEEVENT
141
142LIBLK = $(LK_PATH)liblk.a
143export LIBLK
144
145# python extension build directories
146PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
147PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
148PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
149export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
150
151python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
152
153PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
154PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK)
155
156$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
157 $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
158 --quiet build_ext; \
159 mkdir -p $(OUTPUT)python && \
160 cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
161#
162# No Perl scripts right now:
163#
164
165SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
166
167#
168# Single 'perf' binary right now:
169#
170PROGRAMS += $(OUTPUT)perf
171
172# what 'all' will build and 'install' will install, in perfexecdir
173ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
174
175# what 'all' will build but not install in perfexecdir
176OTHER_PROGRAMS = $(OUTPUT)perf
177
178# Set paths to tools early so that they can be used for version tests.
179ifndef SHELL_PATH
180 SHELL_PATH = /bin/sh
181endif
182ifndef PERL_PATH
183 PERL_PATH = /usr/bin/perl
184endif
185
186export PERL_PATH
187
188$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
189 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
190
191$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
192 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_
193
194$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
195 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
196
197$(OUTPUT)util/pmu-bison.c: util/pmu.y
198 $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_
199
200$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
201$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
202
203LIB_FILE=$(OUTPUT)libperf.a
204
205LIB_H += ../../include/uapi/linux/perf_event.h
206LIB_H += ../../include/linux/rbtree.h
207LIB_H += ../../include/linux/list.h
208LIB_H += ../../include/uapi/linux/const.h
209LIB_H += ../../include/linux/hash.h
210LIB_H += ../../include/linux/stringify.h
211LIB_H += util/include/linux/bitmap.h
212LIB_H += util/include/linux/bitops.h
213LIB_H += util/include/linux/compiler.h
214LIB_H += util/include/linux/const.h
215LIB_H += util/include/linux/ctype.h
216LIB_H += util/include/linux/kernel.h
217LIB_H += util/include/linux/list.h
218LIB_H += util/include/linux/export.h
219LIB_H += util/include/linux/magic.h
220LIB_H += util/include/linux/poison.h
221LIB_H += util/include/linux/prefetch.h
222LIB_H += util/include/linux/rbtree.h
223LIB_H += util/include/linux/rbtree_augmented.h
224LIB_H += util/include/linux/string.h
225LIB_H += util/include/linux/types.h
226LIB_H += util/include/linux/linkage.h
227LIB_H += util/include/asm/asm-offsets.h
228LIB_H += util/include/asm/bug.h
229LIB_H += util/include/asm/byteorder.h
230LIB_H += util/include/asm/hweight.h
231LIB_H += util/include/asm/swab.h
232LIB_H += util/include/asm/system.h
233LIB_H += util/include/asm/uaccess.h
234LIB_H += util/include/dwarf-regs.h
235LIB_H += util/include/asm/dwarf2.h
236LIB_H += util/include/asm/cpufeature.h
237LIB_H += util/include/asm/unistd_32.h
238LIB_H += util/include/asm/unistd_64.h
239LIB_H += perf.h
240LIB_H += util/annotate.h
241LIB_H += util/cache.h
242LIB_H += util/callchain.h
243LIB_H += util/build-id.h
244LIB_H += util/debug.h
245LIB_H += util/fs.h
246LIB_H += util/pmu.h
247LIB_H += util/event.h
248LIB_H += util/evsel.h
249LIB_H += util/evlist.h
250LIB_H += util/exec_cmd.h
251LIB_H += util/types.h
252LIB_H += util/levenshtein.h
253LIB_H += util/machine.h
254LIB_H += util/map.h
255LIB_H += util/parse-options.h
256LIB_H += util/parse-events.h
257LIB_H += util/quote.h
258LIB_H += util/util.h
259LIB_H += util/xyarray.h
260LIB_H += util/header.h
261LIB_H += util/help.h
262LIB_H += util/session.h
263LIB_H += util/strbuf.h
264LIB_H += util/strlist.h
265LIB_H += util/strfilter.h
266LIB_H += util/svghelper.h
267LIB_H += util/tool.h
268LIB_H += util/run-command.h
269LIB_H += util/sigchain.h
270LIB_H += util/dso.h
271LIB_H += util/symbol.h
272LIB_H += util/color.h
273LIB_H += util/values.h
274LIB_H += util/sort.h
275LIB_H += util/hist.h
276LIB_H += util/comm.h
277LIB_H += util/thread.h
278LIB_H += util/thread_map.h
279LIB_H += util/trace-event.h
280LIB_H += util/probe-finder.h
281LIB_H += util/dwarf-aux.h
282LIB_H += util/probe-event.h
283LIB_H += util/pstack.h
284LIB_H += util/cpumap.h
285LIB_H += util/top.h
286LIB_H += $(ARCH_INCLUDE)
287LIB_H += util/cgroup.h
288LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
289LIB_H += util/target.h
290LIB_H += util/rblist.h
291LIB_H += util/intlist.h
292LIB_H += util/perf_regs.h
293LIB_H += util/unwind.h
294LIB_H += util/vdso.h
295LIB_H += ui/helpline.h
296LIB_H += ui/progress.h
297LIB_H += ui/util.h
298LIB_H += ui/ui.h
299LIB_H += util/data.h
300
301LIB_OBJS += $(OUTPUT)util/abspath.o
302LIB_OBJS += $(OUTPUT)util/alias.o
303LIB_OBJS += $(OUTPUT)util/annotate.o
304LIB_OBJS += $(OUTPUT)util/build-id.o
305LIB_OBJS += $(OUTPUT)util/config.o
306LIB_OBJS += $(OUTPUT)util/ctype.o
307LIB_OBJS += $(OUTPUT)util/fs.o
308LIB_OBJS += $(OUTPUT)util/pmu.o
309LIB_OBJS += $(OUTPUT)util/environment.o
310LIB_OBJS += $(OUTPUT)util/event.o
311LIB_OBJS += $(OUTPUT)util/evlist.o
312LIB_OBJS += $(OUTPUT)util/evsel.o
313LIB_OBJS += $(OUTPUT)util/exec_cmd.o
314LIB_OBJS += $(OUTPUT)util/help.o
315LIB_OBJS += $(OUTPUT)util/levenshtein.o
316LIB_OBJS += $(OUTPUT)util/parse-options.o
317LIB_OBJS += $(OUTPUT)util/parse-events.o
318LIB_OBJS += $(OUTPUT)util/path.o
319LIB_OBJS += $(OUTPUT)util/rbtree.o
320LIB_OBJS += $(OUTPUT)util/bitmap.o
321LIB_OBJS += $(OUTPUT)util/hweight.o
322LIB_OBJS += $(OUTPUT)util/run-command.o
323LIB_OBJS += $(OUTPUT)util/quote.o
324LIB_OBJS += $(OUTPUT)util/strbuf.o
325LIB_OBJS += $(OUTPUT)util/string.o
326LIB_OBJS += $(OUTPUT)util/strlist.o
327LIB_OBJS += $(OUTPUT)util/strfilter.o
328LIB_OBJS += $(OUTPUT)util/top.o
329LIB_OBJS += $(OUTPUT)util/usage.o
330LIB_OBJS += $(OUTPUT)util/wrapper.o
331LIB_OBJS += $(OUTPUT)util/sigchain.o
332LIB_OBJS += $(OUTPUT)util/dso.o
333LIB_OBJS += $(OUTPUT)util/symbol.o
334LIB_OBJS += $(OUTPUT)util/symbol-elf.o
335LIB_OBJS += $(OUTPUT)util/color.o
336LIB_OBJS += $(OUTPUT)util/pager.o
337LIB_OBJS += $(OUTPUT)util/header.o
338LIB_OBJS += $(OUTPUT)util/callchain.o
339LIB_OBJS += $(OUTPUT)util/values.o
340LIB_OBJS += $(OUTPUT)util/debug.o
341LIB_OBJS += $(OUTPUT)util/machine.o
342LIB_OBJS += $(OUTPUT)util/map.o
343LIB_OBJS += $(OUTPUT)util/pstack.o
344LIB_OBJS += $(OUTPUT)util/session.o
345LIB_OBJS += $(OUTPUT)util/comm.o
346LIB_OBJS += $(OUTPUT)util/thread.o
347LIB_OBJS += $(OUTPUT)util/thread_map.o
348LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
349LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
350LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
351LIB_OBJS += $(OUTPUT)util/pmu-flex.o
352LIB_OBJS += $(OUTPUT)util/pmu-bison.o
353LIB_OBJS += $(OUTPUT)util/trace-event-read.o
354LIB_OBJS += $(OUTPUT)util/trace-event-info.o
355LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
356LIB_OBJS += $(OUTPUT)util/svghelper.o
357LIB_OBJS += $(OUTPUT)util/sort.o
358LIB_OBJS += $(OUTPUT)util/hist.o
359LIB_OBJS += $(OUTPUT)util/probe-event.o
360LIB_OBJS += $(OUTPUT)util/util.o
361LIB_OBJS += $(OUTPUT)util/xyarray.o
362LIB_OBJS += $(OUTPUT)util/cpumap.o
363LIB_OBJS += $(OUTPUT)util/cgroup.o
364LIB_OBJS += $(OUTPUT)util/target.o
365LIB_OBJS += $(OUTPUT)util/rblist.o
366LIB_OBJS += $(OUTPUT)util/intlist.o
367LIB_OBJS += $(OUTPUT)util/vdso.o
368LIB_OBJS += $(OUTPUT)util/stat.o
369LIB_OBJS += $(OUTPUT)util/record.o
370LIB_OBJS += $(OUTPUT)util/srcline.o
371LIB_OBJS += $(OUTPUT)util/data.o
372
373LIB_OBJS += $(OUTPUT)ui/setup.o
374LIB_OBJS += $(OUTPUT)ui/helpline.o
375LIB_OBJS += $(OUTPUT)ui/progress.o
376LIB_OBJS += $(OUTPUT)ui/util.o
377LIB_OBJS += $(OUTPUT)ui/hist.o
378LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
379
380LIB_OBJS += $(OUTPUT)arch/common.o
381
382LIB_OBJS += $(OUTPUT)tests/parse-events.o
383LIB_OBJS += $(OUTPUT)tests/dso-data.o
384LIB_OBJS += $(OUTPUT)tests/attr.o
385LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o
386LIB_OBJS += $(OUTPUT)tests/open-syscall.o
387LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o
388LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o
389LIB_OBJS += $(OUTPUT)tests/mmap-basic.o
390LIB_OBJS += $(OUTPUT)tests/perf-record.o
391LIB_OBJS += $(OUTPUT)tests/rdpmc.o
392LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
393LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
394LIB_OBJS += $(OUTPUT)tests/pmu.o
395LIB_OBJS += $(OUTPUT)tests/hists_link.o
396LIB_OBJS += $(OUTPUT)tests/python-use.o
397LIB_OBJS += $(OUTPUT)tests/bp_signal.o
398LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
399LIB_OBJS += $(OUTPUT)tests/task-exit.o
400LIB_OBJS += $(OUTPUT)tests/sw-clock.o
401ifeq ($(ARCH),x86)
402LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o
403endif
404LIB_OBJS += $(OUTPUT)tests/code-reading.o
405LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
406LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
407
408BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
409BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
410# Benchmark modules
411BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
412BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
413ifeq ($(RAW_ARCH),x86_64)
414BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
415BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
416endif
417BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
418BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
419
420BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
421BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
422BUILTIN_OBJS += $(OUTPUT)builtin-help.o
423BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
424BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
425BUILTIN_OBJS += $(OUTPUT)builtin-buildid-cache.o
426BUILTIN_OBJS += $(OUTPUT)builtin-list.o
427BUILTIN_OBJS += $(OUTPUT)builtin-record.o
428BUILTIN_OBJS += $(OUTPUT)builtin-report.o
429BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
430BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
431BUILTIN_OBJS += $(OUTPUT)builtin-top.o
432BUILTIN_OBJS += $(OUTPUT)builtin-script.o
433BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
434BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
435BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
436BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
437BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
438BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
439BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
440
441PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
442
443# We choose to avoid "if .. else if .. else .. endif endif"
444# because maintaining the nesting to match is a pain. If
445# we had "elif" things would have been much nicer...
446
447-include arch/$(ARCH)/Makefile
448
449ifneq ($(OUTPUT),)
450 CFLAGS += -I$(OUTPUT)
451endif
452
453ifdef NO_LIBELF
454EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
455
456# Remove ELF/DWARF dependent codes
457LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS))
458LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS))
459LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS))
460LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS))
461
462BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
463
464# Use minimal symbol handling
465LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
466
467else # NO_LIBELF
468ifndef NO_DWARF
469 LIB_OBJS += $(OUTPUT)util/probe-finder.o
470 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
471endif # NO_DWARF
472endif # NO_LIBELF
473
474ifndef NO_LIBUNWIND
475 LIB_OBJS += $(OUTPUT)util/unwind.o
476endif
477LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
478
479ifndef NO_LIBAUDIT
480 BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
481endif
482
483ifndef NO_SLANG
484 LIB_OBJS += $(OUTPUT)ui/browser.o
485 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
486 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
487 LIB_OBJS += $(OUTPUT)ui/browsers/map.o
488 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
489 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
490 LIB_OBJS += $(OUTPUT)ui/tui/util.o
491 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
492 LIB_OBJS += $(OUTPUT)ui/tui/progress.o
493 LIB_H += ui/tui/tui.h
494 LIB_H += ui/browser.h
495 LIB_H += ui/browsers/map.h
496 LIB_H += ui/keysyms.h
497 LIB_H += ui/libslang.h
498endif
499
500ifndef NO_GTK2
501 ALL_PROGRAMS += $(OUTPUT)libperf-gtk.so
502
503 GTK_OBJS += $(OUTPUT)ui/gtk/browser.o
504 GTK_OBJS += $(OUTPUT)ui/gtk/hists.o
505 GTK_OBJS += $(OUTPUT)ui/gtk/setup.o
506 GTK_OBJS += $(OUTPUT)ui/gtk/util.o
507 GTK_OBJS += $(OUTPUT)ui/gtk/helpline.o
508 GTK_OBJS += $(OUTPUT)ui/gtk/progress.o
509 GTK_OBJS += $(OUTPUT)ui/gtk/annotate.o
510
511install-gtk: $(OUTPUT)libperf-gtk.so
512 $(call QUIET_INSTALL, 'GTK UI') \
513 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(libdir_SQ)'; \
514 $(INSTALL) $(OUTPUT)libperf-gtk.so '$(DESTDIR_SQ)$(libdir_SQ)'
515endif
516
517ifndef NO_LIBPERL
518 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
519 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
520endif
521
522ifndef NO_LIBPYTHON
523 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
524 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
525endif
526
527ifeq ($(NO_PERF_REGS),0)
528 ifeq ($(ARCH),x86)
529 LIB_H += arch/x86/include/perf_regs.h
530 endif
531endif
532
533ifndef NO_LIBNUMA
534 BUILTIN_OBJS += $(OUTPUT)bench/numa.o
535endif
536
537ifdef ASCIIDOC8
538 export ASCIIDOC8
539endif
540
541LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
542
543export INSTALL SHELL_PATH
544
545### Build rules
546
547SHELL = $(SHELL_PATH)
548
549all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
550
551please_set_SHELL_PATH_to_a_more_modern_shell:
552 @$$(:)
553
554shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
555
556strip: $(PROGRAMS) $(OUTPUT)perf
557 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
558
559$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
560 $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
561 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
562 $(CFLAGS) -c $(filter %.c,$^) -o $@
563
564$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
565 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \
566 $(BUILTIN_OBJS) $(LIBS) -o $@
567
568$(GTK_OBJS): $(OUTPUT)%.o: %.c $(LIB_H)
569 $(QUIET_CC)$(CC) -o $@ -c -fPIC $(CFLAGS) $(GTK_CFLAGS) $<
570
571$(OUTPUT)libperf-gtk.so: $(GTK_OBJS) $(PERFLIBS)
572 $(QUIET_LINK)$(CC) -o $@ -shared $(ALL_LDFLAGS) $(filter %.o,$^) $(GTK_LIBS)
573
574$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
575 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
576 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
577 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
578 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
579
580$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
581 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
582 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
583 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
584 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
585
586$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
587
588$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
589 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
590
591$(SCRIPTS) : % : %.sh
592 $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
593
594# These can record PERF_VERSION
595$(OUTPUT)perf.o perf.spec \
596 $(SCRIPTS) \
597 : $(OUTPUT)PERF-VERSION-FILE
598
599.SUFFIXES:
600
601#
602# If a target does not match any of the later rules then prefix it by $(OUTPUT)
603# This makes targets like 'make O=/tmp/perf perf.o' work in a natural way.
604#
605ifneq ($(OUTPUT),)
606%.o: $(OUTPUT)%.o
607 @echo " # Redirected target $@ => $(OUTPUT)$@"
608util/%.o: $(OUTPUT)util/%.o
609 @echo " # Redirected target $@ => $(OUTPUT)$@"
610bench/%.o: $(OUTPUT)bench/%.o
611 @echo " # Redirected target $@ => $(OUTPUT)$@"
612tests/%.o: $(OUTPUT)tests/%.o
613 @echo " # Redirected target $@ => $(OUTPUT)$@"
614endif
615
616# These two need to be here so that when O= is not used they take precedence
617# over the general rule for .o
618
619$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
620 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $<
621
622$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
623 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
624
625$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
626 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
627$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
628 $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
629$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
630 $(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $<
631$(OUTPUT)%.o: %.S
632 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
633$(OUTPUT)%.s: %.S
634 $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
635
636$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
637 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
638 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
639 '-DPREFIX="$(prefix_SQ)"' \
640 $<
641
642$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
643 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
644 '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
645 $<
646
647$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
648 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
649 -DPYTHONPATH='"$(OUTPUT)python"' \
650 -DPYTHON='"$(PYTHON_WORD)"' \
651 $<
652
653$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
654 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
655
656$(OUTPUT)ui/setup.o: ui/setup.c $(OUTPUT)PERF-CFLAGS
657 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DLIBDIR='"$(libdir_SQ)"' $<
658
659$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
660 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
661
662$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
663 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
664
665$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
666 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
667
668$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
669 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
670
671$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
672 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
673
674$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
675 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
676
677$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
678 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
679
680$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
681 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $<
682
683$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
684 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $<
685
686$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
687 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
688
689$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
690 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
691
692$(OUTPUT)perf-%: %.o $(PERFLIBS)
693 $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
694
695$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
696$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
697
698# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
699# we depend the various files onto their directories.
700DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS)
701DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
702$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
703# In the second step, we make a rule to actually create these directories
704$(sort $(dir $(DIRECTORY_DEPS))):
705 $(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
706
707$(LIB_FILE): $(LIB_OBJS)
708 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
709
710# libtraceevent.a
711TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch])
712
713$(LIBTRACEEVENT): $(TE_SOURCES)
714 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a
715
716$(LIBTRACEEVENT)-clean:
717 $(call QUIET_CLEAN, libtraceevent)
718 @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
719
720LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch])
721
722# if subdir is set, we've been called from above so target has been built
723# already
724$(LIBLK): $(LIBLK_SOURCES)
725ifeq ($(subdir),)
726 $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a
727endif
728
729$(LIBLK)-clean:
730ifeq ($(subdir),)
731 $(call QUIET_CLEAN, liblk)
732 @$(MAKE) -C $(LK_DIR) O=$(OUTPUT) clean >/dev/null
733endif
734
735help:
736 @echo 'Perf make targets:'
737 @echo ' doc - make *all* documentation (see below)'
738 @echo ' man - make manpage documentation (access with man <foo>)'
739 @echo ' html - make html documentation'
740 @echo ' info - make GNU info documentation (access with info <foo>)'
741 @echo ' pdf - make pdf documentation'
742 @echo ' TAGS - use etags to make tag information for source browsing'
743 @echo ' tags - use ctags to make tag information for source browsing'
744 @echo ' cscope - use cscope to make interactive browsing database'
745 @echo ''
746 @echo 'Perf install targets:'
747 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
748 @echo ' HINT: use "make prefix=<path> <install target>" to install to a particular'
749 @echo ' path like make prefix=/usr/local install install-doc'
750 @echo ' install - install compiled binaries'
751 @echo ' install-doc - install *all* documentation'
752 @echo ' install-man - install manpage documentation'
753 @echo ' install-html - install html documentation'
754 @echo ' install-info - install GNU info documentation'
755 @echo ' install-pdf - install pdf documentation'
756 @echo ''
757 @echo ' quick-install-doc - alias for quick-install-man'
758 @echo ' quick-install-man - install the documentation quickly'
759 @echo ' quick-install-html - install the html documentation quickly'
760 @echo ''
761 @echo 'Perf maintainer targets:'
762 @echo ' clean - clean all binary objects and build output'
763
764
765DOC_TARGETS := doc man html info pdf
766
767INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man
768INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
769
770# 'make doc' should call 'make -C Documentation all'
771$(DOC_TARGETS):
772 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
773
774TAGS:
775 $(RM) TAGS
776 $(FIND) . -name '*.[hcS]' -print | xargs etags -a
777
778tags:
779 $(RM) tags
780 $(FIND) . -name '*.[hcS]' -print | xargs ctags -a
781
782cscope:
783 $(RM) cscope*
784 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b
785
786### Detect prefix changes
787TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
788 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
789
790$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
791 @FLAGS='$(TRACK_CFLAGS)'; \
792 if test x"$$FLAGS" != x"`cat $(OUTPUT)PERF-CFLAGS 2>/dev/null`" ; then \
793 echo 1>&2 " FLAGS: * new build flags or prefix"; \
794 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
795 fi
796
797### Testing rules
798
799# GNU make supports exporting all variables by "export" without parameters.
800# However, the environment gets quite big, and some programs have problems
801# with that.
802
803check: $(OUTPUT)common-cmds.h
804 if sparse; \
805 then \
806 for i in *.c */*.c; \
807 do \
808 sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
809 done; \
810 else \
811 exit 1; \
812 fi
813
814### Installation rules
815
816install-gtk:
817
818install-bin: all install-gtk
819 $(call QUIET_INSTALL, binaries) \
820 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \
821 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \
822 $(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace'
823 $(call QUIET_INSTALL, libexec) \
824 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
825 $(call QUIET_INSTALL, perf-archive) \
826 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
827ifndef NO_LIBPERL
828 $(call QUIET_INSTALL, perl-scripts) \
829 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
830 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
831 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'; \
832 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'; \
833 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
834endif
835ifndef NO_LIBPYTHON
836 $(call QUIET_INSTALL, python-scripts) \
837 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
838 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'; \
839 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
840 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \
841 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
842endif
843 $(call QUIET_INSTALL, bash_completion-script) \
844 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \
845 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
846 $(call QUIET_INSTALL, tests) \
847 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
848 $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
849 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
850 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
851
852install: install-bin try-install-man
853
854install-python_ext:
855 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
856
857# 'make install-doc' should call 'make -C Documentation install'
858$(INSTALL_DOC_TARGETS):
859 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=)
860
861### Cleaning rules
862
863#
864# This is here, not in config/Makefile, because config/Makefile does
865# not get included for the clean target:
866#
867config-clean:
868 $(call QUIET_CLEAN, config)
869 @$(MAKE) -C config/feature-checks clean >/dev/null
870
871clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean config-clean
872 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
873 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
874 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
875 $(call QUIET_CLEAN, Documentation)
876 @$(MAKE) -C Documentation O=$(OUTPUT) clean >/dev/null
877 $(python-clean)
878
879#
880# Trick: if ../../.git does not exist - we are building out of tree for example,
881# then force version regeneration:
882#
883ifeq ($(wildcard ../../.git/HEAD),)
884 GIT-HEAD-PHONY = ../../.git/HEAD
885else
886 GIT-HEAD-PHONY =
887endif
888
889.PHONY: all install clean config-clean strip install-gtk
890.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
891.PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope .FORCE-PERF-CFLAGS
892
diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
index 15130b50dfe3..fe9b61e322a5 100644
--- a/tools/perf/arch/arm/Makefile
+++ b/tools/perf/arch/arm/Makefile
@@ -2,3 +2,6 @@ ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5ifndef NO_LIBUNWIND
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
7endif
diff --git a/tools/perf/arch/arm/include/perf_regs.h b/tools/perf/arch/arm/include/perf_regs.h
new file mode 100644
index 000000000000..2a1cfde66b69
--- /dev/null
+++ b/tools/perf/arch/arm/include/perf_regs.h
@@ -0,0 +1,54 @@
1#ifndef ARCH_PERF_REGS_H
2#define ARCH_PERF_REGS_H
3
4#include <stdlib.h>
5#include "../../util/types.h"
6#include <asm/perf_regs.h>
7
8#define PERF_REGS_MASK ((1ULL << PERF_REG_ARM_MAX) - 1)
9#define PERF_REG_IP PERF_REG_ARM_PC
10#define PERF_REG_SP PERF_REG_ARM_SP
11
12static inline const char *perf_reg_name(int id)
13{
14 switch (id) {
15 case PERF_REG_ARM_R0:
16 return "r0";
17 case PERF_REG_ARM_R1:
18 return "r1";
19 case PERF_REG_ARM_R2:
20 return "r2";
21 case PERF_REG_ARM_R3:
22 return "r3";
23 case PERF_REG_ARM_R4:
24 return "r4";
25 case PERF_REG_ARM_R5:
26 return "r5";
27 case PERF_REG_ARM_R6:
28 return "r6";
29 case PERF_REG_ARM_R7:
30 return "r7";
31 case PERF_REG_ARM_R8:
32 return "r8";
33 case PERF_REG_ARM_R9:
34 return "r9";
35 case PERF_REG_ARM_R10:
36 return "r10";
37 case PERF_REG_ARM_FP:
38 return "fp";
39 case PERF_REG_ARM_IP:
40 return "ip";
41 case PERF_REG_ARM_SP:
42 return "sp";
43 case PERF_REG_ARM_LR:
44 return "lr";
45 case PERF_REG_ARM_PC:
46 return "pc";
47 default:
48 return NULL;
49 }
50
51 return NULL;
52}
53
54#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/arch/arm/util/unwind.c b/tools/perf/arch/arm/util/unwind.c
new file mode 100644
index 000000000000..da3dc950550c
--- /dev/null
+++ b/tools/perf/arch/arm/util/unwind.c
@@ -0,0 +1,48 @@
1
2#include <errno.h>
3#include <libunwind.h>
4#include "perf_regs.h"
5#include "../../util/unwind.h"
6
7int unwind__arch_reg_id(int regnum)
8{
9 switch (regnum) {
10 case UNW_ARM_R0:
11 return PERF_REG_ARM_R0;
12 case UNW_ARM_R1:
13 return PERF_REG_ARM_R1;
14 case UNW_ARM_R2:
15 return PERF_REG_ARM_R2;
16 case UNW_ARM_R3:
17 return PERF_REG_ARM_R3;
18 case UNW_ARM_R4:
19 return PERF_REG_ARM_R4;
20 case UNW_ARM_R5:
21 return PERF_REG_ARM_R5;
22 case UNW_ARM_R6:
23 return PERF_REG_ARM_R6;
24 case UNW_ARM_R7:
25 return PERF_REG_ARM_R7;
26 case UNW_ARM_R8:
27 return PERF_REG_ARM_R8;
28 case UNW_ARM_R9:
29 return PERF_REG_ARM_R9;
30 case UNW_ARM_R10:
31 return PERF_REG_ARM_R10;
32 case UNW_ARM_R11:
33 return PERF_REG_ARM_FP;
34 case UNW_ARM_R12:
35 return PERF_REG_ARM_IP;
36 case UNW_ARM_R13:
37 return PERF_REG_ARM_SP;
38 case UNW_ARM_R14:
39 return PERF_REG_ARM_LR;
40 case UNW_ARM_R15:
41 return PERF_REG_ARM_PC;
42 default:
43 pr_err("unwind: invalid reg id %d\n", regnum);
44 return -EINVAL;
45 }
46
47 return -EINVAL;
48}
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index 7fcdcdbee917..e84ca76aae77 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -5,7 +5,7 @@
5#include "../../util/types.h" 5#include "../../util/types.h"
6#include <asm/perf_regs.h> 6#include <asm/perf_regs.h>
7 7
8#ifndef ARCH_X86_64 8#ifndef HAVE_ARCH_X86_64_SUPPORT
9#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1) 9#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
10#else 10#else
11#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \ 11#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
@@ -52,7 +52,7 @@ static inline const char *perf_reg_name(int id)
52 return "FS"; 52 return "FS";
53 case PERF_REG_X86_GS: 53 case PERF_REG_X86_GS:
54 return "GS"; 54 return "GS";
55#ifdef ARCH_X86_64 55#ifdef HAVE_ARCH_X86_64_SUPPORT
56 case PERF_REG_X86_R8: 56 case PERF_REG_X86_R8:
57 return "R8"; 57 return "R8";
58 case PERF_REG_X86_R9: 58 case PERF_REG_X86_R9:
@@ -69,7 +69,7 @@ static inline const char *perf_reg_name(int id)
69 return "R14"; 69 return "R14";
70 case PERF_REG_X86_R15: 70 case PERF_REG_X86_R15:
71 return "R15"; 71 return "R15";
72#endif /* ARCH_X86_64 */ 72#endif /* HAVE_ARCH_X86_64_SUPPORT */
73 default: 73 default:
74 return NULL; 74 return NULL;
75 } 75 }
diff --git a/tools/perf/arch/x86/util/unwind.c b/tools/perf/arch/x86/util/unwind.c
index 78d956eff96f..456a88cf5b37 100644
--- a/tools/perf/arch/x86/util/unwind.c
+++ b/tools/perf/arch/x86/util/unwind.c
@@ -4,7 +4,7 @@
4#include "perf_regs.h" 4#include "perf_regs.h"
5#include "../../util/unwind.h" 5#include "../../util/unwind.h"
6 6
7#ifdef ARCH_X86_64 7#ifdef HAVE_ARCH_X86_64_SUPPORT
8int unwind__arch_reg_id(int regnum) 8int unwind__arch_reg_id(int regnum)
9{ 9{
10 int id; 10 int id;
@@ -108,4 +108,4 @@ int unwind__arch_reg_id(int regnum)
108 108
109 return id; 109 return id;
110} 110}
111#endif /* ARCH_X86_64 */ 111#endif /* HAVE_ARCH_X86_64_SUPPORT */
diff --git a/tools/perf/bash_completion b/tools/perf/bash_completion
index 56e6a12aab59..62e157db2e2b 100644
--- a/tools/perf/bash_completion
+++ b/tools/perf/bash_completion
@@ -1,17 +1,87 @@
1# perf completion 1# perf completion
2 2
3function_exists() 3# Taken from git.git's completion script.
4__my_reassemble_comp_words_by_ref()
4{ 5{
5 declare -F $1 > /dev/null 6 local exclude i j first
6 return $? 7 # Which word separators to exclude?
8 exclude="${1//[^$COMP_WORDBREAKS]}"
9 cword_=$COMP_CWORD
10 if [ -z "$exclude" ]; then
11 words_=("${COMP_WORDS[@]}")
12 return
13 fi
14 # List of word completion separators has shrunk;
15 # re-assemble words to complete.
16 for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
17 # Append each nonempty word consisting of just
18 # word separator characters to the current word.
19 first=t
20 while
21 [ $i -gt 0 ] &&
22 [ -n "${COMP_WORDS[$i]}" ] &&
23 # word consists of excluded word separators
24 [ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
25 do
26 # Attach to the previous token,
27 # unless the previous token is the command name.
28 if [ $j -ge 2 ] && [ -n "$first" ]; then
29 ((j--))
30 fi
31 first=
32 words_[$j]=${words_[j]}${COMP_WORDS[i]}
33 if [ $i = $COMP_CWORD ]; then
34 cword_=$j
35 fi
36 if (($i < ${#COMP_WORDS[@]} - 1)); then
37 ((i++))
38 else
39 # Done.
40 return
41 fi
42 done
43 words_[$j]=${words_[j]}${COMP_WORDS[i]}
44 if [ $i = $COMP_CWORD ]; then
45 cword_=$j
46 fi
47 done
7} 48}
8 49
9function_exists __ltrim_colon_completions || 50type _get_comp_words_by_ref &>/dev/null ||
51_get_comp_words_by_ref()
52{
53 local exclude cur_ words_ cword_
54 if [ "$1" = "-n" ]; then
55 exclude=$2
56 shift 2
57 fi
58 __my_reassemble_comp_words_by_ref "$exclude"
59 cur_=${words_[cword_]}
60 while [ $# -gt 0 ]; do
61 case "$1" in
62 cur)
63 cur=$cur_
64 ;;
65 prev)
66 prev=${words_[$cword_-1]}
67 ;;
68 words)
69 words=("${words_[@]}")
70 ;;
71 cword)
72 cword=$cword_
73 ;;
74 esac
75 shift
76 done
77}
78
79type __ltrim_colon_completions &>/dev/null ||
10__ltrim_colon_completions() 80__ltrim_colon_completions()
11{ 81{
12 if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then 82 if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
13 # Remove colon-word prefix from COMPREPLY items 83 # Remove colon-word prefix from COMPREPLY items
14 local colon_word=${1%${1##*:}} 84 local colon_word=${1%"${1##*:}"}
15 local i=${#COMPREPLY[*]} 85 local i=${#COMPREPLY[*]}
16 while [[ $((--i)) -ge 0 ]]; do 86 while [[ $((--i)) -ge 0 ]]; do
17 COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} 87 COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
@@ -19,23 +89,18 @@ __ltrim_colon_completions()
19 fi 89 fi
20} 90}
21 91
22have perf && 92type perf &>/dev/null &&
23_perf() 93_perf()
24{ 94{
25 local cur prev cmd 95 local cur words cword prev cmd
26 96
27 COMPREPLY=() 97 COMPREPLY=()
28 if function_exists _get_comp_words_by_ref; then 98 _get_comp_words_by_ref -n =: cur words cword prev
29 _get_comp_words_by_ref -n : cur prev
30 else
31 cur=$(_get_cword :)
32 prev=${COMP_WORDS[COMP_CWORD-1]}
33 fi
34 99
35 cmd=${COMP_WORDS[0]} 100 cmd=${words[0]}
36 101
37 # List perf subcommands or long options 102 # List perf subcommands or long options
38 if [ $COMP_CWORD -eq 1 ]; then 103 if [ $cword -eq 1 ]; then
39 if [[ $cur == --* ]]; then 104 if [[ $cur == --* ]]; then
40 COMPREPLY=( $( compgen -W '--help --version \ 105 COMPREPLY=( $( compgen -W '--help --version \
41 --exec-path --html-path --paginate --no-pager \ 106 --exec-path --html-path --paginate --no-pager \
@@ -45,18 +110,17 @@ _perf()
45 COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) 110 COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) )
46 fi 111 fi
47 # List possible events for -e option 112 # List possible events for -e option
48 elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then 113 elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then
49 evts=$($cmd list --raw-dump) 114 evts=$($cmd list --raw-dump)
50 COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) ) 115 COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) )
51 __ltrim_colon_completions $cur 116 __ltrim_colon_completions $cur
52 # List long option names 117 # List long option names
53 elif [[ $cur == --* ]]; then 118 elif [[ $cur == --* ]]; then
54 subcmd=${COMP_WORDS[1]} 119 subcmd=${words[1]}
55 opts=$($cmd $subcmd --list-opts) 120 opts=$($cmd $subcmd --list-opts)
56 COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) ) 121 COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) )
57 # Fall down to list regular files
58 else
59 _filedir
60 fi 122 fi
61} && 123} &&
62complete -F _perf perf 124
125complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \
126 || complete -o default -o nospace -F _perf perf
diff --git a/tools/perf/bench/mem-memcpy-arch.h b/tools/perf/bench/mem-memcpy-arch.h
index a72e36cb5394..57b4ed871459 100644
--- a/tools/perf/bench/mem-memcpy-arch.h
+++ b/tools/perf/bench/mem-memcpy-arch.h
@@ -1,5 +1,5 @@
1 1
2#ifdef ARCH_X86_64 2#ifdef HAVE_ARCH_X86_64_SUPPORT
3 3
4#define MEMCPY_FN(fn, name, desc) \ 4#define MEMCPY_FN(fn, name, desc) \
5 extern void *fn(void *, const void *, size_t); 5 extern void *fn(void *, const void *, size_t);
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index 8cdca43016b2..5ce71d3b72cf 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -58,7 +58,7 @@ struct routine routines[] = {
58 { "default", 58 { "default",
59 "Default memcpy() provided by glibc", 59 "Default memcpy() provided by glibc",
60 memcpy }, 60 memcpy },
61#ifdef ARCH_X86_64 61#ifdef HAVE_ARCH_X86_64_SUPPORT
62 62
63#define MEMCPY_FN(fn, name, desc) { name, desc, fn }, 63#define MEMCPY_FN(fn, name, desc) { name, desc, fn },
64#include "mem-memcpy-x86-64-asm-def.h" 64#include "mem-memcpy-x86-64-asm-def.h"
diff --git a/tools/perf/bench/mem-memset-arch.h b/tools/perf/bench/mem-memset-arch.h
index a040fa77665b..633800cb0dcb 100644
--- a/tools/perf/bench/mem-memset-arch.h
+++ b/tools/perf/bench/mem-memset-arch.h
@@ -1,5 +1,5 @@
1 1
2#ifdef ARCH_X86_64 2#ifdef HAVE_ARCH_X86_64_SUPPORT
3 3
4#define MEMSET_FN(fn, name, desc) \ 4#define MEMSET_FN(fn, name, desc) \
5 extern void *fn(void *, int, size_t); 5 extern void *fn(void *, int, size_t);
diff --git a/tools/perf/bench/mem-memset.c b/tools/perf/bench/mem-memset.c
index 4a2f12081964..9af79d2b18e5 100644
--- a/tools/perf/bench/mem-memset.c
+++ b/tools/perf/bench/mem-memset.c
@@ -58,7 +58,7 @@ static const struct routine routines[] = {
58 { "default", 58 { "default",
59 "Default memset() provided by glibc", 59 "Default memset() provided by glibc",
60 memset }, 60 memset },
61#ifdef ARCH_X86_64 61#ifdef HAVE_ARCH_X86_64_SUPPORT
62 62
63#define MEMSET_FN(fn, name, desc) { name, desc, fn }, 63#define MEMSET_FN(fn, name, desc) { name, desc, fn },
64#include "mem-memset-x86-64-asm-def.h" 64#include "mem-memset-x86-64-asm-def.h"
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
index 30d1c3225b46..d4c83c60b9b2 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -429,14 +429,14 @@ static int parse_cpu_list(const char *arg)
429 return 0; 429 return 0;
430} 430}
431 431
432static void parse_setup_cpu_list(void) 432static int parse_setup_cpu_list(void)
433{ 433{
434 struct thread_data *td; 434 struct thread_data *td;
435 char *str0, *str; 435 char *str0, *str;
436 int t; 436 int t;
437 437
438 if (!g->p.cpu_list_str) 438 if (!g->p.cpu_list_str)
439 return; 439 return 0;
440 440
441 dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks); 441 dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
442 442
@@ -500,8 +500,12 @@ static void parse_setup_cpu_list(void)
500 500
501 dprintf("CPUs: %d_%d-%d#%dx%d\n", bind_cpu_0, bind_len, bind_cpu_1, step, mul); 501 dprintf("CPUs: %d_%d-%d#%dx%d\n", bind_cpu_0, bind_len, bind_cpu_1, step, mul);
502 502
503 BUG_ON(bind_cpu_0 < 0 || bind_cpu_0 >= g->p.nr_cpus); 503 if (bind_cpu_0 >= g->p.nr_cpus || bind_cpu_1 >= g->p.nr_cpus) {
504 BUG_ON(bind_cpu_1 < 0 || bind_cpu_1 >= g->p.nr_cpus); 504 printf("\nTest not applicable, system has only %d CPUs.\n", g->p.nr_cpus);
505 return -1;
506 }
507
508 BUG_ON(bind_cpu_0 < 0 || bind_cpu_1 < 0);
505 BUG_ON(bind_cpu_0 > bind_cpu_1); 509 BUG_ON(bind_cpu_0 > bind_cpu_1);
506 510
507 for (bind_cpu = bind_cpu_0; bind_cpu <= bind_cpu_1; bind_cpu += step) { 511 for (bind_cpu = bind_cpu_0; bind_cpu <= bind_cpu_1; bind_cpu += step) {
@@ -541,6 +545,7 @@ out:
541 printf("# NOTE: %d tasks bound, %d tasks unbound\n", t, g->p.nr_tasks - t); 545 printf("# NOTE: %d tasks bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
542 546
543 free(str0); 547 free(str0);
548 return 0;
544} 549}
545 550
546static int parse_cpus_opt(const struct option *opt __maybe_unused, 551static int parse_cpus_opt(const struct option *opt __maybe_unused,
@@ -561,14 +566,14 @@ static int parse_node_list(const char *arg)
561 return 0; 566 return 0;
562} 567}
563 568
564static void parse_setup_node_list(void) 569static int parse_setup_node_list(void)
565{ 570{
566 struct thread_data *td; 571 struct thread_data *td;
567 char *str0, *str; 572 char *str0, *str;
568 int t; 573 int t;
569 574
570 if (!g->p.node_list_str) 575 if (!g->p.node_list_str)
571 return; 576 return 0;
572 577
573 dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks); 578 dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
574 579
@@ -619,8 +624,12 @@ static void parse_setup_node_list(void)
619 624
620 dprintf("NODEs: %d-%d #%d\n", bind_node_0, bind_node_1, step); 625 dprintf("NODEs: %d-%d #%d\n", bind_node_0, bind_node_1, step);
621 626
622 BUG_ON(bind_node_0 < 0 || bind_node_0 >= g->p.nr_nodes); 627 if (bind_node_0 >= g->p.nr_nodes || bind_node_1 >= g->p.nr_nodes) {
623 BUG_ON(bind_node_1 < 0 || bind_node_1 >= g->p.nr_nodes); 628 printf("\nTest not applicable, system has only %d nodes.\n", g->p.nr_nodes);
629 return -1;
630 }
631
632 BUG_ON(bind_node_0 < 0 || bind_node_1 < 0);
624 BUG_ON(bind_node_0 > bind_node_1); 633 BUG_ON(bind_node_0 > bind_node_1);
625 634
626 for (bind_node = bind_node_0; bind_node <= bind_node_1; bind_node += step) { 635 for (bind_node = bind_node_0; bind_node <= bind_node_1; bind_node += step) {
@@ -651,6 +660,7 @@ out:
651 printf("# NOTE: %d tasks mem-bound, %d tasks unbound\n", t, g->p.nr_tasks - t); 660 printf("# NOTE: %d tasks mem-bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
652 661
653 free(str0); 662 free(str0);
663 return 0;
654} 664}
655 665
656static int parse_nodes_opt(const struct option *opt __maybe_unused, 666static int parse_nodes_opt(const struct option *opt __maybe_unused,
@@ -1110,7 +1120,7 @@ static void *worker_thread(void *__tdata)
1110 /* Check whether our max runtime timed out: */ 1120 /* Check whether our max runtime timed out: */
1111 if (g->p.nr_secs) { 1121 if (g->p.nr_secs) {
1112 timersub(&stop, &start0, &diff); 1122 timersub(&stop, &start0, &diff);
1113 if (diff.tv_sec >= g->p.nr_secs) { 1123 if ((u32)diff.tv_sec >= g->p.nr_secs) {
1114 g->stop_work = true; 1124 g->stop_work = true;
1115 break; 1125 break;
1116 } 1126 }
@@ -1157,7 +1167,7 @@ static void *worker_thread(void *__tdata)
1157 runtime_ns_max += diff.tv_usec * 1000; 1167 runtime_ns_max += diff.tv_usec * 1000;
1158 1168
1159 if (details >= 0) { 1169 if (details >= 0) {
1160 printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016lx]\n", 1170 printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016"PRIx64"]\n",
1161 process_nr, thread_nr, runtime_ns_max / bytes_done, val); 1171 process_nr, thread_nr, runtime_ns_max / bytes_done, val);
1162 } 1172 }
1163 fflush(stdout); 1173 fflush(stdout);
@@ -1356,8 +1366,8 @@ static int init(void)
1356 init_thread_data(); 1366 init_thread_data();
1357 1367
1358 tprintf("#\n"); 1368 tprintf("#\n");
1359 parse_setup_cpu_list(); 1369 if (parse_setup_cpu_list() || parse_setup_node_list())
1360 parse_setup_node_list(); 1370 return -1;
1361 tprintf("#\n"); 1371 tprintf("#\n");
1362 1372
1363 print_summary(); 1373 print_summary();
@@ -1600,7 +1610,6 @@ static int run_bench_numa(const char *name, const char **argv)
1600 return 0; 1610 return 0;
1601 1611
1602err: 1612err:
1603 usage_with_options(numa_usage, options);
1604 return -1; 1613 return -1;
1605} 1614}
1606 1615
@@ -1701,8 +1710,7 @@ static int bench_all(void)
1701 BUG_ON(ret < 0); 1710 BUG_ON(ret < 0);
1702 1711
1703 for (i = 0; i < nr; i++) { 1712 for (i = 0; i < nr; i++) {
1704 if (run_bench_numa(tests[i][0], tests[i] + 1)) 1713 run_bench_numa(tests[i][0], tests[i] + 1);
1705 return -1;
1706 } 1714 }
1707 1715
1708 printf("\n"); 1716 printf("\n");
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index 69cfba8d4c6c..07a8d7646a15 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -7,9 +7,7 @@
7 * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com> 7 * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com>
8 * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c 8 * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c
9 * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> 9 * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
10 *
11 */ 10 */
12
13#include "../perf.h" 11#include "../perf.h"
14#include "../util/util.h" 12#include "../util/util.h"
15#include "../util/parse-options.h" 13#include "../util/parse-options.h"
@@ -28,12 +26,24 @@
28#include <sys/time.h> 26#include <sys/time.h>
29#include <sys/types.h> 27#include <sys/types.h>
30 28
29#include <pthread.h>
30
31struct thread_data {
32 int nr;
33 int pipe_read;
34 int pipe_write;
35 pthread_t pthread;
36};
37
31#define LOOPS_DEFAULT 1000000 38#define LOOPS_DEFAULT 1000000
32static int loops = LOOPS_DEFAULT; 39static int loops = LOOPS_DEFAULT;
40
41/* Use processes by default: */
42static bool threaded;
33 43
34static const struct option options[] = { 44static const struct option options[] = {
35 OPT_INTEGER('l', "loop", &loops, 45 OPT_INTEGER('l', "loop", &loops, "Specify number of loops"),
36 "Specify number of loops"), 46 OPT_BOOLEAN('T', "threaded", &threaded, "Specify threads/process based task setup"),
37 OPT_END() 47 OPT_END()
38}; 48};
39 49
@@ -42,13 +52,37 @@ static const char * const bench_sched_pipe_usage[] = {
42 NULL 52 NULL
43}; 53};
44 54
45int bench_sched_pipe(int argc, const char **argv, 55static void *worker_thread(void *__tdata)
46 const char *prefix __maybe_unused)
47{ 56{
48 int pipe_1[2], pipe_2[2]; 57 struct thread_data *td = __tdata;
49 int m = 0, i; 58 int m = 0, i;
59 int ret;
60
61 for (i = 0; i < loops; i++) {
62 if (!td->nr) {
63 ret = read(td->pipe_read, &m, sizeof(int));
64 BUG_ON(ret != sizeof(int));
65 ret = write(td->pipe_write, &m, sizeof(int));
66 BUG_ON(ret != sizeof(int));
67 } else {
68 ret = write(td->pipe_write, &m, sizeof(int));
69 BUG_ON(ret != sizeof(int));
70 ret = read(td->pipe_read, &m, sizeof(int));
71 BUG_ON(ret != sizeof(int));
72 }
73 }
74
75 return NULL;
76}
77
78int bench_sched_pipe(int argc, const char **argv, const char *prefix __maybe_unused)
79{
80 struct thread_data threads[2], *td;
81 int pipe_1[2], pipe_2[2];
50 struct timeval start, stop, diff; 82 struct timeval start, stop, diff;
51 unsigned long long result_usec = 0; 83 unsigned long long result_usec = 0;
84 int nr_threads = 2;
85 int t;
52 86
53 /* 87 /*
54 * why does "ret" exist? 88 * why does "ret" exist?
@@ -58,43 +92,66 @@ int bench_sched_pipe(int argc, const char **argv,
58 int __maybe_unused ret, wait_stat; 92 int __maybe_unused ret, wait_stat;
59 pid_t pid, retpid __maybe_unused; 93 pid_t pid, retpid __maybe_unused;
60 94
61 argc = parse_options(argc, argv, options, 95 argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0);
62 bench_sched_pipe_usage, 0);
63 96
64 BUG_ON(pipe(pipe_1)); 97 BUG_ON(pipe(pipe_1));
65 BUG_ON(pipe(pipe_2)); 98 BUG_ON(pipe(pipe_2));
66 99
67 pid = fork();
68 assert(pid >= 0);
69
70 gettimeofday(&start, NULL); 100 gettimeofday(&start, NULL);
71 101
72 if (!pid) { 102 for (t = 0; t < nr_threads; t++) {
73 for (i = 0; i < loops; i++) { 103 td = threads + t;
74 ret = read(pipe_1[0], &m, sizeof(int)); 104
75 ret = write(pipe_2[1], &m, sizeof(int)); 105 td->nr = t;
76 } 106
77 } else { 107 if (t == 0) {
78 for (i = 0; i < loops; i++) { 108 td->pipe_read = pipe_1[0];
79 ret = write(pipe_1[1], &m, sizeof(int)); 109 td->pipe_write = pipe_2[1];
80 ret = read(pipe_2[0], &m, sizeof(int)); 110 } else {
111 td->pipe_write = pipe_1[1];
112 td->pipe_read = pipe_2[0];
81 } 113 }
82 } 114 }
83 115
84 gettimeofday(&stop, NULL);
85 timersub(&stop, &start, &diff);
86 116
87 if (pid) { 117 if (threaded) {
118
119 for (t = 0; t < nr_threads; t++) {
120 td = threads + t;
121
122 ret = pthread_create(&td->pthread, NULL, worker_thread, td);
123 BUG_ON(ret);
124 }
125
126 for (t = 0; t < nr_threads; t++) {
127 td = threads + t;
128
129 ret = pthread_join(td->pthread, NULL);
130 BUG_ON(ret);
131 }
132
133 } else {
134 pid = fork();
135 assert(pid >= 0);
136
137 if (!pid) {
138 worker_thread(threads + 0);
139 exit(0);
140 } else {
141 worker_thread(threads + 1);
142 }
143
88 retpid = waitpid(pid, &wait_stat, 0); 144 retpid = waitpid(pid, &wait_stat, 0);
89 assert((retpid == pid) && WIFEXITED(wait_stat)); 145 assert((retpid == pid) && WIFEXITED(wait_stat));
90 } else {
91 exit(0);
92 } 146 }
93 147
148 gettimeofday(&stop, NULL);
149 timersub(&stop, &start, &diff);
150
94 switch (bench_format) { 151 switch (bench_format) {
95 case BENCH_FORMAT_DEFAULT: 152 case BENCH_FORMAT_DEFAULT:
96 printf("# Executed %d pipe operations between two tasks\n\n", 153 printf("# Executed %d pipe operations between two %s\n\n",
97 loops); 154 loops, threaded ? "threads" : "processes");
98 155
99 result_usec = diff.tv_sec * 1000000; 156 result_usec = diff.tv_sec * 1000000;
100 result_usec += diff.tv_usec; 157 result_usec += diff.tv_usec;
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 5ebd0c3b71b6..4087ab19823c 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -28,8 +28,10 @@
28#include "util/hist.h" 28#include "util/hist.h"
29#include "util/session.h" 29#include "util/session.h"
30#include "util/tool.h" 30#include "util/tool.h"
31#include "util/data.h"
31#include "arch/common.h" 32#include "arch/common.h"
32 33
34#include <dlfcn.h>
33#include <linux/bitmap.h> 35#include <linux/bitmap.h>
34 36
35struct perf_annotate { 37struct perf_annotate {
@@ -63,7 +65,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
63 return 0; 65 return 0;
64 } 66 }
65 67
66 he = __hists__add_entry(&evsel->hists, al, NULL, 1, 1); 68 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0);
67 if (he == NULL) 69 if (he == NULL)
68 return -ENOMEM; 70 return -ENOMEM;
69 71
@@ -116,11 +118,11 @@ static int hist_entry__tty_annotate(struct hist_entry *he,
116 ann->print_line, ann->full_paths, 0, 0); 118 ann->print_line, ann->full_paths, 0, 0);
117} 119}
118 120
119static void hists__find_annotations(struct hists *self, 121static void hists__find_annotations(struct hists *hists,
120 struct perf_evsel *evsel, 122 struct perf_evsel *evsel,
121 struct perf_annotate *ann) 123 struct perf_annotate *ann)
122{ 124{
123 struct rb_node *nd = rb_first(&self->entries), *next; 125 struct rb_node *nd = rb_first(&hists->entries), *next;
124 int key = K_RIGHT; 126 int key = K_RIGHT;
125 127
126 while (nd) { 128 while (nd) {
@@ -142,8 +144,18 @@ find_next:
142 144
143 if (use_browser == 2) { 145 if (use_browser == 2) {
144 int ret; 146 int ret;
147 int (*annotate)(struct hist_entry *he,
148 struct perf_evsel *evsel,
149 struct hist_browser_timer *hbt);
150
151 annotate = dlsym(perf_gtk_handle,
152 "hist_entry__gtk_annotate");
153 if (annotate == NULL) {
154 ui__error("GTK browser not found!\n");
155 return;
156 }
145 157
146 ret = hist_entry__gtk_annotate(he, evsel, NULL); 158 ret = annotate(he, evsel, NULL);
147 if (!ret || !ann->skip_missing) 159 if (!ret || !ann->skip_missing)
148 return; 160 return;
149 161
@@ -188,9 +200,13 @@ static int __cmd_annotate(struct perf_annotate *ann)
188 struct perf_session *session; 200 struct perf_session *session;
189 struct perf_evsel *pos; 201 struct perf_evsel *pos;
190 u64 total_nr_samples; 202 u64 total_nr_samples;
203 struct perf_data_file file = {
204 .path = input_name,
205 .mode = PERF_DATA_MODE_READ,
206 .force = ann->force,
207 };
191 208
192 session = perf_session__new(input_name, O_RDONLY, 209 session = perf_session__new(&file, false, &ann->tool);
193 ann->force, false, &ann->tool);
194 if (session == NULL) 210 if (session == NULL)
195 return -ENOMEM; 211 return -ENOMEM;
196 212
@@ -231,7 +247,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
231 247
232 if (nr_samples > 0) { 248 if (nr_samples > 0) {
233 total_nr_samples += nr_samples; 249 total_nr_samples += nr_samples;
234 hists__collapse_resort(hists); 250 hists__collapse_resort(hists, NULL);
235 hists__output_resort(hists); 251 hists__output_resort(hists);
236 252
237 if (symbol_conf.event_group && 253 if (symbol_conf.event_group &&
@@ -243,12 +259,21 @@ static int __cmd_annotate(struct perf_annotate *ann)
243 } 259 }
244 260
245 if (total_nr_samples == 0) { 261 if (total_nr_samples == 0) {
246 ui__error("The %s file has no samples!\n", session->filename); 262 ui__error("The %s file has no samples!\n", file.path);
247 goto out_delete; 263 goto out_delete;
248 } 264 }
249 265
250 if (use_browser == 2) 266 if (use_browser == 2) {
251 perf_gtk__show_annotations(); 267 void (*show_annotations)(void);
268
269 show_annotations = dlsym(perf_gtk_handle,
270 "perf_gtk__show_annotations");
271 if (show_annotations == NULL) {
272 ui__error("GTK browser not found!\n");
273 goto out_delete;
274 }
275 show_annotations();
276 }
252 277
253out_delete: 278out_delete:
254 /* 279 /*
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index 77298bf892b8..e47f90cc7b98 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -1,21 +1,18 @@
1/* 1/*
2 *
3 * builtin-bench.c 2 * builtin-bench.c
4 * 3 *
5 * General benchmarking subsystem provided by perf 4 * General benchmarking collections provided by perf
6 * 5 *
7 * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> 6 * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
8 *
9 */ 7 */
10 8
11/* 9/*
10 * Available benchmark collection list:
12 * 11 *
13 * Available subsystem list: 12 * sched ... scheduler and IPC performance
14 * sched ... scheduler and IPC mechanism
15 * mem ... memory access performance 13 * mem ... memory access performance
16 * 14 * numa ... NUMA scheduling and MM performance
17 */ 15 */
18
19#include "perf.h" 16#include "perf.h"
20#include "util/util.h" 17#include "util/util.h"
21#include "util/parse-options.h" 18#include "util/parse-options.h"
@@ -25,112 +22,92 @@
25#include <stdio.h> 22#include <stdio.h>
26#include <stdlib.h> 23#include <stdlib.h>
27#include <string.h> 24#include <string.h>
25#include <sys/prctl.h>
28 26
29struct bench_suite { 27typedef int (*bench_fn_t)(int argc, const char **argv, const char *prefix);
30 const char *name; 28
31 const char *summary; 29struct bench {
32 int (*fn)(int, const char **, const char *); 30 const char *name;
31 const char *summary;
32 bench_fn_t fn;
33}; 33};
34 \ 34
35/* sentinel: easy for help */ 35#ifdef HAVE_LIBNUMA_SUPPORT
36#define suite_all { "all", "Test all benchmark suites", NULL } 36static struct bench numa_benchmarks[] = {
37 37 { "mem", "Benchmark for NUMA workloads", bench_numa },
38#ifdef LIBNUMA_SUPPORT 38 { "all", "Test all NUMA benchmarks", NULL },
39static struct bench_suite numa_suites[] = { 39 { NULL, NULL, NULL }
40 { "mem",
41 "Benchmark for NUMA workloads",
42 bench_numa },
43 suite_all,
44 { NULL,
45 NULL,
46 NULL }
47}; 40};
48#endif 41#endif
49 42
50static struct bench_suite sched_suites[] = { 43static struct bench sched_benchmarks[] = {
51 { "messaging", 44 { "messaging", "Benchmark for scheduling and IPC", bench_sched_messaging },
52 "Benchmark for scheduler and IPC mechanisms", 45 { "pipe", "Benchmark for pipe() between two processes", bench_sched_pipe },
53 bench_sched_messaging }, 46 { "all", "Test all scheduler benchmarks", NULL },
54 { "pipe", 47 { NULL, NULL, NULL }
55 "Flood of communication over pipe() between two processes",
56 bench_sched_pipe },
57 suite_all,
58 { NULL,
59 NULL,
60 NULL }
61}; 48};
62 49
63static struct bench_suite mem_suites[] = { 50static struct bench mem_benchmarks[] = {
64 { "memcpy", 51 { "memcpy", "Benchmark for memcpy()", bench_mem_memcpy },
65 "Simple memory copy in various ways", 52 { "memset", "Benchmark for memset() tests", bench_mem_memset },
66 bench_mem_memcpy }, 53 { "all", "Test all memory benchmarks", NULL },
67 { "memset", 54 { NULL, NULL, NULL }
68 "Simple memory set in various ways",
69 bench_mem_memset },
70 suite_all,
71 { NULL,
72 NULL,
73 NULL }
74}; 55};
75 56
76struct bench_subsys { 57struct collection {
77 const char *name; 58 const char *name;
78 const char *summary; 59 const char *summary;
79 struct bench_suite *suites; 60 struct bench *benchmarks;
80}; 61};
81 62
82static struct bench_subsys subsystems[] = { 63static struct collection collections[] = {
83#ifdef LIBNUMA_SUPPORT 64 { "sched", "Scheduler and IPC benchmarks", sched_benchmarks },
84 { "numa", 65 { "mem", "Memory access benchmarks", mem_benchmarks },
85 "NUMA scheduling and MM behavior", 66#ifdef HAVE_LIBNUMA_SUPPORT
86 numa_suites }, 67 { "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks },
87#endif 68#endif
88 { "sched", 69 { "all", "All benchmarks", NULL },
89 "scheduler and IPC mechanism", 70 { NULL, NULL, NULL }
90 sched_suites },
91 { "mem",
92 "memory access performance",
93 mem_suites },
94 { "all", /* sentinel: easy for help */
95 "all benchmark subsystem",
96 NULL },
97 { NULL,
98 NULL,
99 NULL }
100}; 71};
101 72
102static void dump_suites(int subsys_index) 73/* Iterate over all benchmark collections: */
74#define for_each_collection(coll) \
75 for (coll = collections; coll->name; coll++)
76
77/* Iterate over all benchmarks within a collection: */
78#define for_each_bench(coll, bench) \
79 for (bench = coll->benchmarks; bench->name; bench++)
80
81static void dump_benchmarks(struct collection *coll)
103{ 82{
104 int i; 83 struct bench *bench;
105 84
106 printf("# List of available suites for %s...\n\n", 85 printf("\n # List of available benchmarks for collection '%s':\n\n", coll->name);
107 subsystems[subsys_index].name);
108 86
109 for (i = 0; subsystems[subsys_index].suites[i].name; i++) 87 for_each_bench(coll, bench)
110 printf("%14s: %s\n", 88 printf("%14s: %s\n", bench->name, bench->summary);
111 subsystems[subsys_index].suites[i].name,
112 subsystems[subsys_index].suites[i].summary);
113 89
114 printf("\n"); 90 printf("\n");
115 return;
116} 91}
117 92
118static const char *bench_format_str; 93static const char *bench_format_str;
94
95/* Output/formatting style, exported to benchmark modules: */
119int bench_format = BENCH_FORMAT_DEFAULT; 96int bench_format = BENCH_FORMAT_DEFAULT;
120 97
121static const struct option bench_options[] = { 98static const struct option bench_options[] = {
122 OPT_STRING('f', "format", &bench_format_str, "default", 99 OPT_STRING('f', "format", &bench_format_str, "default", "Specify format style"),
123 "Specify format style"),
124 OPT_END() 100 OPT_END()
125}; 101};
126 102
127static const char * const bench_usage[] = { 103static const char * const bench_usage[] = {
128 "perf bench [<common options>] <subsystem> <suite> [<options>]", 104 "perf bench [<common options>] <collection> <benchmark> [<options>]",
129 NULL 105 NULL
130}; 106};
131 107
132static void print_usage(void) 108static void print_usage(void)
133{ 109{
110 struct collection *coll;
134 int i; 111 int i;
135 112
136 printf("Usage: \n"); 113 printf("Usage: \n");
@@ -138,11 +115,10 @@ static void print_usage(void)
138 printf("\t%s\n", bench_usage[i]); 115 printf("\t%s\n", bench_usage[i]);
139 printf("\n"); 116 printf("\n");
140 117
141 printf("# List of available subsystems...\n\n"); 118 printf(" # List of all available benchmark collections:\n\n");
142 119
143 for (i = 0; subsystems[i].name; i++) 120 for_each_collection(coll)
144 printf("%14s: %s\n", 121 printf("%14s: %s\n", coll->name, coll->summary);
145 subsystems[i].name, subsystems[i].summary);
146 printf("\n"); 122 printf("\n");
147} 123}
148 124
@@ -159,44 +135,74 @@ static int bench_str2int(const char *str)
159 return BENCH_FORMAT_UNKNOWN; 135 return BENCH_FORMAT_UNKNOWN;
160} 136}
161 137
162static void all_suite(struct bench_subsys *subsys) /* FROM HERE */ 138/*
139 * Run a specific benchmark but first rename the running task's ->comm[]
140 * to something meaningful:
141 */
142static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
143 int argc, const char **argv, const char *prefix)
163{ 144{
164 int i; 145 int size;
146 char *name;
147 int ret;
148
149 size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
150
151 name = zalloc(size);
152 BUG_ON(!name);
153
154 scnprintf(name, size, "%s-%s", coll_name, bench_name);
155
156 prctl(PR_SET_NAME, name);
157 argv[0] = name;
158
159 ret = fn(argc, argv, prefix);
160
161 free(name);
162
163 return ret;
164}
165
166static void run_collection(struct collection *coll)
167{
168 struct bench *bench;
165 const char *argv[2]; 169 const char *argv[2];
166 struct bench_suite *suites = subsys->suites;
167 170
168 argv[1] = NULL; 171 argv[1] = NULL;
169 /* 172 /*
170 * TODO: 173 * TODO:
171 * preparing preset parameters for 174 *
175 * Preparing preset parameters for
172 * embedded, ordinary PC, HPC, etc... 176 * embedded, ordinary PC, HPC, etc...
173 * will be helpful 177 * would be helpful.
174 */ 178 */
175 for (i = 0; suites[i].fn; i++) { 179 for_each_bench(coll, bench) {
176 printf("# Running %s/%s benchmark...\n", 180 if (!bench->fn)
177 subsys->name, 181 break;
178 suites[i].name); 182 printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
179 fflush(stdout); 183 fflush(stdout);
180 184
181 argv[1] = suites[i].name; 185 argv[1] = bench->name;
182 suites[i].fn(1, argv, NULL); 186 run_bench(coll->name, bench->name, bench->fn, 1, argv, NULL);
183 printf("\n"); 187 printf("\n");
184 } 188 }
185} 189}
186 190
187static void all_subsystem(void) 191static void run_all_collections(void)
188{ 192{
189 int i; 193 struct collection *coll;
190 for (i = 0; subsystems[i].suites; i++) 194
191 all_suite(&subsystems[i]); 195 for_each_collection(coll)
196 run_collection(coll);
192} 197}
193 198
194int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) 199int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
195{ 200{
196 int i, j, status = 0; 201 struct collection *coll;
202 int ret = 0;
197 203
198 if (argc < 2) { 204 if (argc < 2) {
199 /* No subsystem specified. */ 205 /* No collection specified. */
200 print_usage(); 206 print_usage();
201 goto end; 207 goto end;
202 } 208 }
@@ -206,7 +212,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
206 212
207 bench_format = bench_str2int(bench_format_str); 213 bench_format = bench_str2int(bench_format_str);
208 if (bench_format == BENCH_FORMAT_UNKNOWN) { 214 if (bench_format == BENCH_FORMAT_UNKNOWN) {
209 printf("Unknown format descriptor:%s\n", bench_format_str); 215 printf("Unknown format descriptor: '%s'\n", bench_format_str);
210 goto end; 216 goto end;
211 } 217 }
212 218
@@ -216,52 +222,51 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
216 } 222 }
217 223
218 if (!strcmp(argv[0], "all")) { 224 if (!strcmp(argv[0], "all")) {
219 all_subsystem(); 225 run_all_collections();
220 goto end; 226 goto end;
221 } 227 }
222 228
223 for (i = 0; subsystems[i].name; i++) { 229 for_each_collection(coll) {
224 if (strcmp(subsystems[i].name, argv[0])) 230 struct bench *bench;
231
232 if (strcmp(coll->name, argv[0]))
225 continue; 233 continue;
226 234
227 if (argc < 2) { 235 if (argc < 2) {
228 /* No suite specified. */ 236 /* No bench specified. */
229 dump_suites(i); 237 dump_benchmarks(coll);
230 goto end; 238 goto end;
231 } 239 }
232 240
233 if (!strcmp(argv[1], "all")) { 241 if (!strcmp(argv[1], "all")) {
234 all_suite(&subsystems[i]); 242 run_collection(coll);
235 goto end; 243 goto end;
236 } 244 }
237 245
238 for (j = 0; subsystems[i].suites[j].name; j++) { 246 for_each_bench(coll, bench) {
239 if (strcmp(subsystems[i].suites[j].name, argv[1])) 247 if (strcmp(bench->name, argv[1]))
240 continue; 248 continue;
241 249
242 if (bench_format == BENCH_FORMAT_DEFAULT) 250 if (bench_format == BENCH_FORMAT_DEFAULT)
243 printf("# Running %s/%s benchmark...\n", 251 printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
244 subsystems[i].name,
245 subsystems[i].suites[j].name);
246 fflush(stdout); 252 fflush(stdout);
247 status = subsystems[i].suites[j].fn(argc - 1, 253 ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1, prefix);
248 argv + 1, prefix);
249 goto end; 254 goto end;
250 } 255 }
251 256
252 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 257 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
253 dump_suites(i); 258 dump_benchmarks(coll);
254 goto end; 259 goto end;
255 } 260 }
256 261
257 printf("Unknown suite:%s for %s\n", argv[1], argv[0]); 262 printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
258 status = 1; 263 ret = 1;
259 goto end; 264 goto end;
260 } 265 }
261 266
262 printf("Unknown subsystem:%s\n", argv[0]); 267 printf("Unknown collection: '%s'\n", argv[0]);
263 status = 1; 268 ret = 1;
264 269
265end: 270end:
266 return status; 271 return ret;
267} 272}
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index c96c8fa38243..cfede86161d8 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -6,6 +6,11 @@
6 * Copyright (C) 2010, Red Hat Inc. 6 * Copyright (C) 2010, Red Hat Inc.
7 * Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com> 7 * Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
8 */ 8 */
9#include <sys/types.h>
10#include <sys/time.h>
11#include <time.h>
12#include <dirent.h>
13#include <unistd.h>
9#include "builtin.h" 14#include "builtin.h"
10#include "perf.h" 15#include "perf.h"
11#include "util/cache.h" 16#include "util/cache.h"
@@ -17,6 +22,140 @@
17#include "util/session.h" 22#include "util/session.h"
18#include "util/symbol.h" 23#include "util/symbol.h"
19 24
25static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
26{
27 char root_dir[PATH_MAX];
28 char notes[PATH_MAX];
29 u8 build_id[BUILD_ID_SIZE];
30 char *p;
31
32 strlcpy(root_dir, proc_dir, sizeof(root_dir));
33
34 p = strrchr(root_dir, '/');
35 if (!p)
36 return -1;
37 *p = '\0';
38
39 scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
40
41 if (sysfs__read_build_id(notes, build_id, sizeof(build_id)))
42 return -1;
43
44 build_id__sprintf(build_id, sizeof(build_id), sbuildid);
45
46 return 0;
47}
48
49static int build_id_cache__kcore_dir(char *dir, size_t sz)
50{
51 struct timeval tv;
52 struct tm tm;
53 char dt[32];
54
55 if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
56 return -1;
57
58 if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
59 return -1;
60
61 scnprintf(dir, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
62
63 return 0;
64}
65
66static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
67 size_t to_dir_sz)
68{
69 char from[PATH_MAX];
70 char to[PATH_MAX];
71 struct dirent *dent;
72 int ret = -1;
73 DIR *d;
74
75 d = opendir(to_dir);
76 if (!d)
77 return -1;
78
79 scnprintf(from, sizeof(from), "%s/modules", from_dir);
80
81 while (1) {
82 dent = readdir(d);
83 if (!dent)
84 break;
85 if (dent->d_type != DT_DIR)
86 continue;
87 scnprintf(to, sizeof(to), "%s/%s/modules", to_dir,
88 dent->d_name);
89 if (!compare_proc_modules(from, to)) {
90 scnprintf(to, sizeof(to), "%s/%s", to_dir,
91 dent->d_name);
92 strlcpy(to_dir, to, to_dir_sz);
93 ret = 0;
94 break;
95 }
96 }
97
98 closedir(d);
99
100 return ret;
101}
102
103static int build_id_cache__add_kcore(const char *filename, const char *debugdir)
104{
105 char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1];
106 char from_dir[PATH_MAX], to_dir[PATH_MAX];
107 char *p;
108
109 strlcpy(from_dir, filename, sizeof(from_dir));
110
111 p = strrchr(from_dir, '/');
112 if (!p || strcmp(p + 1, "kcore"))
113 return -1;
114 *p = '\0';
115
116 if (build_id_cache__kcore_buildid(from_dir, sbuildid))
117 return -1;
118
119 scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
120 debugdir, sbuildid);
121
122 if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
123 pr_debug("same kcore found in %s\n", to_dir);
124 return 0;
125 }
126
127 if (build_id_cache__kcore_dir(dir, sizeof(dir)))
128 return -1;
129
130 scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s/%s",
131 debugdir, sbuildid, dir);
132
133 if (mkdir_p(to_dir, 0755))
134 return -1;
135
136 if (kcore_copy(from_dir, to_dir)) {
137 /* Remove YYYYmmddHHMMSShh directory */
138 if (!rmdir(to_dir)) {
139 p = strrchr(to_dir, '/');
140 if (p)
141 *p = '\0';
142 /* Try to remove buildid directory */
143 if (!rmdir(to_dir)) {
144 p = strrchr(to_dir, '/');
145 if (p)
146 *p = '\0';
147 /* Try to remove [kernel.kcore] directory */
148 rmdir(to_dir);
149 }
150 }
151 return -1;
152 }
153
154 pr_debug("kcore added to build-id cache directory %s\n", to_dir);
155
156 return 0;
157}
158
20static int build_id_cache__add_file(const char *filename, const char *debugdir) 159static int build_id_cache__add_file(const char *filename, const char *debugdir)
21{ 160{
22 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 161 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -82,8 +221,12 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
82 221
83static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp) 222static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp)
84{ 223{
85 struct perf_session *session = perf_session__new(filename, O_RDONLY, 224 struct perf_data_file file = {
86 force, false, NULL); 225 .path = filename,
226 .mode = PERF_DATA_MODE_READ,
227 .force = force,
228 };
229 struct perf_session *session = perf_session__new(&file, false, NULL);
87 if (session == NULL) 230 if (session == NULL)
88 return -1; 231 return -1;
89 232
@@ -130,11 +273,14 @@ int cmd_buildid_cache(int argc, const char **argv,
130 char const *add_name_list_str = NULL, 273 char const *add_name_list_str = NULL,
131 *remove_name_list_str = NULL, 274 *remove_name_list_str = NULL,
132 *missing_filename = NULL, 275 *missing_filename = NULL,
133 *update_name_list_str = NULL; 276 *update_name_list_str = NULL,
277 *kcore_filename;
134 278
135 const struct option buildid_cache_options[] = { 279 const struct option buildid_cache_options[] = {
136 OPT_STRING('a', "add", &add_name_list_str, 280 OPT_STRING('a', "add", &add_name_list_str,
137 "file list", "file(s) to add"), 281 "file list", "file(s) to add"),
282 OPT_STRING('k', "kcore", &kcore_filename,
283 "file", "kcore file to add"),
138 OPT_STRING('r', "remove", &remove_name_list_str, "file list", 284 OPT_STRING('r', "remove", &remove_name_list_str, "file list",
139 "file(s) to remove"), 285 "file(s) to remove"),
140 OPT_STRING('M', "missing", &missing_filename, "file", 286 OPT_STRING('M', "missing", &missing_filename, "file",
@@ -217,5 +363,9 @@ int cmd_buildid_cache(int argc, const char **argv,
217 } 363 }
218 } 364 }
219 365
366 if (kcore_filename &&
367 build_id_cache__add_kcore(kcore_filename, debugdir))
368 pr_warning("Couldn't add %s\n", kcore_filename);
369
220 return ret; 370 return ret;
221} 371}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index e74366a13218..ed3873b3e238 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -15,6 +15,7 @@
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17#include "util/symbol.h" 17#include "util/symbol.h"
18#include "util/data.h"
18 19
19static int sysfs__fprintf_build_id(FILE *fp) 20static int sysfs__fprintf_build_id(FILE *fp)
20{ 21{
@@ -52,6 +53,11 @@ static bool dso__skip_buildid(struct dso *dso, int with_hits)
52static int perf_session__list_build_ids(bool force, bool with_hits) 53static int perf_session__list_build_ids(bool force, bool with_hits)
53{ 54{
54 struct perf_session *session; 55 struct perf_session *session;
56 struct perf_data_file file = {
57 .path = input_name,
58 .mode = PERF_DATA_MODE_READ,
59 .force = force,
60 };
55 61
56 symbol__elf_init(); 62 symbol__elf_init();
57 /* 63 /*
@@ -60,15 +66,14 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
60 if (filename__fprintf_build_id(input_name, stdout)) 66 if (filename__fprintf_build_id(input_name, stdout))
61 goto out; 67 goto out;
62 68
63 session = perf_session__new(input_name, O_RDONLY, force, false, 69 session = perf_session__new(&file, false, &build_id__mark_dso_hit_ops);
64 &build_id__mark_dso_hit_ops);
65 if (session == NULL) 70 if (session == NULL)
66 return -1; 71 return -1;
67 /* 72 /*
68 * in pipe-mode, the only way to get the buildids is to parse 73 * in pipe-mode, the only way to get the buildids is to parse
69 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID 74 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
70 */ 75 */
71 if (with_hits || session->fd_pipe) 76 if (with_hits || perf_data_file__is_pipe(&file))
72 perf_session__process_events(session, &build_id__mark_dso_hit_ops); 77 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
73 78
74 perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits); 79 perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index f28799e94f2a..3b67ea2444bd 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -16,6 +16,7 @@
16#include "util/sort.h" 16#include "util/sort.h"
17#include "util/symbol.h" 17#include "util/symbol.h"
18#include "util/util.h" 18#include "util/util.h"
19#include "util/data.h"
19 20
20#include <stdlib.h> 21#include <stdlib.h>
21#include <math.h> 22#include <math.h>
@@ -42,7 +43,7 @@ struct diff_hpp_fmt {
42 43
43struct data__file { 44struct data__file {
44 struct perf_session *session; 45 struct perf_session *session;
45 const char *file; 46 struct perf_data_file file;
46 int idx; 47 int idx;
47 struct hists *hists; 48 struct hists *hists;
48 struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX]; 49 struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
@@ -302,11 +303,12 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
302 return -1; 303 return -1;
303} 304}
304 305
305static int hists__add_entry(struct hists *self, 306static int hists__add_entry(struct hists *hists,
306 struct addr_location *al, u64 period, 307 struct addr_location *al, u64 period,
307 u64 weight) 308 u64 weight, u64 transaction)
308{ 309{
309 if (__hists__add_entry(self, al, NULL, period, weight) != NULL) 310 if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight,
311 transaction) != NULL)
310 return 0; 312 return 0;
311 return -ENOMEM; 313 return -ENOMEM;
312} 314}
@@ -328,7 +330,8 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
328 if (al.filtered) 330 if (al.filtered)
329 return 0; 331 return 0;
330 332
331 if (hists__add_entry(&evsel->hists, &al, sample->period, sample->weight)) { 333 if (hists__add_entry(&evsel->hists, &al, sample->period,
334 sample->weight, sample->transaction)) {
332 pr_warning("problem incrementing symbol period, skipping event\n"); 335 pr_warning("problem incrementing symbol period, skipping event\n");
333 return -1; 336 return -1;
334 } 337 }
@@ -367,7 +370,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
367 list_for_each_entry(evsel, &evlist->entries, node) { 370 list_for_each_entry(evsel, &evlist->entries, node) {
368 struct hists *hists = &evsel->hists; 371 struct hists *hists = &evsel->hists;
369 372
370 hists__collapse_resort(hists); 373 hists__collapse_resort(hists, NULL);
371 } 374 }
372} 375}
373 376
@@ -599,7 +602,7 @@ static void data__fprintf(void)
599 602
600 data__for_each_file(i, d) 603 data__for_each_file(i, d)
601 fprintf(stdout, "# [%d] %s %s\n", 604 fprintf(stdout, "# [%d] %s %s\n",
602 d->idx, d->file, 605 d->idx, d->file.path,
603 !d->idx ? "(Baseline)" : ""); 606 !d->idx ? "(Baseline)" : "");
604 607
605 fprintf(stdout, "#\n"); 608 fprintf(stdout, "#\n");
@@ -661,17 +664,16 @@ static int __cmd_diff(void)
661 int ret = -EINVAL, i; 664 int ret = -EINVAL, i;
662 665
663 data__for_each_file(i, d) { 666 data__for_each_file(i, d) {
664 d->session = perf_session__new(d->file, O_RDONLY, force, 667 d->session = perf_session__new(&d->file, false, &tool);
665 false, &tool);
666 if (!d->session) { 668 if (!d->session) {
667 pr_err("Failed to open %s\n", d->file); 669 pr_err("Failed to open %s\n", d->file.path);
668 ret = -ENOMEM; 670 ret = -ENOMEM;
669 goto out_delete; 671 goto out_delete;
670 } 672 }
671 673
672 ret = perf_session__process_events(d->session, &tool); 674 ret = perf_session__process_events(d->session, &tool);
673 if (ret) { 675 if (ret) {
674 pr_err("Failed to process %s\n", d->file); 676 pr_err("Failed to process %s\n", d->file.path);
675 goto out_delete; 677 goto out_delete;
676 } 678 }
677 679
@@ -1014,7 +1016,12 @@ static int data_init(int argc, const char **argv)
1014 return -ENOMEM; 1016 return -ENOMEM;
1015 1017
1016 data__for_each_file(i, d) { 1018 data__for_each_file(i, d) {
1017 d->file = use_default ? defaults[i] : argv[i]; 1019 struct perf_data_file *file = &d->file;
1020
1021 file->path = use_default ? defaults[i] : argv[i];
1022 file->mode = PERF_DATA_MODE_READ,
1023 file->force = force,
1024
1018 d->idx = i; 1025 d->idx = i;
1019 } 1026 }
1020 1027
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 05bd9dfe875c..20b0f12763b0 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -14,13 +14,18 @@
14#include "util/parse-events.h" 14#include "util/parse-events.h"
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17#include "util/data.h"
17 18
18static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) 19static int __cmd_evlist(const char *file_name, struct perf_attr_details *details)
19{ 20{
20 struct perf_session *session; 21 struct perf_session *session;
21 struct perf_evsel *pos; 22 struct perf_evsel *pos;
23 struct perf_data_file file = {
24 .path = file_name,
25 .mode = PERF_DATA_MODE_READ,
26 };
22 27
23 session = perf_session__new(file_name, O_RDONLY, 0, false, NULL); 28 session = perf_session__new(&file, 0, NULL);
24 if (session == NULL) 29 if (session == NULL)
25 return -ENOMEM; 30 return -ENOMEM;
26 31
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index afe377b2884f..6a2508589460 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -15,6 +15,7 @@
15#include "util/tool.h" 15#include "util/tool.h"
16#include "util/debug.h" 16#include "util/debug.h"
17#include "util/build-id.h" 17#include "util/build-id.h"
18#include "util/data.h"
18 19
19#include "util/parse-options.h" 20#include "util/parse-options.h"
20 21
@@ -71,12 +72,17 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
71 union perf_event *event, 72 union perf_event *event,
72 struct perf_evlist **pevlist) 73 struct perf_evlist **pevlist)
73{ 74{
75 struct perf_inject *inject = container_of(tool, struct perf_inject,
76 tool);
74 int ret; 77 int ret;
75 78
76 ret = perf_event__process_attr(tool, event, pevlist); 79 ret = perf_event__process_attr(tool, event, pevlist);
77 if (ret) 80 if (ret)
78 return ret; 81 return ret;
79 82
83 if (!inject->pipe_output)
84 return 0;
85
80 return perf_event__repipe_synth(tool, event); 86 return perf_event__repipe_synth(tool, event);
81} 87}
82 88
@@ -100,8 +106,8 @@ static int perf_event__repipe_sample(struct perf_tool *tool,
100 struct perf_evsel *evsel, 106 struct perf_evsel *evsel,
101 struct machine *machine) 107 struct machine *machine)
102{ 108{
103 if (evsel->handler.func) { 109 if (evsel->handler) {
104 inject_handler f = evsel->handler.func; 110 inject_handler f = evsel->handler;
105 return f(tool, event, sample, evsel, machine); 111 return f(tool, event, sample, evsel, machine);
106 } 112 }
107 113
@@ -161,38 +167,38 @@ static int perf_event__repipe_tracing_data(struct perf_tool *tool,
161 return err; 167 return err;
162} 168}
163 169
164static int dso__read_build_id(struct dso *self) 170static int dso__read_build_id(struct dso *dso)
165{ 171{
166 if (self->has_build_id) 172 if (dso->has_build_id)
167 return 0; 173 return 0;
168 174
169 if (filename__read_build_id(self->long_name, self->build_id, 175 if (filename__read_build_id(dso->long_name, dso->build_id,
170 sizeof(self->build_id)) > 0) { 176 sizeof(dso->build_id)) > 0) {
171 self->has_build_id = true; 177 dso->has_build_id = true;
172 return 0; 178 return 0;
173 } 179 }
174 180
175 return -1; 181 return -1;
176} 182}
177 183
178static int dso__inject_build_id(struct dso *self, struct perf_tool *tool, 184static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
179 struct machine *machine) 185 struct machine *machine)
180{ 186{
181 u16 misc = PERF_RECORD_MISC_USER; 187 u16 misc = PERF_RECORD_MISC_USER;
182 int err; 188 int err;
183 189
184 if (dso__read_build_id(self) < 0) { 190 if (dso__read_build_id(dso) < 0) {
185 pr_debug("no build_id found for %s\n", self->long_name); 191 pr_debug("no build_id found for %s\n", dso->long_name);
186 return -1; 192 return -1;
187 } 193 }
188 194
189 if (self->kernel) 195 if (dso->kernel)
190 misc = PERF_RECORD_MISC_KERNEL; 196 misc = PERF_RECORD_MISC_KERNEL;
191 197
192 err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe, 198 err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe,
193 machine); 199 machine);
194 if (err) { 200 if (err) {
195 pr_err("Can't synthesize build_id event for %s\n", self->long_name); 201 pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
196 return -1; 202 return -1;
197 } 203 }
198 204
@@ -231,7 +237,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
231 * account this as unresolved. 237 * account this as unresolved.
232 */ 238 */
233 } else { 239 } else {
234#ifdef LIBELF_SUPPORT 240#ifdef HAVE_LIBELF_SUPPORT
235 pr_warning("no symbols found in %s, maybe " 241 pr_warning("no symbols found in %s, maybe "
236 "install a debug package?\n", 242 "install a debug package?\n",
237 al.map->dso->long_name); 243 al.map->dso->long_name);
@@ -345,6 +351,10 @@ static int __cmd_inject(struct perf_inject *inject)
345{ 351{
346 struct perf_session *session; 352 struct perf_session *session;
347 int ret = -EINVAL; 353 int ret = -EINVAL;
354 struct perf_data_file file = {
355 .path = inject->input_name,
356 .mode = PERF_DATA_MODE_READ,
357 };
348 358
349 signal(SIGINT, sig_handler); 359 signal(SIGINT, sig_handler);
350 360
@@ -355,7 +365,7 @@ static int __cmd_inject(struct perf_inject *inject)
355 inject->tool.tracing_data = perf_event__repipe_tracing_data; 365 inject->tool.tracing_data = perf_event__repipe_tracing_data;
356 } 366 }
357 367
358 session = perf_session__new(inject->input_name, O_RDONLY, false, true, &inject->tool); 368 session = perf_session__new(&file, true, &inject->tool);
359 if (session == NULL) 369 if (session == NULL)
360 return -ENOMEM; 370 return -ENOMEM;
361 371
@@ -373,11 +383,11 @@ static int __cmd_inject(struct perf_inject *inject)
373 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID")) 383 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
374 return -EINVAL; 384 return -EINVAL;
375 385
376 evsel->handler.func = perf_inject__sched_switch; 386 evsel->handler = perf_inject__sched_switch;
377 } else if (!strcmp(name, "sched:sched_process_exit")) 387 } else if (!strcmp(name, "sched:sched_process_exit"))
378 evsel->handler.func = perf_inject__sched_process_exit; 388 evsel->handler = perf_inject__sched_process_exit;
379 else if (!strncmp(name, "sched:sched_stat_", 17)) 389 else if (!strncmp(name, "sched:sched_stat_", 17))
380 evsel->handler.func = perf_inject__sched_stat; 390 evsel->handler = perf_inject__sched_stat;
381 } 391 }
382 } 392 }
383 393
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 9b5f077fee5b..929462aa4943 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -13,6 +13,7 @@
13 13
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/trace-event.h" 15#include "util/trace-event.h"
16#include "util/data.h"
16 17
17#include "util/debug.h" 18#include "util/debug.h"
18 19
@@ -314,10 +315,10 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
314 return -1; 315 return -1;
315 } 316 }
316 317
317 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid); 318 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
318 319
319 if (evsel->handler.func != NULL) { 320 if (evsel->handler != NULL) {
320 tracepoint_handler f = evsel->handler.func; 321 tracepoint_handler f = evsel->handler;
321 return f(evsel, sample); 322 return f(evsel, sample);
322 } 323 }
323 324
@@ -486,8 +487,12 @@ static int __cmd_kmem(void)
486 { "kmem:kfree", perf_evsel__process_free_event, }, 487 { "kmem:kfree", perf_evsel__process_free_event, },
487 { "kmem:kmem_cache_free", perf_evsel__process_free_event, }, 488 { "kmem:kmem_cache_free", perf_evsel__process_free_event, },
488 }; 489 };
490 struct perf_data_file file = {
491 .path = input_name,
492 .mode = PERF_DATA_MODE_READ,
493 };
489 494
490 session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_kmem); 495 session = perf_session__new(&file, false, &perf_kmem);
491 if (session == NULL) 496 if (session == NULL)
492 return -ENOMEM; 497 return -ENOMEM;
493 498
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 935d52216c89..f8bf5f244d77 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -17,9 +17,12 @@
17#include "util/tool.h" 17#include "util/tool.h"
18#include "util/stat.h" 18#include "util/stat.h"
19#include "util/top.h" 19#include "util/top.h"
20#include "util/data.h"
20 21
21#include <sys/prctl.h> 22#include <sys/prctl.h>
23#ifdef HAVE_TIMERFD_SUPPORT
22#include <sys/timerfd.h> 24#include <sys/timerfd.h>
25#endif
23 26
24#include <termios.h> 27#include <termios.h>
25#include <semaphore.h> 28#include <semaphore.h>
@@ -336,6 +339,7 @@ static void init_kvm_event_record(struct perf_kvm_stat *kvm)
336 INIT_LIST_HEAD(&kvm->kvm_events_cache[i]); 339 INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
337} 340}
338 341
342#ifdef HAVE_TIMERFD_SUPPORT
339static void clear_events_cache_stats(struct list_head *kvm_events_cache) 343static void clear_events_cache_stats(struct list_head *kvm_events_cache)
340{ 344{
341 struct list_head *head; 345 struct list_head *head;
@@ -357,6 +361,7 @@ static void clear_events_cache_stats(struct list_head *kvm_events_cache)
357 } 361 }
358 } 362 }
359} 363}
364#endif
360 365
361static int kvm_events_hash_fn(u64 key) 366static int kvm_events_hash_fn(u64 key)
362{ 367{
@@ -782,6 +787,7 @@ static void print_result(struct perf_kvm_stat *kvm)
782 pr_info("\nLost events: %" PRIu64 "\n\n", kvm->lost_events); 787 pr_info("\nLost events: %" PRIu64 "\n\n", kvm->lost_events);
783} 788}
784 789
790#ifdef HAVE_TIMERFD_SUPPORT
785static int process_lost_event(struct perf_tool *tool, 791static int process_lost_event(struct perf_tool *tool,
786 union perf_event *event __maybe_unused, 792 union perf_event *event __maybe_unused,
787 struct perf_sample *sample __maybe_unused, 793 struct perf_sample *sample __maybe_unused,
@@ -792,6 +798,7 @@ static int process_lost_event(struct perf_tool *tool,
792 kvm->lost_events++; 798 kvm->lost_events++;
793 return 0; 799 return 0;
794} 800}
801#endif
795 802
796static bool skip_sample(struct perf_kvm_stat *kvm, 803static bool skip_sample(struct perf_kvm_stat *kvm,
797 struct perf_sample *sample) 804 struct perf_sample *sample)
@@ -871,6 +878,7 @@ static bool verify_vcpu(int vcpu)
871 return true; 878 return true;
872} 879}
873 880
881#ifdef HAVE_TIMERFD_SUPPORT
874/* keeping the max events to a modest level to keep 882/* keeping the max events to a modest level to keep
875 * the processing of samples per mmap smooth. 883 * the processing of samples per mmap smooth.
876 */ 884 */
@@ -888,11 +896,18 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
888 while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) { 896 while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) {
889 err = perf_evlist__parse_sample(kvm->evlist, event, &sample); 897 err = perf_evlist__parse_sample(kvm->evlist, event, &sample);
890 if (err) { 898 if (err) {
899 perf_evlist__mmap_consume(kvm->evlist, idx);
891 pr_err("Failed to parse sample\n"); 900 pr_err("Failed to parse sample\n");
892 return -1; 901 return -1;
893 } 902 }
894 903
895 err = perf_session_queue_event(kvm->session, event, &sample, 0); 904 err = perf_session_queue_event(kvm->session, event, &sample, 0);
905 /*
906 * FIXME: Here we can't consume the event, as perf_session_queue_event will
907 * point to it, and it'll get possibly overwritten by the kernel.
908 */
909 perf_evlist__mmap_consume(kvm->evlist, idx);
910
896 if (err) { 911 if (err) {
897 pr_err("Failed to enqueue sample: %d\n", err); 912 pr_err("Failed to enqueue sample: %d\n", err);
898 return -1; 913 return -1;
@@ -1205,6 +1220,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
1205out: 1220out:
1206 return rc; 1221 return rc;
1207} 1222}
1223#endif
1208 1224
1209static int read_events(struct perf_kvm_stat *kvm) 1225static int read_events(struct perf_kvm_stat *kvm)
1210{ 1226{
@@ -1215,10 +1231,13 @@ static int read_events(struct perf_kvm_stat *kvm)
1215 .comm = perf_event__process_comm, 1231 .comm = perf_event__process_comm,
1216 .ordered_samples = true, 1232 .ordered_samples = true,
1217 }; 1233 };
1234 struct perf_data_file file = {
1235 .path = input_name,
1236 .mode = PERF_DATA_MODE_READ,
1237 };
1218 1238
1219 kvm->tool = eops; 1239 kvm->tool = eops;
1220 kvm->session = perf_session__new(kvm->file_name, O_RDONLY, 0, false, 1240 kvm->session = perf_session__new(&file, false, &kvm->tool);
1221 &kvm->tool);
1222 if (!kvm->session) { 1241 if (!kvm->session) {
1223 pr_err("Initializing perf session failed\n"); 1242 pr_err("Initializing perf session failed\n");
1224 return -EINVAL; 1243 return -EINVAL;
@@ -1368,6 +1387,7 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
1368 return kvm_events_report_vcpu(kvm); 1387 return kvm_events_report_vcpu(kvm);
1369} 1388}
1370 1389
1390#ifdef HAVE_TIMERFD_SUPPORT
1371static struct perf_evlist *kvm_live_event_list(void) 1391static struct perf_evlist *kvm_live_event_list(void)
1372{ 1392{
1373 struct perf_evlist *evlist; 1393 struct perf_evlist *evlist;
@@ -1426,8 +1446,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1426 const struct option live_options[] = { 1446 const struct option live_options[] = {
1427 OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid", 1447 OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
1428 "record events on existing process id"), 1448 "record events on existing process id"),
1429 OPT_UINTEGER('m', "mmap-pages", &kvm->opts.mmap_pages, 1449 OPT_CALLBACK('m', "mmap-pages", &kvm->opts.mmap_pages, "pages",
1430 "number of mmap data pages"), 1450 "number of mmap data pages",
1451 perf_evlist__parse_mmap_pages),
1431 OPT_INCR('v', "verbose", &verbose, 1452 OPT_INCR('v', "verbose", &verbose,
1432 "be more verbose (show counter open errors, etc)"), 1453 "be more verbose (show counter open errors, etc)"),
1433 OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide, 1454 OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide,
@@ -1449,6 +1470,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1449 "perf kvm stat live [<options>]", 1470 "perf kvm stat live [<options>]",
1450 NULL 1471 NULL
1451 }; 1472 };
1473 struct perf_data_file file = {
1474 .mode = PERF_DATA_MODE_WRITE,
1475 };
1452 1476
1453 1477
1454 /* event handling */ 1478 /* event handling */
@@ -1486,13 +1510,13 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1486 /* 1510 /*
1487 * target related setups 1511 * target related setups
1488 */ 1512 */
1489 err = perf_target__validate(&kvm->opts.target); 1513 err = target__validate(&kvm->opts.target);
1490 if (err) { 1514 if (err) {
1491 perf_target__strerror(&kvm->opts.target, err, errbuf, BUFSIZ); 1515 target__strerror(&kvm->opts.target, err, errbuf, BUFSIZ);
1492 ui__warning("%s", errbuf); 1516 ui__warning("%s", errbuf);
1493 } 1517 }
1494 1518
1495 if (perf_target__none(&kvm->opts.target)) 1519 if (target__none(&kvm->opts.target))
1496 kvm->opts.target.system_wide = true; 1520 kvm->opts.target.system_wide = true;
1497 1521
1498 1522
@@ -1513,25 +1537,15 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1513 /* 1537 /*
1514 * perf session 1538 * perf session
1515 */ 1539 */
1516 kvm->session = perf_session__new(NULL, O_WRONLY, false, false, &kvm->tool); 1540 kvm->session = perf_session__new(&file, false, &kvm->tool);
1517 if (kvm->session == NULL) { 1541 if (kvm->session == NULL) {
1518 err = -ENOMEM; 1542 err = -ENOMEM;
1519 goto out; 1543 goto out;
1520 } 1544 }
1521 kvm->session->evlist = kvm->evlist; 1545 kvm->session->evlist = kvm->evlist;
1522 perf_session__set_id_hdr_size(kvm->session); 1546 perf_session__set_id_hdr_size(kvm->session);
1523 1547 machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target,
1524 1548 kvm->evlist->threads, false);
1525 if (perf_target__has_task(&kvm->opts.target))
1526 perf_event__synthesize_thread_map(&kvm->tool,
1527 kvm->evlist->threads,
1528 perf_event__process,
1529 &kvm->session->machines.host);
1530 else
1531 perf_event__synthesize_threads(&kvm->tool, perf_event__process,
1532 &kvm->session->machines.host);
1533
1534
1535 err = kvm_live_open_events(kvm); 1549 err = kvm_live_open_events(kvm);
1536 if (err) 1550 if (err)
1537 goto out; 1551 goto out;
@@ -1551,6 +1565,7 @@ out:
1551 1565
1552 return err; 1566 return err;
1553} 1567}
1568#endif
1554 1569
1555static void print_kvm_stat_usage(void) 1570static void print_kvm_stat_usage(void)
1556{ 1571{
@@ -1589,8 +1604,10 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
1589 if (!strncmp(argv[1], "rep", 3)) 1604 if (!strncmp(argv[1], "rep", 3))
1590 return kvm_events_report(&kvm, argc - 1 , argv + 1); 1605 return kvm_events_report(&kvm, argc - 1 , argv + 1);
1591 1606
1607#ifdef HAVE_TIMERFD_SUPPORT
1592 if (!strncmp(argv[1], "live", 4)) 1608 if (!strncmp(argv[1], "live", 4))
1593 return kvm_events_live(&kvm, argc - 1 , argv + 1); 1609 return kvm_events_live(&kvm, argc - 1 , argv + 1);
1610#endif
1594 1611
1595perf_stat: 1612perf_stat:
1596 return cmd_stat(argc, argv, NULL); 1613 return cmd_stat(argc, argv, NULL);
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index e79f423cc302..011195e38f21 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -14,51 +14,63 @@
14#include "util/parse-events.h" 14#include "util/parse-events.h"
15#include "util/cache.h" 15#include "util/cache.h"
16#include "util/pmu.h" 16#include "util/pmu.h"
17#include "util/parse-options.h"
17 18
18int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) 19int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
19{ 20{
21 int i;
22 const struct option list_options[] = {
23 OPT_END()
24 };
25 const char * const list_usage[] = {
26 "perf list [hw|sw|cache|tracepoint|pmu|event_glob]",
27 NULL
28 };
29
30 argc = parse_options(argc, argv, list_options, list_usage,
31 PARSE_OPT_STOP_AT_NON_OPTION);
32
20 setup_pager(); 33 setup_pager();
21 34
22 if (argc == 1) 35 if (argc == 0) {
23 print_events(NULL, false); 36 print_events(NULL, false);
24 else { 37 return 0;
25 int i; 38 }
26
27 for (i = 1; i < argc; ++i) {
28 if (i > 2)
29 putchar('\n');
30 if (strncmp(argv[i], "tracepoint", 10) == 0)
31 print_tracepoint_events(NULL, NULL, false);
32 else if (strcmp(argv[i], "hw") == 0 ||
33 strcmp(argv[i], "hardware") == 0)
34 print_events_type(PERF_TYPE_HARDWARE);
35 else if (strcmp(argv[i], "sw") == 0 ||
36 strcmp(argv[i], "software") == 0)
37 print_events_type(PERF_TYPE_SOFTWARE);
38 else if (strcmp(argv[i], "cache") == 0 ||
39 strcmp(argv[i], "hwcache") == 0)
40 print_hwcache_events(NULL, false);
41 else if (strcmp(argv[i], "pmu") == 0)
42 print_pmu_events(NULL, false);
43 else if (strcmp(argv[i], "--raw-dump") == 0)
44 print_events(NULL, true);
45 else {
46 char *sep = strchr(argv[i], ':'), *s;
47 int sep_idx;
48 39
49 if (sep == NULL) { 40 for (i = 0; i < argc; ++i) {
50 print_events(argv[i], false); 41 if (i)
51 continue; 42 putchar('\n');
52 } 43 if (strncmp(argv[i], "tracepoint", 10) == 0)
53 sep_idx = sep - argv[i]; 44 print_tracepoint_events(NULL, NULL, false);
54 s = strdup(argv[i]); 45 else if (strcmp(argv[i], "hw") == 0 ||
55 if (s == NULL) 46 strcmp(argv[i], "hardware") == 0)
56 return -1; 47 print_events_type(PERF_TYPE_HARDWARE);
48 else if (strcmp(argv[i], "sw") == 0 ||
49 strcmp(argv[i], "software") == 0)
50 print_events_type(PERF_TYPE_SOFTWARE);
51 else if (strcmp(argv[i], "cache") == 0 ||
52 strcmp(argv[i], "hwcache") == 0)
53 print_hwcache_events(NULL, false);
54 else if (strcmp(argv[i], "pmu") == 0)
55 print_pmu_events(NULL, false);
56 else if (strcmp(argv[i], "--raw-dump") == 0)
57 print_events(NULL, true);
58 else {
59 char *sep = strchr(argv[i], ':'), *s;
60 int sep_idx;
57 61
58 s[sep_idx] = '\0'; 62 if (sep == NULL) {
59 print_tracepoint_events(s, s + sep_idx + 1, false); 63 print_events(argv[i], false);
60 free(s); 64 continue;
61 } 65 }
66 sep_idx = sep - argv[i];
67 s = strdup(argv[i]);
68 if (s == NULL)
69 return -1;
70
71 s[sep_idx] = '\0';
72 print_tracepoint_events(s, s + sep_idx + 1, false);
73 free(s);
62 } 74 }
63 } 75 }
64 return 0; 76 return 0;
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index ee33ba2f05dd..c852c7a85d32 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -15,6 +15,7 @@
15#include "util/debug.h" 15#include "util/debug.h"
16#include "util/session.h" 16#include "util/session.h"
17#include "util/tool.h" 17#include "util/tool.h"
18#include "util/data.h"
18 19
19#include <sys/types.h> 20#include <sys/types.h>
20#include <sys/prctl.h> 21#include <sys/prctl.h>
@@ -56,7 +57,9 @@ struct lock_stat {
56 57
57 unsigned int nr_readlock; 58 unsigned int nr_readlock;
58 unsigned int nr_trylock; 59 unsigned int nr_trylock;
60
59 /* these times are in nano sec. */ 61 /* these times are in nano sec. */
62 u64 avg_wait_time;
60 u64 wait_time_total; 63 u64 wait_time_total;
61 u64 wait_time_min; 64 u64 wait_time_min;
62 u64 wait_time_max; 65 u64 wait_time_max;
@@ -208,6 +211,7 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
208 211
209SINGLE_KEY(nr_acquired) 212SINGLE_KEY(nr_acquired)
210SINGLE_KEY(nr_contended) 213SINGLE_KEY(nr_contended)
214SINGLE_KEY(avg_wait_time)
211SINGLE_KEY(wait_time_total) 215SINGLE_KEY(wait_time_total)
212SINGLE_KEY(wait_time_max) 216SINGLE_KEY(wait_time_max)
213 217
@@ -244,6 +248,7 @@ static struct rb_root result; /* place to store sorted data */
244struct lock_key keys[] = { 248struct lock_key keys[] = {
245 DEF_KEY_LOCK(acquired, nr_acquired), 249 DEF_KEY_LOCK(acquired, nr_acquired),
246 DEF_KEY_LOCK(contended, nr_contended), 250 DEF_KEY_LOCK(contended, nr_contended),
251 DEF_KEY_LOCK(avg_wait, avg_wait_time),
247 DEF_KEY_LOCK(wait_total, wait_time_total), 252 DEF_KEY_LOCK(wait_total, wait_time_total),
248 DEF_KEY_LOCK(wait_min, wait_time_min), 253 DEF_KEY_LOCK(wait_min, wait_time_min),
249 DEF_KEY_LOCK(wait_max, wait_time_max), 254 DEF_KEY_LOCK(wait_max, wait_time_max),
@@ -321,10 +326,12 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
321 326
322 new->addr = addr; 327 new->addr = addr;
323 new->name = zalloc(sizeof(char) * strlen(name) + 1); 328 new->name = zalloc(sizeof(char) * strlen(name) + 1);
324 if (!new->name) 329 if (!new->name) {
330 free(new);
325 goto alloc_failed; 331 goto alloc_failed;
326 strcpy(new->name, name); 332 }
327 333
334 strcpy(new->name, name);
328 new->wait_time_min = ULLONG_MAX; 335 new->wait_time_min = ULLONG_MAX;
329 336
330 list_add(&new->hash_entry, entry); 337 list_add(&new->hash_entry, entry);
@@ -400,17 +407,17 @@ static int report_lock_acquire_event(struct perf_evsel *evsel,
400 407
401 ls = lock_stat_findnew(addr, name); 408 ls = lock_stat_findnew(addr, name);
402 if (!ls) 409 if (!ls)
403 return -1; 410 return -ENOMEM;
404 if (ls->discard) 411 if (ls->discard)
405 return 0; 412 return 0;
406 413
407 ts = thread_stat_findnew(sample->tid); 414 ts = thread_stat_findnew(sample->tid);
408 if (!ts) 415 if (!ts)
409 return -1; 416 return -ENOMEM;
410 417
411 seq = get_seq(ts, addr); 418 seq = get_seq(ts, addr);
412 if (!seq) 419 if (!seq)
413 return -1; 420 return -ENOMEM;
414 421
415 switch (seq->state) { 422 switch (seq->state) {
416 case SEQ_STATE_UNINITIALIZED: 423 case SEQ_STATE_UNINITIALIZED:
@@ -446,7 +453,6 @@ broken:
446 list_del(&seq->list); 453 list_del(&seq->list);
447 free(seq); 454 free(seq);
448 goto end; 455 goto end;
449 break;
450 default: 456 default:
451 BUG_ON("Unknown state of lock sequence found!\n"); 457 BUG_ON("Unknown state of lock sequence found!\n");
452 break; 458 break;
@@ -473,17 +479,17 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
473 479
474 ls = lock_stat_findnew(addr, name); 480 ls = lock_stat_findnew(addr, name);
475 if (!ls) 481 if (!ls)
476 return -1; 482 return -ENOMEM;
477 if (ls->discard) 483 if (ls->discard)
478 return 0; 484 return 0;
479 485
480 ts = thread_stat_findnew(sample->tid); 486 ts = thread_stat_findnew(sample->tid);
481 if (!ts) 487 if (!ts)
482 return -1; 488 return -ENOMEM;
483 489
484 seq = get_seq(ts, addr); 490 seq = get_seq(ts, addr);
485 if (!seq) 491 if (!seq)
486 return -1; 492 return -ENOMEM;
487 493
488 switch (seq->state) { 494 switch (seq->state) {
489 case SEQ_STATE_UNINITIALIZED: 495 case SEQ_STATE_UNINITIALIZED:
@@ -508,8 +514,6 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
508 list_del(&seq->list); 514 list_del(&seq->list);
509 free(seq); 515 free(seq);
510 goto end; 516 goto end;
511 break;
512
513 default: 517 default:
514 BUG_ON("Unknown state of lock sequence found!\n"); 518 BUG_ON("Unknown state of lock sequence found!\n");
515 break; 519 break;
@@ -517,6 +521,7 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
517 521
518 seq->state = SEQ_STATE_ACQUIRED; 522 seq->state = SEQ_STATE_ACQUIRED;
519 ls->nr_acquired++; 523 ls->nr_acquired++;
524 ls->avg_wait_time = ls->nr_contended ? ls->wait_time_total/ls->nr_contended : 0;
520 seq->prev_event_time = sample->time; 525 seq->prev_event_time = sample->time;
521end: 526end:
522 return 0; 527 return 0;
@@ -536,17 +541,17 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
536 541
537 ls = lock_stat_findnew(addr, name); 542 ls = lock_stat_findnew(addr, name);
538 if (!ls) 543 if (!ls)
539 return -1; 544 return -ENOMEM;
540 if (ls->discard) 545 if (ls->discard)
541 return 0; 546 return 0;
542 547
543 ts = thread_stat_findnew(sample->tid); 548 ts = thread_stat_findnew(sample->tid);
544 if (!ts) 549 if (!ts)
545 return -1; 550 return -ENOMEM;
546 551
547 seq = get_seq(ts, addr); 552 seq = get_seq(ts, addr);
548 if (!seq) 553 if (!seq)
549 return -1; 554 return -ENOMEM;
550 555
551 switch (seq->state) { 556 switch (seq->state) {
552 case SEQ_STATE_UNINITIALIZED: 557 case SEQ_STATE_UNINITIALIZED:
@@ -564,7 +569,6 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
564 list_del(&seq->list); 569 list_del(&seq->list);
565 free(seq); 570 free(seq);
566 goto end; 571 goto end;
567 break;
568 default: 572 default:
569 BUG_ON("Unknown state of lock sequence found!\n"); 573 BUG_ON("Unknown state of lock sequence found!\n");
570 break; 574 break;
@@ -572,6 +576,7 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
572 576
573 seq->state = SEQ_STATE_CONTENDED; 577 seq->state = SEQ_STATE_CONTENDED;
574 ls->nr_contended++; 578 ls->nr_contended++;
579 ls->avg_wait_time = ls->wait_time_total/ls->nr_contended;
575 seq->prev_event_time = sample->time; 580 seq->prev_event_time = sample->time;
576end: 581end:
577 return 0; 582 return 0;
@@ -591,22 +596,21 @@ static int report_lock_release_event(struct perf_evsel *evsel,
591 596
592 ls = lock_stat_findnew(addr, name); 597 ls = lock_stat_findnew(addr, name);
593 if (!ls) 598 if (!ls)
594 return -1; 599 return -ENOMEM;
595 if (ls->discard) 600 if (ls->discard)
596 return 0; 601 return 0;
597 602
598 ts = thread_stat_findnew(sample->tid); 603 ts = thread_stat_findnew(sample->tid);
599 if (!ts) 604 if (!ts)
600 return -1; 605 return -ENOMEM;
601 606
602 seq = get_seq(ts, addr); 607 seq = get_seq(ts, addr);
603 if (!seq) 608 if (!seq)
604 return -1; 609 return -ENOMEM;
605 610
606 switch (seq->state) { 611 switch (seq->state) {
607 case SEQ_STATE_UNINITIALIZED: 612 case SEQ_STATE_UNINITIALIZED:
608 goto end; 613 goto end;
609 break;
610 case SEQ_STATE_ACQUIRED: 614 case SEQ_STATE_ACQUIRED:
611 break; 615 break;
612 case SEQ_STATE_READ_ACQUIRED: 616 case SEQ_STATE_READ_ACQUIRED:
@@ -624,7 +628,6 @@ static int report_lock_release_event(struct perf_evsel *evsel,
624 ls->discard = 1; 628 ls->discard = 1;
625 bad_hist[BROKEN_RELEASE]++; 629 bad_hist[BROKEN_RELEASE]++;
626 goto free_seq; 630 goto free_seq;
627 break;
628 default: 631 default:
629 BUG_ON("Unknown state of lock sequence found!\n"); 632 BUG_ON("Unknown state of lock sequence found!\n");
630 break; 633 break;
@@ -690,7 +693,7 @@ static void print_bad_events(int bad, int total)
690 693
691 pr_info("\n=== output for debug===\n\n"); 694 pr_info("\n=== output for debug===\n\n");
692 pr_info("bad: %d, total: %d\n", bad, total); 695 pr_info("bad: %d, total: %d\n", bad, total);
693 pr_info("bad rate: %f %%\n", (double)bad / (double)total * 100); 696 pr_info("bad rate: %.2f %%\n", (double)bad / (double)total * 100);
694 pr_info("histogram of events caused bad sequence\n"); 697 pr_info("histogram of events caused bad sequence\n");
695 for (i = 0; i < BROKEN_MAX; i++) 698 for (i = 0; i < BROKEN_MAX; i++)
696 pr_info(" %10s: %d\n", name[i], bad_hist[i]); 699 pr_info(" %10s: %d\n", name[i], bad_hist[i]);
@@ -707,6 +710,7 @@ static void print_result(void)
707 pr_info("%10s ", "acquired"); 710 pr_info("%10s ", "acquired");
708 pr_info("%10s ", "contended"); 711 pr_info("%10s ", "contended");
709 712
713 pr_info("%15s ", "avg wait (ns)");
710 pr_info("%15s ", "total wait (ns)"); 714 pr_info("%15s ", "total wait (ns)");
711 pr_info("%15s ", "max wait (ns)"); 715 pr_info("%15s ", "max wait (ns)");
712 pr_info("%15s ", "min wait (ns)"); 716 pr_info("%15s ", "min wait (ns)");
@@ -738,6 +742,7 @@ static void print_result(void)
738 pr_info("%10u ", st->nr_acquired); 742 pr_info("%10u ", st->nr_acquired);
739 pr_info("%10u ", st->nr_contended); 743 pr_info("%10u ", st->nr_contended);
740 744
745 pr_info("%15" PRIu64 " ", st->avg_wait_time);
741 pr_info("%15" PRIu64 " ", st->wait_time_total); 746 pr_info("%15" PRIu64 " ", st->wait_time_total);
742 pr_info("%15" PRIu64 " ", st->wait_time_max); 747 pr_info("%15" PRIu64 " ", st->wait_time_max);
743 pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ? 748 pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
@@ -762,7 +767,7 @@ static void dump_threads(void)
762 while (node) { 767 while (node) {
763 st = container_of(node, struct thread_stat, rb); 768 st = container_of(node, struct thread_stat, rb);
764 t = perf_session__findnew(session, st->tid); 769 t = perf_session__findnew(session, st->tid);
765 pr_info("%10d: %s\n", st->tid, t->comm); 770 pr_info("%10d: %s\n", st->tid, thread__comm_str(t));
766 node = rb_next(node); 771 node = rb_next(node);
767 }; 772 };
768} 773}
@@ -814,14 +819,26 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
814 return -1; 819 return -1;
815 } 820 }
816 821
817 if (evsel->handler.func != NULL) { 822 if (evsel->handler != NULL) {
818 tracepoint_handler f = evsel->handler.func; 823 tracepoint_handler f = evsel->handler;
819 return f(evsel, sample); 824 return f(evsel, sample);
820 } 825 }
821 826
822 return 0; 827 return 0;
823} 828}
824 829
830static void sort_result(void)
831{
832 unsigned int i;
833 struct lock_stat *st;
834
835 for (i = 0; i < LOCKHASH_SIZE; i++) {
836 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
837 insert_to_result(st, compare);
838 }
839 }
840}
841
825static const struct perf_evsel_str_handler lock_tracepoints[] = { 842static const struct perf_evsel_str_handler lock_tracepoints[] = {
826 { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */ 843 { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */
827 { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ 844 { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
@@ -829,51 +846,51 @@ static const struct perf_evsel_str_handler lock_tracepoints[] = {
829 { "lock:lock_release", perf_evsel__process_lock_release, }, /* CONFIG_LOCKDEP */ 846 { "lock:lock_release", perf_evsel__process_lock_release, }, /* CONFIG_LOCKDEP */
830}; 847};
831 848
832static int read_events(void) 849static int __cmd_report(bool display_info)
833{ 850{
851 int err = -EINVAL;
834 struct perf_tool eops = { 852 struct perf_tool eops = {
835 .sample = process_sample_event, 853 .sample = process_sample_event,
836 .comm = perf_event__process_comm, 854 .comm = perf_event__process_comm,
837 .ordered_samples = true, 855 .ordered_samples = true,
838 }; 856 };
839 session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); 857 struct perf_data_file file = {
858 .path = input_name,
859 .mode = PERF_DATA_MODE_READ,
860 };
861
862 session = perf_session__new(&file, false, &eops);
840 if (!session) { 863 if (!session) {
841 pr_err("Initializing perf session failed\n"); 864 pr_err("Initializing perf session failed\n");
842 return -1; 865 return -ENOMEM;
843 } 866 }
844 867
868 if (!perf_session__has_traces(session, "lock record"))
869 goto out_delete;
870
845 if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) { 871 if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
846 pr_err("Initializing perf session tracepoint handlers failed\n"); 872 pr_err("Initializing perf session tracepoint handlers failed\n");
847 return -1; 873 goto out_delete;
848 } 874 }
849 875
850 return perf_session__process_events(session, &eops); 876 if (select_key())
851} 877 goto out_delete;
852
853static void sort_result(void)
854{
855 unsigned int i;
856 struct lock_stat *st;
857 878
858 for (i = 0; i < LOCKHASH_SIZE; i++) { 879 err = perf_session__process_events(session, &eops);
859 list_for_each_entry(st, &lockhash_table[i], hash_entry) { 880 if (err)
860 insert_to_result(st, compare); 881 goto out_delete;
861 }
862 }
863}
864 882
865static int __cmd_report(void)
866{
867 setup_pager(); 883 setup_pager();
884 if (display_info) /* used for info subcommand */
885 err = dump_info();
886 else {
887 sort_result();
888 print_result();
889 }
868 890
869 if ((select_key() != 0) || 891out_delete:
870 (read_events() != 0)) 892 perf_session__delete(session);
871 return -1; 893 return err;
872
873 sort_result();
874 print_result();
875
876 return 0;
877} 894}
878 895
879static int __cmd_record(int argc, const char **argv) 896static int __cmd_record(int argc, const char **argv)
@@ -881,7 +898,7 @@ static int __cmd_record(int argc, const char **argv)
881 const char *record_args[] = { 898 const char *record_args[] = {
882 "record", "-R", "-m", "1024", "-c", "1", 899 "record", "-R", "-m", "1024", "-c", "1",
883 }; 900 };
884 unsigned int rec_argc, i, j; 901 unsigned int rec_argc, i, j, ret;
885 const char **rec_argv; 902 const char **rec_argv;
886 903
887 for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) { 904 for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
@@ -898,7 +915,7 @@ static int __cmd_record(int argc, const char **argv)
898 rec_argc += 2 * ARRAY_SIZE(lock_tracepoints); 915 rec_argc += 2 * ARRAY_SIZE(lock_tracepoints);
899 916
900 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 917 rec_argv = calloc(rec_argc + 1, sizeof(char *));
901 if (rec_argv == NULL) 918 if (!rec_argv)
902 return -ENOMEM; 919 return -ENOMEM;
903 920
904 for (i = 0; i < ARRAY_SIZE(record_args); i++) 921 for (i = 0; i < ARRAY_SIZE(record_args); i++)
@@ -914,7 +931,9 @@ static int __cmd_record(int argc, const char **argv)
914 931
915 BUG_ON(i != rec_argc); 932 BUG_ON(i != rec_argc);
916 933
917 return cmd_record(i, rec_argv, NULL); 934 ret = cmd_record(i, rec_argv, NULL);
935 free(rec_argv);
936 return ret;
918} 937}
919 938
920int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) 939int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
@@ -934,7 +953,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
934 }; 953 };
935 const struct option report_options[] = { 954 const struct option report_options[] = {
936 OPT_STRING('k', "key", &sort_key, "acquired", 955 OPT_STRING('k', "key", &sort_key, "acquired",
937 "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"), 956 "key for sorting (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
938 /* TODO: type */ 957 /* TODO: type */
939 OPT_END() 958 OPT_END()
940 }; 959 };
@@ -972,7 +991,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
972 if (argc) 991 if (argc)
973 usage_with_options(report_usage, report_options); 992 usage_with_options(report_usage, report_options);
974 } 993 }
975 __cmd_report(); 994 rc = __cmd_report(false);
976 } else if (!strcmp(argv[0], "script")) { 995 } else if (!strcmp(argv[0], "script")) {
977 /* Aliased to 'perf script' */ 996 /* Aliased to 'perf script' */
978 return cmd_script(argc, argv, prefix); 997 return cmd_script(argc, argv, prefix);
@@ -985,11 +1004,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
985 } 1004 }
986 /* recycling report_lock_ops */ 1005 /* recycling report_lock_ops */
987 trace_handler = &report_lock_ops; 1006 trace_handler = &report_lock_ops;
988 setup_pager(); 1007 rc = __cmd_report(true);
989 if (read_events() != 0)
990 rc = -1;
991 else
992 rc = dump_info();
993 } else { 1008 } else {
994 usage_with_options(lock_usage, lock_options); 1009 usage_with_options(lock_usage, lock_options);
995 } 1010 }
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 253133a6251d..31c00f186da1 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -5,6 +5,7 @@
5#include "util/trace-event.h" 5#include "util/trace-event.h"
6#include "util/tool.h" 6#include "util/tool.h"
7#include "util/session.h" 7#include "util/session.h"
8#include "util/data.h"
8 9
9#define MEM_OPERATION_LOAD "load" 10#define MEM_OPERATION_LOAD "load"
10#define MEM_OPERATION_STORE "store" 11#define MEM_OPERATION_STORE "store"
@@ -119,10 +120,14 @@ static int process_sample_event(struct perf_tool *tool,
119 120
120static int report_raw_events(struct perf_mem *mem) 121static int report_raw_events(struct perf_mem *mem)
121{ 122{
123 struct perf_data_file file = {
124 .path = input_name,
125 .mode = PERF_DATA_MODE_READ,
126 };
122 int err = -EINVAL; 127 int err = -EINVAL;
123 int ret; 128 int ret;
124 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 129 struct perf_session *session = perf_session__new(&file, false,
125 0, false, &mem->tool); 130 &mem->tool);
126 131
127 if (session == NULL) 132 if (session == NULL)
128 return -ENOMEM; 133 return -ENOMEM;
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index e8a66f9a6715..6ea9e85bdc00 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -173,7 +173,7 @@ static int opt_set_target(const struct option *opt, const char *str,
173 if (str && !params.target) { 173 if (str && !params.target) {
174 if (!strcmp(opt->long_name, "exec")) 174 if (!strcmp(opt->long_name, "exec"))
175 params.uprobes = true; 175 params.uprobes = true;
176#ifdef DWARF_SUPPORT 176#ifdef HAVE_DWARF_SUPPORT
177 else if (!strcmp(opt->long_name, "module")) 177 else if (!strcmp(opt->long_name, "module"))
178 params.uprobes = false; 178 params.uprobes = false;
179#endif 179#endif
@@ -187,7 +187,7 @@ static int opt_set_target(const struct option *opt, const char *str,
187 return ret; 187 return ret;
188} 188}
189 189
190#ifdef DWARF_SUPPORT 190#ifdef HAVE_DWARF_SUPPORT
191static int opt_show_lines(const struct option *opt __maybe_unused, 191static int opt_show_lines(const struct option *opt __maybe_unused,
192 const char *str, int unset __maybe_unused) 192 const char *str, int unset __maybe_unused)
193{ 193{
@@ -257,7 +257,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
257 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 257 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
258 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 258 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
259 "perf probe --list", 259 "perf probe --list",
260#ifdef DWARF_SUPPORT 260#ifdef HAVE_DWARF_SUPPORT
261 "perf probe [<options>] --line 'LINEDESC'", 261 "perf probe [<options>] --line 'LINEDESC'",
262 "perf probe [<options>] --vars 'PROBEPOINT'", 262 "perf probe [<options>] --vars 'PROBEPOINT'",
263#endif 263#endif
@@ -271,7 +271,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
271 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 271 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
272 opt_del_probe_event), 272 opt_del_probe_event),
273 OPT_CALLBACK('a', "add", NULL, 273 OPT_CALLBACK('a', "add", NULL,
274#ifdef DWARF_SUPPORT 274#ifdef HAVE_DWARF_SUPPORT
275 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" 275 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
276 " [[NAME=]ARG ...]", 276 " [[NAME=]ARG ...]",
277#else 277#else
@@ -283,7 +283,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
283 "\t\tFUNC:\tFunction name\n" 283 "\t\tFUNC:\tFunction name\n"
284 "\t\tOFF:\tOffset from function entry (in byte)\n" 284 "\t\tOFF:\tOffset from function entry (in byte)\n"
285 "\t\t%return:\tPut the probe at function return\n" 285 "\t\t%return:\tPut the probe at function return\n"
286#ifdef DWARF_SUPPORT 286#ifdef HAVE_DWARF_SUPPORT
287 "\t\tSRC:\tSource code path\n" 287 "\t\tSRC:\tSource code path\n"
288 "\t\tRL:\tRelative line number from function entry.\n" 288 "\t\tRL:\tRelative line number from function entry.\n"
289 "\t\tAL:\tAbsolute line number in file.\n" 289 "\t\tAL:\tAbsolute line number in file.\n"
@@ -296,7 +296,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
296 opt_add_probe_event), 296 opt_add_probe_event),
297 OPT_BOOLEAN('f', "force", &params.force_add, "forcibly add events" 297 OPT_BOOLEAN('f', "force", &params.force_add, "forcibly add events"
298 " with existing name"), 298 " with existing name"),
299#ifdef DWARF_SUPPORT 299#ifdef HAVE_DWARF_SUPPORT
300 OPT_CALLBACK('L', "line", NULL, 300 OPT_CALLBACK('L', "line", NULL,
301 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", 301 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
302 "Show source code lines.", opt_show_lines), 302 "Show source code lines.", opt_show_lines),
@@ -325,6 +325,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
325 opt_set_filter), 325 opt_set_filter),
326 OPT_CALLBACK('x', "exec", NULL, "executable|path", 326 OPT_CALLBACK('x', "exec", NULL, "executable|path",
327 "target executable name or path", opt_set_target), 327 "target executable name or path", opt_set_target),
328 OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
329 "Disable symbol demangling"),
328 OPT_END() 330 OPT_END()
329 }; 331 };
330 int ret; 332 int ret;
@@ -408,7 +410,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
408 return ret; 410 return ret;
409 } 411 }
410 412
411#ifdef DWARF_SUPPORT 413#ifdef HAVE_DWARF_SUPPORT
412 if (params.show_lines && !params.uprobes) { 414 if (params.show_lines && !params.uprobes) {
413 if (params.mod_events) { 415 if (params.mod_events) {
414 pr_err(" Error: Don't use --line with" 416 pr_err(" Error: Don't use --line with"
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index a41ac41546c9..7c8020a32784 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -24,12 +24,13 @@
24#include "util/symbol.h" 24#include "util/symbol.h"
25#include "util/cpumap.h" 25#include "util/cpumap.h"
26#include "util/thread_map.h" 26#include "util/thread_map.h"
27#include "util/data.h"
27 28
28#include <unistd.h> 29#include <unistd.h>
29#include <sched.h> 30#include <sched.h>
30#include <sys/mman.h> 31#include <sys/mman.h>
31 32
32#ifndef HAVE_ON_EXIT 33#ifndef HAVE_ON_EXIT_SUPPORT
33#ifndef ATEXIT_MAX 34#ifndef ATEXIT_MAX
34#define ATEXIT_MAX 32 35#define ATEXIT_MAX 32
35#endif 36#endif
@@ -65,31 +66,25 @@ struct perf_record {
65 struct perf_tool tool; 66 struct perf_tool tool;
66 struct perf_record_opts opts; 67 struct perf_record_opts opts;
67 u64 bytes_written; 68 u64 bytes_written;
68 const char *output_name; 69 struct perf_data_file file;
69 struct perf_evlist *evlist; 70 struct perf_evlist *evlist;
70 struct perf_session *session; 71 struct perf_session *session;
71 const char *progname; 72 const char *progname;
72 int output;
73 unsigned int page_size;
74 int realtime_prio; 73 int realtime_prio;
75 bool no_buildid; 74 bool no_buildid;
76 bool no_buildid_cache; 75 bool no_buildid_cache;
77 long samples; 76 long samples;
78 off_t post_processing_offset;
79}; 77};
80 78
81static void advance_output(struct perf_record *rec, size_t size) 79static int do_write_output(struct perf_record *rec, void *buf, size_t size)
82{ 80{
83 rec->bytes_written += size; 81 struct perf_data_file *file = &rec->file;
84}
85 82
86static int write_output(struct perf_record *rec, void *buf, size_t size)
87{
88 while (size) { 83 while (size) {
89 int ret = write(rec->output, buf, size); 84 ssize_t ret = write(file->fd, buf, size);
90 85
91 if (ret < 0) { 86 if (ret < 0) {
92 pr_err("failed to write\n"); 87 pr_err("failed to write perf data, error: %m\n");
93 return -1; 88 return -1;
94 } 89 }
95 90
@@ -102,6 +97,11 @@ static int write_output(struct perf_record *rec, void *buf, size_t size)
102 return 0; 97 return 0;
103} 98}
104 99
100static int write_output(struct perf_record *rec, void *buf, size_t size)
101{
102 return do_write_output(rec, buf, size);
103}
104
105static int process_synthesized_event(struct perf_tool *tool, 105static int process_synthesized_event(struct perf_tool *tool,
106 union perf_event *event, 106 union perf_event *event,
107 struct perf_sample *sample __maybe_unused, 107 struct perf_sample *sample __maybe_unused,
@@ -119,7 +119,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
119{ 119{
120 unsigned int head = perf_mmap__read_head(md); 120 unsigned int head = perf_mmap__read_head(md);
121 unsigned int old = md->prev; 121 unsigned int old = md->prev;
122 unsigned char *data = md->base + rec->page_size; 122 unsigned char *data = md->base + page_size;
123 unsigned long size; 123 unsigned long size;
124 void *buf; 124 void *buf;
125 int rc = 0; 125 int rc = 0;
@@ -234,10 +234,6 @@ try_again:
234 "or try again with a smaller value of -m/--mmap_pages.\n" 234 "or try again with a smaller value of -m/--mmap_pages.\n"
235 "(current value: %d)\n", opts->mmap_pages); 235 "(current value: %d)\n", opts->mmap_pages);
236 rc = -errno; 236 rc = -errno;
237 } else if (!is_power_of_2(opts->mmap_pages) &&
238 (opts->mmap_pages != UINT_MAX)) {
239 pr_err("--mmap_pages/-m value must be a power of two.");
240 rc = -EINVAL;
241 } else { 237 } else {
242 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); 238 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
243 rc = -errno; 239 rc = -errno;
@@ -253,31 +249,34 @@ out:
253 249
254static int process_buildids(struct perf_record *rec) 250static int process_buildids(struct perf_record *rec)
255{ 251{
256 u64 size = lseek(rec->output, 0, SEEK_CUR); 252 struct perf_data_file *file = &rec->file;
253 struct perf_session *session = rec->session;
254 u64 start = session->header.data_offset;
257 255
256 u64 size = lseek(file->fd, 0, SEEK_CUR);
258 if (size == 0) 257 if (size == 0)
259 return 0; 258 return 0;
260 259
261 rec->session->fd = rec->output; 260 return __perf_session__process_events(session, start,
262 return __perf_session__process_events(rec->session, rec->post_processing_offset, 261 size - start,
263 size - rec->post_processing_offset,
264 size, &build_id__mark_dso_hit_ops); 262 size, &build_id__mark_dso_hit_ops);
265} 263}
266 264
267static void perf_record__exit(int status, void *arg) 265static void perf_record__exit(int status, void *arg)
268{ 266{
269 struct perf_record *rec = arg; 267 struct perf_record *rec = arg;
268 struct perf_data_file *file = &rec->file;
270 269
271 if (status != 0) 270 if (status != 0)
272 return; 271 return;
273 272
274 if (!rec->opts.pipe_output) { 273 if (!file->is_pipe) {
275 rec->session->header.data_size += rec->bytes_written; 274 rec->session->header.data_size += rec->bytes_written;
276 275
277 if (!rec->no_buildid) 276 if (!rec->no_buildid)
278 process_buildids(rec); 277 process_buildids(rec);
279 perf_session__write_header(rec->session, rec->evlist, 278 perf_session__write_header(rec->session, rec->evlist,
280 rec->output, true); 279 file->fd, true);
281 perf_session__delete(rec->session); 280 perf_session__delete(rec->session);
282 perf_evlist__delete(rec->evlist); 281 perf_evlist__delete(rec->evlist);
283 symbol__exit(); 282 symbol__exit();
@@ -343,64 +342,47 @@ out:
343 return rc; 342 return rc;
344} 343}
345 344
345static void perf_record__init_features(struct perf_record *rec)
346{
347 struct perf_evlist *evsel_list = rec->evlist;
348 struct perf_session *session = rec->session;
349 int feat;
350
351 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
352 perf_header__set_feat(&session->header, feat);
353
354 if (rec->no_buildid)
355 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
356
357 if (!have_tracepoints(&evsel_list->entries))
358 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
359
360 if (!rec->opts.branch_stack)
361 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
362}
363
346static int __cmd_record(struct perf_record *rec, int argc, const char **argv) 364static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
347{ 365{
348 struct stat st; 366 int err;
349 int flags;
350 int err, output, feat;
351 unsigned long waking = 0; 367 unsigned long waking = 0;
352 const bool forks = argc > 0; 368 const bool forks = argc > 0;
353 struct machine *machine; 369 struct machine *machine;
354 struct perf_tool *tool = &rec->tool; 370 struct perf_tool *tool = &rec->tool;
355 struct perf_record_opts *opts = &rec->opts; 371 struct perf_record_opts *opts = &rec->opts;
356 struct perf_evlist *evsel_list = rec->evlist; 372 struct perf_evlist *evsel_list = rec->evlist;
357 const char *output_name = rec->output_name; 373 struct perf_data_file *file = &rec->file;
358 struct perf_session *session; 374 struct perf_session *session;
359 bool disabled = false; 375 bool disabled = false;
360 376
361 rec->progname = argv[0]; 377 rec->progname = argv[0];
362 378
363 rec->page_size = sysconf(_SC_PAGE_SIZE);
364
365 on_exit(perf_record__sig_exit, rec); 379 on_exit(perf_record__sig_exit, rec);
366 signal(SIGCHLD, sig_handler); 380 signal(SIGCHLD, sig_handler);
367 signal(SIGINT, sig_handler); 381 signal(SIGINT, sig_handler);
368 signal(SIGUSR1, sig_handler); 382 signal(SIGUSR1, sig_handler);
369 signal(SIGTERM, sig_handler); 383 signal(SIGTERM, sig_handler);
370 384
371 if (!output_name) { 385 session = perf_session__new(file, false, NULL);
372 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
373 opts->pipe_output = true;
374 else
375 rec->output_name = output_name = "perf.data";
376 }
377 if (output_name) {
378 if (!strcmp(output_name, "-"))
379 opts->pipe_output = true;
380 else if (!stat(output_name, &st) && st.st_size) {
381 char oldname[PATH_MAX];
382 snprintf(oldname, sizeof(oldname), "%s.old",
383 output_name);
384 unlink(oldname);
385 rename(output_name, oldname);
386 }
387 }
388
389 flags = O_CREAT|O_RDWR|O_TRUNC;
390
391 if (opts->pipe_output)
392 output = STDOUT_FILENO;
393 else
394 output = open(output_name, flags, S_IRUSR | S_IWUSR);
395 if (output < 0) {
396 perror("failed to create output file");
397 return -1;
398 }
399
400 rec->output = output;
401
402 session = perf_session__new(output_name, O_WRONLY,
403 true, false, NULL);
404 if (session == NULL) { 386 if (session == NULL) {
405 pr_err("Not enough memory for reading perf file header\n"); 387 pr_err("Not enough memory for reading perf file header\n");
406 return -1; 388 return -1;
@@ -408,21 +390,11 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
408 390
409 rec->session = session; 391 rec->session = session;
410 392
411 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++) 393 perf_record__init_features(rec);
412 perf_header__set_feat(&session->header, feat);
413
414 if (rec->no_buildid)
415 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
416
417 if (!have_tracepoints(&evsel_list->entries))
418 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
419
420 if (!rec->opts.branch_stack)
421 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
422 394
423 if (forks) { 395 if (forks) {
424 err = perf_evlist__prepare_workload(evsel_list, &opts->target, 396 err = perf_evlist__prepare_workload(evsel_list, &opts->target,
425 argv, opts->pipe_output, 397 argv, file->is_pipe,
426 true); 398 true);
427 if (err < 0) { 399 if (err < 0) {
428 pr_err("Couldn't run the workload!\n"); 400 pr_err("Couldn't run the workload!\n");
@@ -443,13 +415,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
443 */ 415 */
444 on_exit(perf_record__exit, rec); 416 on_exit(perf_record__exit, rec);
445 417
446 if (opts->pipe_output) { 418 if (file->is_pipe) {
447 err = perf_header__write_pipe(output); 419 err = perf_header__write_pipe(file->fd);
448 if (err < 0) 420 if (err < 0)
449 goto out_delete_session; 421 goto out_delete_session;
450 } else { 422 } else {
451 err = perf_session__write_header(session, evsel_list, 423 err = perf_session__write_header(session, evsel_list,
452 output, false); 424 file->fd, false);
453 if (err < 0) 425 if (err < 0)
454 goto out_delete_session; 426 goto out_delete_session;
455 } 427 }
@@ -462,11 +434,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
462 goto out_delete_session; 434 goto out_delete_session;
463 } 435 }
464 436
465 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
466
467 machine = &session->machines.host; 437 machine = &session->machines.host;
468 438
469 if (opts->pipe_output) { 439 if (file->is_pipe) {
470 err = perf_event__synthesize_attrs(tool, session, 440 err = perf_event__synthesize_attrs(tool, session,
471 process_synthesized_event); 441 process_synthesized_event);
472 if (err < 0) { 442 if (err < 0) {
@@ -483,13 +453,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
483 * return this more properly and also 453 * return this more properly and also
484 * propagate errors that now are calling die() 454 * propagate errors that now are calling die()
485 */ 455 */
486 err = perf_event__synthesize_tracing_data(tool, output, evsel_list, 456 err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
487 process_synthesized_event); 457 process_synthesized_event);
488 if (err <= 0) { 458 if (err <= 0) {
489 pr_err("Couldn't record tracing data.\n"); 459 pr_err("Couldn't record tracing data.\n");
490 goto out_delete_session; 460 goto out_delete_session;
491 } 461 }
492 advance_output(rec, err); 462 rec->bytes_written += err;
493 } 463 }
494 } 464 }
495 465
@@ -515,16 +485,8 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
515 perf_event__synthesize_guest_os, tool); 485 perf_event__synthesize_guest_os, tool);
516 } 486 }
517 487
518 if (perf_target__has_task(&opts->target)) 488 err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads,
519 err = perf_event__synthesize_thread_map(tool, evsel_list->threads, 489 process_synthesized_event, opts->sample_address);
520 process_synthesized_event,
521 machine);
522 else if (perf_target__has_cpu(&opts->target))
523 err = perf_event__synthesize_threads(tool, process_synthesized_event,
524 machine);
525 else /* command specified */
526 err = 0;
527
528 if (err != 0) 490 if (err != 0)
529 goto out_delete_session; 491 goto out_delete_session;
530 492
@@ -544,7 +506,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
544 * (apart from group members) have enable_on_exec=1 set, 506 * (apart from group members) have enable_on_exec=1 set,
545 * so don't spoil it by prematurely enabling them. 507 * so don't spoil it by prematurely enabling them.
546 */ 508 */
547 if (!perf_target__none(&opts->target)) 509 if (!target__none(&opts->target))
548 perf_evlist__enable(evsel_list); 510 perf_evlist__enable(evsel_list);
549 511
550 /* 512 /*
@@ -573,7 +535,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
573 * die with the process and we wait for that. Thus no need to 535 * die with the process and we wait for that. Thus no need to
574 * disable events in this case. 536 * disable events in this case.
575 */ 537 */
576 if (done && !disabled && !perf_target__none(&opts->target)) { 538 if (done && !disabled && !target__none(&opts->target)) {
577 perf_evlist__disable(evsel_list); 539 perf_evlist__disable(evsel_list);
578 disabled = true; 540 disabled = true;
579 } 541 }
@@ -590,7 +552,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
590 fprintf(stderr, 552 fprintf(stderr,
591 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 553 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
592 (double)rec->bytes_written / 1024.0 / 1024.0, 554 (double)rec->bytes_written / 1024.0 / 1024.0,
593 output_name, 555 file->path,
594 rec->bytes_written / 24); 556 rec->bytes_written / 24);
595 557
596 return 0; 558 return 0;
@@ -618,6 +580,9 @@ static const struct branch_mode branch_modes[] = {
618 BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL), 580 BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
619 BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN), 581 BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
620 BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL), 582 BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
583 BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
584 BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
585 BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
621 BRANCH_END 586 BRANCH_END
622}; 587};
623 588
@@ -684,7 +649,7 @@ error:
684 return ret; 649 return ret;
685} 650}
686 651
687#ifdef LIBUNWIND_SUPPORT 652#ifdef HAVE_LIBUNWIND_SUPPORT
688static int get_stack_size(char *str, unsigned long *_size) 653static int get_stack_size(char *str, unsigned long *_size)
689{ 654{
690 char *endptr; 655 char *endptr;
@@ -710,23 +675,14 @@ static int get_stack_size(char *str, unsigned long *_size)
710 max_size, str); 675 max_size, str);
711 return -1; 676 return -1;
712} 677}
713#endif /* LIBUNWIND_SUPPORT */ 678#endif /* HAVE_LIBUNWIND_SUPPORT */
714 679
715int record_parse_callchain_opt(const struct option *opt, 680int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
716 const char *arg, int unset)
717{ 681{
718 struct perf_record_opts *opts = opt->value;
719 char *tok, *name, *saveptr = NULL; 682 char *tok, *name, *saveptr = NULL;
720 char *buf; 683 char *buf;
721 int ret = -1; 684 int ret = -1;
722 685
723 /* --no-call-graph */
724 if (unset)
725 return 0;
726
727 /* We specified default option if none is provided. */
728 BUG_ON(!arg);
729
730 /* We need buffer that we know we can write to. */ 686 /* We need buffer that we know we can write to. */
731 buf = malloc(strlen(arg) + 1); 687 buf = malloc(strlen(arg) + 1);
732 if (!buf) 688 if (!buf)
@@ -748,7 +704,7 @@ int record_parse_callchain_opt(const struct option *opt,
748 "needed for -g fp\n"); 704 "needed for -g fp\n");
749 break; 705 break;
750 706
751#ifdef LIBUNWIND_SUPPORT 707#ifdef HAVE_LIBUNWIND_SUPPORT
752 /* Dwarf style */ 708 /* Dwarf style */
753 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { 709 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
754 const unsigned long default_stack_dump_size = 8192; 710 const unsigned long default_stack_dump_size = 8192;
@@ -764,13 +720,9 @@ int record_parse_callchain_opt(const struct option *opt,
764 ret = get_stack_size(tok, &size); 720 ret = get_stack_size(tok, &size);
765 opts->stack_dump_size = size; 721 opts->stack_dump_size = size;
766 } 722 }
767 723#endif /* HAVE_LIBUNWIND_SUPPORT */
768 if (!ret)
769 pr_debug("callchain: stack dump size %d\n",
770 opts->stack_dump_size);
771#endif /* LIBUNWIND_SUPPORT */
772 } else { 724 } else {
773 pr_err("callchain: Unknown -g option " 725 pr_err("callchain: Unknown --call-graph option "
774 "value: %s\n", arg); 726 "value: %s\n", arg);
775 break; 727 break;
776 } 728 }
@@ -778,13 +730,52 @@ int record_parse_callchain_opt(const struct option *opt,
778 } while (0); 730 } while (0);
779 731
780 free(buf); 732 free(buf);
733 return ret;
734}
781 735
736static void callchain_debug(struct perf_record_opts *opts)
737{
738 pr_debug("callchain: type %d\n", opts->call_graph);
739
740 if (opts->call_graph == CALLCHAIN_DWARF)
741 pr_debug("callchain: stack dump size %d\n",
742 opts->stack_dump_size);
743}
744
745int record_parse_callchain_opt(const struct option *opt,
746 const char *arg,
747 int unset)
748{
749 struct perf_record_opts *opts = opt->value;
750 int ret;
751
752 /* --no-call-graph */
753 if (unset) {
754 opts->call_graph = CALLCHAIN_NONE;
755 pr_debug("callchain: disabled\n");
756 return 0;
757 }
758
759 ret = record_parse_callchain(arg, opts);
782 if (!ret) 760 if (!ret)
783 pr_debug("callchain: type %d\n", opts->call_graph); 761 callchain_debug(opts);
784 762
785 return ret; 763 return ret;
786} 764}
787 765
766int record_callchain_opt(const struct option *opt,
767 const char *arg __maybe_unused,
768 int unset __maybe_unused)
769{
770 struct perf_record_opts *opts = opt->value;
771
772 if (opts->call_graph == CALLCHAIN_NONE)
773 opts->call_graph = CALLCHAIN_FP;
774
775 callchain_debug(opts);
776 return 0;
777}
778
788static const char * const record_usage[] = { 779static const char * const record_usage[] = {
789 "perf record [<options>] [<command>]", 780 "perf record [<options>] [<command>]",
790 "perf record [<options>] -- <command> [<options>]", 781 "perf record [<options>] -- <command> [<options>]",
@@ -813,12 +804,12 @@ static struct perf_record record = {
813 }, 804 },
814}; 805};
815 806
816#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " 807#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
817 808
818#ifdef LIBUNWIND_SUPPORT 809#ifdef HAVE_LIBUNWIND_SUPPORT
819const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; 810const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
820#else 811#else
821const char record_callchain_help[] = CALLCHAIN_HELP "[fp]"; 812const char record_callchain_help[] = CALLCHAIN_HELP "fp";
822#endif 813#endif
823 814
824/* 815/*
@@ -849,18 +840,22 @@ const struct option record_options[] = {
849 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", 840 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
850 "list of cpus to monitor"), 841 "list of cpus to monitor"),
851 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 842 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
852 OPT_STRING('o', "output", &record.output_name, "file", 843 OPT_STRING('o', "output", &record.file.path, "file",
853 "output file name"), 844 "output file name"),
854 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, 845 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
855 "child tasks do not inherit counters"), 846 "child tasks do not inherit counters"),
856 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), 847 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
857 OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages, 848 OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
858 "number of mmap data pages"), 849 "number of mmap data pages",
850 perf_evlist__parse_mmap_pages),
859 OPT_BOOLEAN(0, "group", &record.opts.group, 851 OPT_BOOLEAN(0, "group", &record.opts.group,
860 "put the counters into a counter group"), 852 "put the counters into a counter group"),
861 OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts, 853 OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
862 "mode[,dump_size]", record_callchain_help, 854 NULL, "enables call-graph recording" ,
863 &record_parse_callchain_opt, "fp"), 855 &record_callchain_opt),
856 OPT_CALLBACK(0, "call-graph", &record.opts,
857 "mode[,dump_size]", record_callchain_help,
858 &record_parse_callchain_opt),
864 OPT_INCR('v', "verbose", &verbose, 859 OPT_INCR('v', "verbose", &verbose,
865 "be more verbose (show counter open errors, etc)"), 860 "be more verbose (show counter open errors, etc)"),
866 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 861 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
@@ -891,6 +886,10 @@ const struct option record_options[] = {
891 parse_branch_stack), 886 parse_branch_stack),
892 OPT_BOOLEAN('W', "weight", &record.opts.sample_weight, 887 OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
893 "sample by weight (on special events only)"), 888 "sample by weight (on special events only)"),
889 OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
890 "sample transaction flags (special events only)"),
891 OPT_BOOLEAN(0, "force-per-cpu", &record.opts.target.force_per_cpu,
892 "force the use of per-cpu mmaps"),
894 OPT_END() 893 OPT_END()
895}; 894};
896 895
@@ -909,7 +908,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
909 908
910 argc = parse_options(argc, argv, record_options, record_usage, 909 argc = parse_options(argc, argv, record_options, record_usage,
911 PARSE_OPT_STOP_AT_NON_OPTION); 910 PARSE_OPT_STOP_AT_NON_OPTION);
912 if (!argc && perf_target__none(&rec->opts.target)) 911 if (!argc && target__none(&rec->opts.target))
913 usage_with_options(record_usage, record_options); 912 usage_with_options(record_usage, record_options);
914 913
915 if (nr_cgroups && !rec->opts.target.system_wide) { 914 if (nr_cgroups && !rec->opts.target.system_wide) {
@@ -939,17 +938,17 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
939 goto out_symbol_exit; 938 goto out_symbol_exit;
940 } 939 }
941 940
942 err = perf_target__validate(&rec->opts.target); 941 err = target__validate(&rec->opts.target);
943 if (err) { 942 if (err) {
944 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 943 target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
945 ui__warning("%s", errbuf); 944 ui__warning("%s", errbuf);
946 } 945 }
947 946
948 err = perf_target__parse_uid(&rec->opts.target); 947 err = target__parse_uid(&rec->opts.target);
949 if (err) { 948 if (err) {
950 int saved_errno = errno; 949 int saved_errno = errno;
951 950
952 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 951 target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
953 ui__error("%s", errbuf); 952 ui__error("%s", errbuf);
954 953
955 err = -saved_errno; 954 err = -saved_errno;
@@ -960,20 +959,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
960 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) 959 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
961 usage_with_options(record_usage, record_options); 960 usage_with_options(record_usage, record_options);
962 961
963 if (rec->opts.user_interval != ULLONG_MAX) 962 if (perf_record_opts__config(&rec->opts)) {
964 rec->opts.default_interval = rec->opts.user_interval;
965 if (rec->opts.user_freq != UINT_MAX)
966 rec->opts.freq = rec->opts.user_freq;
967
968 /*
969 * User specified count overrides default frequency.
970 */
971 if (rec->opts.default_interval)
972 rec->opts.freq = 0;
973 else if (rec->opts.freq) {
974 rec->opts.default_interval = rec->opts.freq;
975 } else {
976 ui__error("frequency and count are zero, aborting\n");
977 err = -EINVAL; 963 err = -EINVAL;
978 goto out_free_fd; 964 goto out_free_fd;
979 } 965 }
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 72eae7498c09..8cf8e66ba594 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -33,8 +33,10 @@
33#include "util/thread.h" 33#include "util/thread.h"
34#include "util/sort.h" 34#include "util/sort.h"
35#include "util/hist.h" 35#include "util/hist.h"
36#include "util/data.h"
36#include "arch/common.h" 37#include "arch/common.h"
37 38
39#include <dlfcn.h>
38#include <linux/bitmap.h> 40#include <linux/bitmap.h>
39 41
40struct perf_report { 42struct perf_report {
@@ -47,6 +49,7 @@ struct perf_report {
47 bool show_threads; 49 bool show_threads;
48 bool inverted_callchain; 50 bool inverted_callchain;
49 bool mem_mode; 51 bool mem_mode;
52 int max_stack;
50 struct perf_read_values show_threads_values; 53 struct perf_read_values show_threads_values;
51 const char *pretty_printing_style; 54 const char *pretty_printing_style;
52 const char *cpu_list; 55 const char *cpu_list;
@@ -88,7 +91,8 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
88 if ((sort__has_parent || symbol_conf.use_callchain) && 91 if ((sort__has_parent || symbol_conf.use_callchain) &&
89 sample->callchain) { 92 sample->callchain) {
90 err = machine__resolve_callchain(machine, evsel, al->thread, 93 err = machine__resolve_callchain(machine, evsel, al->thread,
91 sample, &parent, al); 94 sample, &parent, al,
95 rep->max_stack);
92 if (err) 96 if (err)
93 return err; 97 return err;
94 } 98 }
@@ -111,7 +115,8 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
111 * and this is indirectly achieved by passing period=weight here 115 * and this is indirectly achieved by passing period=weight here
112 * and the he_stat__add_period() function. 116 * and the he_stat__add_period() function.
113 */ 117 */
114 he = __hists__add_mem_entry(&evsel->hists, al, parent, mi, cost, cost); 118 he = __hists__add_entry(&evsel->hists, al, parent, NULL, mi,
119 cost, cost, 0);
115 if (!he) 120 if (!he)
116 return -ENOMEM; 121 return -ENOMEM;
117 122
@@ -179,7 +184,8 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
179 if ((sort__has_parent || symbol_conf.use_callchain) 184 if ((sort__has_parent || symbol_conf.use_callchain)
180 && sample->callchain) { 185 && sample->callchain) {
181 err = machine__resolve_callchain(machine, evsel, al->thread, 186 err = machine__resolve_callchain(machine, evsel, al->thread,
182 sample, &parent, al); 187 sample, &parent, al,
188 rep->max_stack);
183 if (err) 189 if (err)
184 return err; 190 return err;
185 } 191 }
@@ -195,12 +201,16 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
195 201
196 err = -ENOMEM; 202 err = -ENOMEM;
197 203
204 /* overwrite the 'al' to branch-to info */
205 al->map = bi[i].to.map;
206 al->sym = bi[i].to.sym;
207 al->addr = bi[i].to.addr;
198 /* 208 /*
199 * The report shows the percentage of total branches captured 209 * The report shows the percentage of total branches captured
200 * and not events sampled. Thus we use a pseudo period of 1. 210 * and not events sampled. Thus we use a pseudo period of 1.
201 */ 211 */
202 he = __hists__add_branch_entry(&evsel->hists, al, parent, 212 he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
203 &bi[i], 1, 1); 213 1, 1, 0);
204 if (he) { 214 if (he) {
205 struct annotation *notes; 215 struct annotation *notes;
206 bx = he->branch_info; 216 bx = he->branch_info;
@@ -242,24 +252,28 @@ out:
242 return err; 252 return err;
243} 253}
244 254
245static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, 255static int perf_evsel__add_hist_entry(struct perf_tool *tool,
256 struct perf_evsel *evsel,
246 struct addr_location *al, 257 struct addr_location *al,
247 struct perf_sample *sample, 258 struct perf_sample *sample,
248 struct machine *machine) 259 struct machine *machine)
249{ 260{
261 struct perf_report *rep = container_of(tool, struct perf_report, tool);
250 struct symbol *parent = NULL; 262 struct symbol *parent = NULL;
251 int err = 0; 263 int err = 0;
252 struct hist_entry *he; 264 struct hist_entry *he;
253 265
254 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 266 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
255 err = machine__resolve_callchain(machine, evsel, al->thread, 267 err = machine__resolve_callchain(machine, evsel, al->thread,
256 sample, &parent, al); 268 sample, &parent, al,
269 rep->max_stack);
257 if (err) 270 if (err)
258 return err; 271 return err;
259 } 272 }
260 273
261 he = __hists__add_entry(&evsel->hists, al, parent, sample->period, 274 he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
262 sample->weight); 275 sample->period, sample->weight,
276 sample->transaction);
263 if (he == NULL) 277 if (he == NULL)
264 return -ENOMEM; 278 return -ENOMEM;
265 279
@@ -330,7 +344,8 @@ static int process_sample_event(struct perf_tool *tool,
330 if (al.map != NULL) 344 if (al.map != NULL)
331 al.map->dso->hit = 1; 345 al.map->dso->hit = 1;
332 346
333 ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine); 347 ret = perf_evsel__add_hist_entry(tool, evsel, &al, sample,
348 machine);
334 if (ret < 0) 349 if (ret < 0)
335 pr_debug("problem incrementing symbol period, skipping event\n"); 350 pr_debug("problem incrementing symbol period, skipping event\n");
336 } 351 }
@@ -364,10 +379,11 @@ static int process_read_event(struct perf_tool *tool,
364/* For pipe mode, sample_type is not currently set */ 379/* For pipe mode, sample_type is not currently set */
365static int perf_report__setup_sample_type(struct perf_report *rep) 380static int perf_report__setup_sample_type(struct perf_report *rep)
366{ 381{
367 struct perf_session *self = rep->session; 382 struct perf_session *session = rep->session;
368 u64 sample_type = perf_evlist__combined_sample_type(self->evlist); 383 u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
384 bool is_pipe = perf_data_file__is_pipe(session->file);
369 385
370 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { 386 if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
371 if (sort__has_parent) { 387 if (sort__has_parent) {
372 ui__error("Selected --sort parent, but no " 388 ui__error("Selected --sort parent, but no "
373 "callchain data. Did you call " 389 "callchain data. Did you call "
@@ -390,7 +406,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
390 } 406 }
391 407
392 if (sort__mode == SORT_MODE__BRANCH) { 408 if (sort__mode == SORT_MODE__BRANCH) {
393 if (!self->fd_pipe && 409 if (!is_pipe &&
394 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { 410 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
395 ui__error("Selected -b but no branch data. " 411 ui__error("Selected -b but no branch data. "
396 "Did you call perf record without -b?\n"); 412 "Did you call perf record without -b?\n");
@@ -407,14 +423,14 @@ static void sig_handler(int sig __maybe_unused)
407} 423}
408 424
409static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, 425static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
410 struct hists *self, 426 struct hists *hists,
411 const char *evname, FILE *fp) 427 const char *evname, FILE *fp)
412{ 428{
413 size_t ret; 429 size_t ret;
414 char unit; 430 char unit;
415 unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; 431 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
416 u64 nr_events = self->stats.total_period; 432 u64 nr_events = hists->stats.total_period;
417 struct perf_evsel *evsel = hists_to_evsel(self); 433 struct perf_evsel *evsel = hists_to_evsel(hists);
418 char buf[512]; 434 char buf[512];
419 size_t size = sizeof(buf); 435 size_t size = sizeof(buf);
420 436
@@ -486,6 +502,8 @@ static int __cmd_report(struct perf_report *rep)
486 struct map *kernel_map; 502 struct map *kernel_map;
487 struct kmap *kernel_kmap; 503 struct kmap *kernel_kmap;
488 const char *help = "For a higher level overview, try: perf report --sort comm,dso"; 504 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
505 struct ui_progress prog;
506 struct perf_data_file *file = session->file;
489 507
490 signal(SIGINT, sig_handler); 508 signal(SIGINT, sig_handler);
491 509
@@ -547,13 +565,19 @@ static int __cmd_report(struct perf_report *rep)
547 } 565 }
548 566
549 nr_samples = 0; 567 nr_samples = 0;
568 list_for_each_entry(pos, &session->evlist->entries, node)
569 nr_samples += pos->hists.nr_entries;
570
571 ui_progress__init(&prog, nr_samples, "Merging related events...");
572
573 nr_samples = 0;
550 list_for_each_entry(pos, &session->evlist->entries, node) { 574 list_for_each_entry(pos, &session->evlist->entries, node) {
551 struct hists *hists = &pos->hists; 575 struct hists *hists = &pos->hists;
552 576
553 if (pos->idx == 0) 577 if (pos->idx == 0)
554 hists->symbol_filter_str = rep->symbol_filter_str; 578 hists->symbol_filter_str = rep->symbol_filter_str;
555 579
556 hists__collapse_resort(hists); 580 hists__collapse_resort(hists, &prog);
557 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; 581 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
558 582
559 /* Non-group events are considered as leader */ 583 /* Non-group events are considered as leader */
@@ -565,12 +589,13 @@ static int __cmd_report(struct perf_report *rep)
565 hists__link(leader_hists, hists); 589 hists__link(leader_hists, hists);
566 } 590 }
567 } 591 }
592 ui_progress__finish();
568 593
569 if (session_done()) 594 if (session_done())
570 return 0; 595 return 0;
571 596
572 if (nr_samples == 0) { 597 if (nr_samples == 0) {
573 ui__error("The %s file has no samples!\n", session->filename); 598 ui__error("The %s file has no samples!\n", file->path);
574 return 0; 599 return 0;
575 } 600 }
576 601
@@ -591,8 +616,19 @@ static int __cmd_report(struct perf_report *rep)
591 ret = 0; 616 ret = 0;
592 617
593 } else if (use_browser == 2) { 618 } else if (use_browser == 2) {
594 perf_evlist__gtk_browse_hists(session->evlist, help, 619 int (*hist_browser)(struct perf_evlist *,
595 NULL, rep->min_percent); 620 const char *,
621 struct hist_browser_timer *,
622 float min_pcnt);
623
624 hist_browser = dlsym(perf_gtk_handle,
625 "perf_evlist__gtk_browse_hists");
626 if (hist_browser == NULL) {
627 ui__error("GTK browser not found!\n");
628 return ret;
629 }
630 hist_browser(session->evlist, help, NULL,
631 rep->min_percent);
596 } 632 }
597 } else 633 } else
598 perf_evlist__tty_browse_hists(session->evlist, rep, help); 634 perf_evlist__tty_browse_hists(session->evlist, rep, help);
@@ -757,6 +793,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
757 .ordered_samples = true, 793 .ordered_samples = true,
758 .ordering_requires_timestamps = true, 794 .ordering_requires_timestamps = true,
759 }, 795 },
796 .max_stack = PERF_MAX_STACK_DEPTH,
760 .pretty_printing_style = "normal", 797 .pretty_printing_style = "normal",
761 }; 798 };
762 const struct option options[] = { 799 const struct option options[] = {
@@ -787,7 +824,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
787 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," 824 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
788 " dso_to, dso_from, symbol_to, symbol_from, mispredict," 825 " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
789 " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, " 826 " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, "
790 "snoop, locked"), 827 "snoop, locked, abort, in_tx, transaction"),
791 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 828 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
792 "Show sample percentage for different cpu modes"), 829 "Show sample percentage for different cpu modes"),
793 OPT_STRING('p', "parent", &parent_pattern, "regex", 830 OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -797,6 +834,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
797 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 834 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
798 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). " 835 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
799 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt), 836 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
837 OPT_INTEGER(0, "max-stack", &report.max_stack,
838 "Set the maximum stack depth when parsing the callchain, "
839 "anything beyond the specified depth will be ignored. "
840 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
800 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, 841 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
801 "alias for inverted call graph"), 842 "alias for inverted call graph"),
802 OPT_CALLBACK(0, "ignore-callees", NULL, "regex", 843 OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
@@ -845,6 +886,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
845 "Don't show entries under that percent", parse_percent_limit), 886 "Don't show entries under that percent", parse_percent_limit),
846 OPT_END() 887 OPT_END()
847 }; 888 };
889 struct perf_data_file file = {
890 .mode = PERF_DATA_MODE_READ,
891 };
848 892
849 perf_config(perf_report_config, &report); 893 perf_config(perf_report_config, &report);
850 894
@@ -867,16 +911,11 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
867 input_name = "perf.data"; 911 input_name = "perf.data";
868 } 912 }
869 913
870 if (strcmp(input_name, "-") != 0) 914 file.path = input_name;
871 setup_browser(true); 915 file.force = report.force;
872 else {
873 use_browser = 0;
874 perf_hpp__init();
875 }
876 916
877repeat: 917repeat:
878 session = perf_session__new(input_name, O_RDONLY, 918 session = perf_session__new(&file, false, &report.tool);
879 report.force, false, &report.tool);
880 if (session == NULL) 919 if (session == NULL)
881 return -ENOMEM; 920 return -ENOMEM;
882 921
@@ -914,8 +953,22 @@ repeat:
914 sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; 953 sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
915 } 954 }
916 955
917 if (setup_sorting() < 0) 956 if (setup_sorting() < 0) {
918 usage_with_options(report_usage, options); 957 parse_options_usage(report_usage, options, "s", 1);
958 goto error;
959 }
960
961 if (parent_pattern != default_parent_pattern) {
962 if (sort_dimension__add("parent") < 0)
963 goto error;
964 }
965
966 if (strcmp(input_name, "-") != 0)
967 setup_browser(true);
968 else {
969 use_browser = 0;
970 perf_hpp__init();
971 }
919 972
920 /* 973 /*
921 * Only in the TUI browser we are doing integrated annotation, 974 * Only in the TUI browser we are doing integrated annotation,
@@ -946,11 +999,6 @@ repeat:
946 if (symbol__init() < 0) 999 if (symbol__init() < 0)
947 goto error; 1000 goto error;
948 1001
949 if (parent_pattern != default_parent_pattern) {
950 if (sort_dimension__add("parent") < 0)
951 goto error;
952 }
953
954 if (argc) { 1002 if (argc) {
955 /* 1003 /*
956 * Special case: if there's an argument left then assume that 1004 * Special case: if there's an argument left then assume that
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index d8c51b2f263f..0f3c65518a2c 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -737,12 +737,12 @@ static int replay_fork_event(struct perf_sched *sched,
737 737
738 if (verbose) { 738 if (verbose) {
739 printf("fork event\n"); 739 printf("fork event\n");
740 printf("... parent: %s/%d\n", parent->comm, parent->tid); 740 printf("... parent: %s/%d\n", thread__comm_str(parent), parent->tid);
741 printf("... child: %s/%d\n", child->comm, child->tid); 741 printf("... child: %s/%d\n", thread__comm_str(child), child->tid);
742 } 742 }
743 743
744 register_pid(sched, parent->tid, parent->comm); 744 register_pid(sched, parent->tid, thread__comm_str(parent));
745 register_pid(sched, child->tid, child->comm); 745 register_pid(sched, child->tid, thread__comm_str(child));
746 return 0; 746 return 0;
747} 747}
748 748
@@ -1077,7 +1077,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
1077 if (!atoms) { 1077 if (!atoms) {
1078 if (thread_atoms_insert(sched, migrant)) 1078 if (thread_atoms_insert(sched, migrant))
1079 return -1; 1079 return -1;
1080 register_pid(sched, migrant->tid, migrant->comm); 1080 register_pid(sched, migrant->tid, thread__comm_str(migrant));
1081 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1081 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1082 if (!atoms) { 1082 if (!atoms) {
1083 pr_err("migration-event: Internal tree error"); 1083 pr_err("migration-event: Internal tree error");
@@ -1111,13 +1111,13 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
1111 /* 1111 /*
1112 * Ignore idle threads: 1112 * Ignore idle threads:
1113 */ 1113 */
1114 if (!strcmp(work_list->thread->comm, "swapper")) 1114 if (!strcmp(thread__comm_str(work_list->thread), "swapper"))
1115 return; 1115 return;
1116 1116
1117 sched->all_runtime += work_list->total_runtime; 1117 sched->all_runtime += work_list->total_runtime;
1118 sched->all_count += work_list->nb_atoms; 1118 sched->all_count += work_list->nb_atoms;
1119 1119
1120 ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->tid); 1120 ret = printf(" %s:%d ", thread__comm_str(work_list->thread), work_list->thread->tid);
1121 1121
1122 for (i = 0; i < 24 - ret; i++) 1122 for (i = 0; i < 24 - ret; i++)
1123 printf(" "); 1123 printf(" ");
@@ -1334,7 +1334,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1334 printf(" %12.6f secs ", (double)timestamp/1e9); 1334 printf(" %12.6f secs ", (double)timestamp/1e9);
1335 if (new_shortname) { 1335 if (new_shortname) {
1336 printf("%s => %s:%d\n", 1336 printf("%s => %s:%d\n",
1337 sched_in->shortname, sched_in->comm, sched_in->tid); 1337 sched_in->shortname, thread__comm_str(sched_in), sched_in->tid);
1338 } else { 1338 } else {
1339 printf("\n"); 1339 printf("\n");
1340 } 1340 }
@@ -1427,8 +1427,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
1427 evsel->hists.stats.total_period += sample->period; 1427 evsel->hists.stats.total_period += sample->period;
1428 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 1428 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
1429 1429
1430 if (evsel->handler.func != NULL) { 1430 if (evsel->handler != NULL) {
1431 tracepoint_handler f = evsel->handler.func; 1431 tracepoint_handler f = evsel->handler;
1432 err = f(tool, evsel, sample, machine); 1432 err = f(tool, evsel, sample, machine);
1433 } 1433 }
1434 1434
@@ -1446,8 +1446,12 @@ static int perf_sched__read_events(struct perf_sched *sched,
1446 { "sched:sched_migrate_task", process_sched_migrate_task_event, }, 1446 { "sched:sched_migrate_task", process_sched_migrate_task_event, },
1447 }; 1447 };
1448 struct perf_session *session; 1448 struct perf_session *session;
1449 struct perf_data_file file = {
1450 .path = input_name,
1451 .mode = PERF_DATA_MODE_READ,
1452 };
1449 1453
1450 session = perf_session__new(input_name, O_RDONLY, 0, false, &sched->tool); 1454 session = perf_session__new(&file, false, &sched->tool);
1451 if (session == NULL) { 1455 if (session == NULL) {
1452 pr_debug("No Memory for session\n"); 1456 pr_debug("No Memory for session\n");
1453 return -1; 1457 return -1;
@@ -1651,29 +1655,27 @@ static int __cmd_record(int argc, const char **argv)
1651 return cmd_record(i, rec_argv, NULL); 1655 return cmd_record(i, rec_argv, NULL);
1652} 1656}
1653 1657
1654static const char default_sort_order[] = "avg, max, switch, runtime";
1655static struct perf_sched sched = {
1656 .tool = {
1657 .sample = perf_sched__process_tracepoint_sample,
1658 .comm = perf_event__process_comm,
1659 .lost = perf_event__process_lost,
1660 .fork = perf_sched__process_fork_event,
1661 .ordered_samples = true,
1662 },
1663 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
1664 .sort_list = LIST_HEAD_INIT(sched.sort_list),
1665 .start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
1666 .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
1667 .curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
1668 .sort_order = default_sort_order,
1669 .replay_repeat = 10,
1670 .profile_cpu = -1,
1671 .next_shortname1 = 'A',
1672 .next_shortname2 = '0',
1673};
1674
1675int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) 1658int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1676{ 1659{
1660 const char default_sort_order[] = "avg, max, switch, runtime";
1661 struct perf_sched sched = {
1662 .tool = {
1663 .sample = perf_sched__process_tracepoint_sample,
1664 .comm = perf_event__process_comm,
1665 .lost = perf_event__process_lost,
1666 .fork = perf_sched__process_fork_event,
1667 .ordered_samples = true,
1668 },
1669 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
1670 .sort_list = LIST_HEAD_INIT(sched.sort_list),
1671 .start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
1672 .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
1673 .sort_order = default_sort_order,
1674 .replay_repeat = 10,
1675 .profile_cpu = -1,
1676 .next_shortname1 = 'A',
1677 .next_shortname2 = '0',
1678 };
1677 const struct option latency_options[] = { 1679 const struct option latency_options[] = {
1678 OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", 1680 OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
1679 "sort by key(s): runtime, switch, avg, max"), 1681 "sort by key(s): runtime, switch, avg, max"),
@@ -1729,6 +1731,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1729 .switch_event = replay_switch_event, 1731 .switch_event = replay_switch_event,
1730 .fork_event = replay_fork_event, 1732 .fork_event = replay_fork_event,
1731 }; 1733 };
1734 unsigned int i;
1735
1736 for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++)
1737 sched.curr_pid[i] = -1;
1732 1738
1733 argc = parse_options(argc, argv, sched_options, sched_usage, 1739 argc = parse_options(argc, argv, sched_options, sched_usage,
1734 PARSE_OPT_STOP_AT_NON_OPTION); 1740 PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 9c333ff3dfeb..baf17989a216 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -15,6 +15,7 @@
15#include "util/evlist.h" 15#include "util/evlist.h"
16#include "util/evsel.h" 16#include "util/evsel.h"
17#include "util/sort.h" 17#include "util/sort.h"
18#include "util/data.h"
18#include <linux/bitmap.h> 19#include <linux/bitmap.h>
19 20
20static char const *script_name; 21static char const *script_name;
@@ -228,6 +229,24 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
228 return 0; 229 return 0;
229} 230}
230 231
232static void set_print_ip_opts(struct perf_event_attr *attr)
233{
234 unsigned int type = attr->type;
235
236 output[type].print_ip_opts = 0;
237 if (PRINT_FIELD(IP))
238 output[type].print_ip_opts |= PRINT_IP_OPT_IP;
239
240 if (PRINT_FIELD(SYM))
241 output[type].print_ip_opts |= PRINT_IP_OPT_SYM;
242
243 if (PRINT_FIELD(DSO))
244 output[type].print_ip_opts |= PRINT_IP_OPT_DSO;
245
246 if (PRINT_FIELD(SYMOFFSET))
247 output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
248}
249
231/* 250/*
232 * verify all user requested events exist and the samples 251 * verify all user requested events exist and the samples
233 * have the expected data 252 * have the expected data
@@ -236,7 +255,6 @@ static int perf_session__check_output_opt(struct perf_session *session)
236{ 255{
237 int j; 256 int j;
238 struct perf_evsel *evsel; 257 struct perf_evsel *evsel;
239 struct perf_event_attr *attr;
240 258
241 for (j = 0; j < PERF_TYPE_MAX; ++j) { 259 for (j = 0; j < PERF_TYPE_MAX; ++j) {
242 evsel = perf_session__find_first_evtype(session, j); 260 evsel = perf_session__find_first_evtype(session, j);
@@ -259,20 +277,7 @@ static int perf_session__check_output_opt(struct perf_session *session)
259 if (evsel == NULL) 277 if (evsel == NULL)
260 continue; 278 continue;
261 279
262 attr = &evsel->attr; 280 set_print_ip_opts(&evsel->attr);
263
264 output[j].print_ip_opts = 0;
265 if (PRINT_FIELD(IP))
266 output[j].print_ip_opts |= PRINT_IP_OPT_IP;
267
268 if (PRINT_FIELD(SYM))
269 output[j].print_ip_opts |= PRINT_IP_OPT_SYM;
270
271 if (PRINT_FIELD(DSO))
272 output[j].print_ip_opts |= PRINT_IP_OPT_DSO;
273
274 if (PRINT_FIELD(SYMOFFSET))
275 output[j].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
276 } 281 }
277 282
278 return 0; 283 return 0;
@@ -290,11 +295,11 @@ static void print_sample_start(struct perf_sample *sample,
290 295
291 if (PRINT_FIELD(COMM)) { 296 if (PRINT_FIELD(COMM)) {
292 if (latency_format) 297 if (latency_format)
293 printf("%8.8s ", thread->comm); 298 printf("%8.8s ", thread__comm_str(thread));
294 else if (PRINT_FIELD(IP) && symbol_conf.use_callchain) 299 else if (PRINT_FIELD(IP) && symbol_conf.use_callchain)
295 printf("%s ", thread->comm); 300 printf("%s ", thread__comm_str(thread));
296 else 301 else
297 printf("%16s ", thread->comm); 302 printf("%16s ", thread__comm_str(thread));
298 } 303 }
299 304
300 if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) 305 if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
@@ -409,7 +414,9 @@ static void print_sample_bts(union perf_event *event,
409 printf(" => "); 414 printf(" => ");
410 415
411 /* print branch_to information */ 416 /* print branch_to information */
412 if (PRINT_FIELD(ADDR)) 417 if (PRINT_FIELD(ADDR) ||
418 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
419 !output[attr->type].user_set))
413 print_sample_addr(event, sample, machine, thread, attr); 420 print_sample_addr(event, sample, machine, thread, attr);
414 421
415 printf("\n"); 422 printf("\n");
@@ -539,32 +546,51 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
539 return 0; 546 return 0;
540} 547}
541 548
542static struct perf_tool perf_script = { 549struct perf_script {
543 .sample = process_sample_event, 550 struct perf_tool tool;
544 .mmap = perf_event__process_mmap, 551 struct perf_session *session;
545 .mmap2 = perf_event__process_mmap2,
546 .comm = perf_event__process_comm,
547 .exit = perf_event__process_exit,
548 .fork = perf_event__process_fork,
549 .attr = perf_event__process_attr,
550 .tracing_data = perf_event__process_tracing_data,
551 .build_id = perf_event__process_build_id,
552 .ordered_samples = true,
553 .ordering_requires_timestamps = true,
554}; 552};
555 553
554static int process_attr(struct perf_tool *tool, union perf_event *event,
555 struct perf_evlist **pevlist)
556{
557 struct perf_script *scr = container_of(tool, struct perf_script, tool);
558 struct perf_evlist *evlist;
559 struct perf_evsel *evsel, *pos;
560 int err;
561
562 err = perf_event__process_attr(tool, event, pevlist);
563 if (err)
564 return err;
565
566 evlist = *pevlist;
567 evsel = perf_evlist__last(*pevlist);
568
569 if (evsel->attr.type >= PERF_TYPE_MAX)
570 return 0;
571
572 list_for_each_entry(pos, &evlist->entries, node) {
573 if (pos->attr.type == evsel->attr.type && pos != evsel)
574 return 0;
575 }
576
577 set_print_ip_opts(&evsel->attr);
578
579 return perf_evsel__check_attr(evsel, scr->session);
580}
581
556static void sig_handler(int sig __maybe_unused) 582static void sig_handler(int sig __maybe_unused)
557{ 583{
558 session_done = 1; 584 session_done = 1;
559} 585}
560 586
561static int __cmd_script(struct perf_session *session) 587static int __cmd_script(struct perf_script *script)
562{ 588{
563 int ret; 589 int ret;
564 590
565 signal(SIGINT, sig_handler); 591 signal(SIGINT, sig_handler);
566 592
567 ret = perf_session__process_events(session, &perf_script); 593 ret = perf_session__process_events(script->session, &script->tool);
568 594
569 if (debug_mode) 595 if (debug_mode)
570 pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); 596 pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
@@ -1113,10 +1139,14 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
1113 char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; 1139 char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN];
1114 DIR *scripts_dir, *lang_dir; 1140 DIR *scripts_dir, *lang_dir;
1115 struct perf_session *session; 1141 struct perf_session *session;
1142 struct perf_data_file file = {
1143 .path = input_name,
1144 .mode = PERF_DATA_MODE_READ,
1145 };
1116 char *temp; 1146 char *temp;
1117 int i = 0; 1147 int i = 0;
1118 1148
1119 session = perf_session__new(input_name, O_RDONLY, 0, false, NULL); 1149 session = perf_session__new(&file, false, NULL);
1120 if (!session) 1150 if (!session)
1121 return -1; 1151 return -1;
1122 1152
@@ -1266,6 +1296,21 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1266 char *script_path = NULL; 1296 char *script_path = NULL;
1267 const char **__argv; 1297 const char **__argv;
1268 int i, j, err; 1298 int i, j, err;
1299 struct perf_script script = {
1300 .tool = {
1301 .sample = process_sample_event,
1302 .mmap = perf_event__process_mmap,
1303 .mmap2 = perf_event__process_mmap2,
1304 .comm = perf_event__process_comm,
1305 .exit = perf_event__process_exit,
1306 .fork = perf_event__process_fork,
1307 .attr = process_attr,
1308 .tracing_data = perf_event__process_tracing_data,
1309 .build_id = perf_event__process_build_id,
1310 .ordered_samples = true,
1311 .ordering_requires_timestamps = true,
1312 },
1313 };
1269 const struct option options[] = { 1314 const struct option options[] = {
1270 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1315 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1271 "dump raw trace in ASCII"), 1316 "dump raw trace in ASCII"),
@@ -1317,12 +1362,17 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1317 "perf script [<options>] <top-script> [script-args]", 1362 "perf script [<options>] <top-script> [script-args]",
1318 NULL 1363 NULL
1319 }; 1364 };
1365 struct perf_data_file file = {
1366 .mode = PERF_DATA_MODE_READ,
1367 };
1320 1368
1321 setup_scripting(); 1369 setup_scripting();
1322 1370
1323 argc = parse_options(argc, argv, options, script_usage, 1371 argc = parse_options(argc, argv, options, script_usage,
1324 PARSE_OPT_STOP_AT_NON_OPTION); 1372 PARSE_OPT_STOP_AT_NON_OPTION);
1325 1373
1374 file.path = input_name;
1375
1326 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { 1376 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
1327 rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); 1377 rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
1328 if (!rec_script_path) 1378 if (!rec_script_path)
@@ -1486,11 +1536,12 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1486 if (!script_name) 1536 if (!script_name)
1487 setup_pager(); 1537 setup_pager();
1488 1538
1489 session = perf_session__new(input_name, O_RDONLY, 0, false, 1539 session = perf_session__new(&file, false, &script.tool);
1490 &perf_script);
1491 if (session == NULL) 1540 if (session == NULL)
1492 return -ENOMEM; 1541 return -ENOMEM;
1493 1542
1543 script.session = session;
1544
1494 if (cpu_list) { 1545 if (cpu_list) {
1495 if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) 1546 if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
1496 return -1; 1547 return -1;
@@ -1514,7 +1565,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1514 return -1; 1565 return -1;
1515 } 1566 }
1516 1567
1517 input = open(session->filename, O_RDONLY); /* input_name */ 1568 input = open(file.path, O_RDONLY); /* input_name */
1518 if (input < 0) { 1569 if (input < 0) {
1519 perror("failed to open file"); 1570 perror("failed to open file");
1520 return -1; 1571 return -1;
@@ -1554,7 +1605,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1554 if (err < 0) 1605 if (err < 0)
1555 goto out; 1606 goto out;
1556 1607
1557 err = __cmd_script(session); 1608 err = __cmd_script(&script);
1558 1609
1559 perf_session__delete(session); 1610 perf_session__delete(session);
1560 cleanup_scripting(); 1611 cleanup_scripting();
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 5098f144b92d..ee0d565f83e3 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -46,6 +46,7 @@
46#include "util/util.h" 46#include "util/util.h"
47#include "util/parse-options.h" 47#include "util/parse-options.h"
48#include "util/parse-events.h" 48#include "util/parse-events.h"
49#include "util/pmu.h"
49#include "util/event.h" 50#include "util/event.h"
50#include "util/evlist.h" 51#include "util/evlist.h"
51#include "util/evsel.h" 52#include "util/evsel.h"
@@ -70,9 +71,44 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
70static void print_counter(struct perf_evsel *counter, char *prefix); 71static void print_counter(struct perf_evsel *counter, char *prefix);
71static void print_aggr(char *prefix); 72static void print_aggr(char *prefix);
72 73
74/* Default events used for perf stat -T */
75static const char * const transaction_attrs[] = {
76 "task-clock",
77 "{"
78 "instructions,"
79 "cycles,"
80 "cpu/cycles-t/,"
81 "cpu/tx-start/,"
82 "cpu/el-start/,"
83 "cpu/cycles-ct/"
84 "}"
85};
86
87/* More limited version when the CPU does not have all events. */
88static const char * const transaction_limited_attrs[] = {
89 "task-clock",
90 "{"
91 "instructions,"
92 "cycles,"
93 "cpu/cycles-t/,"
94 "cpu/tx-start/"
95 "}"
96};
97
98/* must match transaction_attrs and the beginning limited_attrs */
99enum {
100 T_TASK_CLOCK,
101 T_INSTRUCTIONS,
102 T_CYCLES,
103 T_CYCLES_IN_TX,
104 T_TRANSACTION_START,
105 T_ELISION_START,
106 T_CYCLES_IN_TX_CP,
107};
108
73static struct perf_evlist *evsel_list; 109static struct perf_evlist *evsel_list;
74 110
75static struct perf_target target = { 111static struct target target = {
76 .uid = UINT_MAX, 112 .uid = UINT_MAX,
77}; 113};
78 114
@@ -90,6 +126,7 @@ static enum aggr_mode aggr_mode = AGGR_GLOBAL;
90static volatile pid_t child_pid = -1; 126static volatile pid_t child_pid = -1;
91static bool null_run = false; 127static bool null_run = false;
92static int detailed_run = 0; 128static int detailed_run = 0;
129static bool transaction_run;
93static bool big_num = true; 130static bool big_num = true;
94static int big_num_opt = -1; 131static int big_num_opt = -1;
95static const char *csv_sep = NULL; 132static const char *csv_sep = NULL;
@@ -214,7 +251,10 @@ static struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
214static struct stats runtime_ll_cache_stats[MAX_NR_CPUS]; 251static struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
215static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; 252static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
216static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 253static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
254static struct stats runtime_cycles_in_tx_stats[MAX_NR_CPUS];
217static struct stats walltime_nsecs_stats; 255static struct stats walltime_nsecs_stats;
256static struct stats runtime_transaction_stats[MAX_NR_CPUS];
257static struct stats runtime_elision_stats[MAX_NR_CPUS];
218 258
219static void perf_stat__reset_stats(struct perf_evlist *evlist) 259static void perf_stat__reset_stats(struct perf_evlist *evlist)
220{ 260{
@@ -236,6 +276,11 @@ static void perf_stat__reset_stats(struct perf_evlist *evlist)
236 memset(runtime_ll_cache_stats, 0, sizeof(runtime_ll_cache_stats)); 276 memset(runtime_ll_cache_stats, 0, sizeof(runtime_ll_cache_stats));
237 memset(runtime_itlb_cache_stats, 0, sizeof(runtime_itlb_cache_stats)); 277 memset(runtime_itlb_cache_stats, 0, sizeof(runtime_itlb_cache_stats));
238 memset(runtime_dtlb_cache_stats, 0, sizeof(runtime_dtlb_cache_stats)); 278 memset(runtime_dtlb_cache_stats, 0, sizeof(runtime_dtlb_cache_stats));
279 memset(runtime_cycles_in_tx_stats, 0,
280 sizeof(runtime_cycles_in_tx_stats));
281 memset(runtime_transaction_stats, 0,
282 sizeof(runtime_transaction_stats));
283 memset(runtime_elision_stats, 0, sizeof(runtime_elision_stats));
239 memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats)); 284 memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats));
240} 285}
241 286
@@ -249,11 +294,10 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
249 294
250 attr->inherit = !no_inherit; 295 attr->inherit = !no_inherit;
251 296
252 if (perf_target__has_cpu(&target)) 297 if (target__has_cpu(&target))
253 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); 298 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
254 299
255 if (!perf_target__has_task(&target) && 300 if (!target__has_task(&target) && perf_evsel__is_group_leader(evsel)) {
256 perf_evsel__is_group_leader(evsel)) {
257 attr->disabled = 1; 301 attr->disabled = 1;
258 if (!initial_delay) 302 if (!initial_delay)
259 attr->enable_on_exec = 1; 303 attr->enable_on_exec = 1;
@@ -274,6 +318,29 @@ static inline int nsec_counter(struct perf_evsel *evsel)
274 return 0; 318 return 0;
275} 319}
276 320
321static struct perf_evsel *nth_evsel(int n)
322{
323 static struct perf_evsel **array;
324 static int array_len;
325 struct perf_evsel *ev;
326 int j;
327
328 /* Assumes this only called when evsel_list does not change anymore. */
329 if (!array) {
330 list_for_each_entry(ev, &evsel_list->entries, node)
331 array_len++;
332 array = malloc(array_len * sizeof(void *));
333 if (!array)
334 exit(ENOMEM);
335 j = 0;
336 list_for_each_entry(ev, &evsel_list->entries, node)
337 array[j++] = ev;
338 }
339 if (n < array_len)
340 return array[n];
341 return NULL;
342}
343
277/* 344/*
278 * Update various tracking values we maintain to print 345 * Update various tracking values we maintain to print
279 * more semantic information such as miss/hit ratios, 346 * more semantic information such as miss/hit ratios,
@@ -285,6 +352,15 @@ static void update_shadow_stats(struct perf_evsel *counter, u64 *count)
285 update_stats(&runtime_nsecs_stats[0], count[0]); 352 update_stats(&runtime_nsecs_stats[0], count[0]);
286 else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) 353 else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
287 update_stats(&runtime_cycles_stats[0], count[0]); 354 update_stats(&runtime_cycles_stats[0], count[0]);
355 else if (transaction_run &&
356 perf_evsel__cmp(counter, nth_evsel(T_CYCLES_IN_TX)))
357 update_stats(&runtime_cycles_in_tx_stats[0], count[0]);
358 else if (transaction_run &&
359 perf_evsel__cmp(counter, nth_evsel(T_TRANSACTION_START)))
360 update_stats(&runtime_transaction_stats[0], count[0]);
361 else if (transaction_run &&
362 perf_evsel__cmp(counter, nth_evsel(T_ELISION_START)))
363 update_stats(&runtime_elision_stats[0], count[0]);
288 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) 364 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
289 update_stats(&runtime_stalled_cycles_front_stats[0], count[0]); 365 update_stats(&runtime_stalled_cycles_front_stats[0], count[0]);
290 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND)) 366 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND))
@@ -629,10 +705,13 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
629{ 705{
630 double msecs = avg / 1e6; 706 double msecs = avg / 1e6;
631 const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s"; 707 const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s";
708 char name[25];
632 709
633 aggr_printout(evsel, cpu, nr); 710 aggr_printout(evsel, cpu, nr);
634 711
635 fprintf(output, fmt, msecs, csv_sep, perf_evsel__name(evsel)); 712 scnprintf(name, sizeof(name), "%s%s",
713 perf_evsel__name(evsel), csv_output ? "" : " (msec)");
714 fprintf(output, fmt, msecs, csv_sep, name);
636 715
637 if (evsel->cgrp) 716 if (evsel->cgrp)
638 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 717 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -828,7 +907,7 @@ static void print_ll_cache_misses(int cpu,
828 907
829static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 908static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
830{ 909{
831 double total, ratio = 0.0; 910 double total, ratio = 0.0, total2;
832 const char *fmt; 911 const char *fmt;
833 912
834 if (csv_output) 913 if (csv_output)
@@ -853,11 +932,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
853 932
854 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { 933 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
855 total = avg_stats(&runtime_cycles_stats[cpu]); 934 total = avg_stats(&runtime_cycles_stats[cpu]);
856 if (total) 935 if (total) {
857 ratio = avg / total; 936 ratio = avg / total;
858 937 fprintf(output, " # %5.2f insns per cycle ", ratio);
859 fprintf(output, " # %5.2f insns per cycle ", ratio); 938 }
860
861 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); 939 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
862 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); 940 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
863 941
@@ -920,10 +998,47 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
920 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { 998 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
921 total = avg_stats(&runtime_nsecs_stats[cpu]); 999 total = avg_stats(&runtime_nsecs_stats[cpu]);
922 1000
1001 if (total) {
1002 ratio = avg / total;
1003 fprintf(output, " # %8.3f GHz ", ratio);
1004 }
1005 } else if (transaction_run &&
1006 perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX))) {
1007 total = avg_stats(&runtime_cycles_stats[cpu]);
1008 if (total)
1009 fprintf(output,
1010 " # %5.2f%% transactional cycles ",
1011 100.0 * (avg / total));
1012 } else if (transaction_run &&
1013 perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX_CP))) {
1014 total = avg_stats(&runtime_cycles_stats[cpu]);
1015 total2 = avg_stats(&runtime_cycles_in_tx_stats[cpu]);
1016 if (total2 < avg)
1017 total2 = avg;
1018 if (total)
1019 fprintf(output,
1020 " # %5.2f%% aborted cycles ",
1021 100.0 * ((total2-avg) / total));
1022 } else if (transaction_run &&
1023 perf_evsel__cmp(evsel, nth_evsel(T_TRANSACTION_START)) &&
1024 avg > 0 &&
1025 runtime_cycles_in_tx_stats[cpu].n != 0) {
1026 total = avg_stats(&runtime_cycles_in_tx_stats[cpu]);
1027
923 if (total) 1028 if (total)
924 ratio = 1.0 * avg / total; 1029 ratio = total / avg;
925 1030
926 fprintf(output, " # %8.3f GHz ", ratio); 1031 fprintf(output, " # %8.0f cycles / transaction ", ratio);
1032 } else if (transaction_run &&
1033 perf_evsel__cmp(evsel, nth_evsel(T_ELISION_START)) &&
1034 avg > 0 &&
1035 runtime_cycles_in_tx_stats[cpu].n != 0) {
1036 total = avg_stats(&runtime_cycles_in_tx_stats[cpu]);
1037
1038 if (total)
1039 ratio = total / avg;
1040
1041 fprintf(output, " # %8.0f cycles / elision ", ratio);
927 } else if (runtime_nsecs_stats[cpu].n != 0) { 1042 } else if (runtime_nsecs_stats[cpu].n != 0) {
928 char unit = 'M'; 1043 char unit = 'M';
929 1044
@@ -1116,7 +1231,11 @@ static void print_stat(int argc, const char **argv)
1116 if (!csv_output) { 1231 if (!csv_output) {
1117 fprintf(output, "\n"); 1232 fprintf(output, "\n");
1118 fprintf(output, " Performance counter stats for "); 1233 fprintf(output, " Performance counter stats for ");
1119 if (!perf_target__has_task(&target)) { 1234 if (target.system_wide)
1235 fprintf(output, "\'system wide");
1236 else if (target.cpu_list)
1237 fprintf(output, "\'CPU(s) %s", target.cpu_list);
1238 else if (!target__has_task(&target)) {
1120 fprintf(output, "\'%s", argv[0]); 1239 fprintf(output, "\'%s", argv[0]);
1121 for (i = 1; i < argc; i++) 1240 for (i = 1; i < argc; i++)
1122 fprintf(output, " %s", argv[i]); 1241 fprintf(output, " %s", argv[i]);
@@ -1237,6 +1356,16 @@ static int perf_stat_init_aggr_mode(void)
1237 return 0; 1356 return 0;
1238} 1357}
1239 1358
1359static int setup_events(const char * const *attrs, unsigned len)
1360{
1361 unsigned i;
1362
1363 for (i = 0; i < len; i++) {
1364 if (parse_events(evsel_list, attrs[i]))
1365 return -1;
1366 }
1367 return 0;
1368}
1240 1369
1241/* 1370/*
1242 * Add default attributes, if there were no attributes specified or 1371 * Add default attributes, if there were no attributes specified or
@@ -1355,6 +1484,22 @@ static int add_default_attributes(void)
1355 if (null_run) 1484 if (null_run)
1356 return 0; 1485 return 0;
1357 1486
1487 if (transaction_run) {
1488 int err;
1489 if (pmu_have_event("cpu", "cycles-ct") &&
1490 pmu_have_event("cpu", "el-start"))
1491 err = setup_events(transaction_attrs,
1492 ARRAY_SIZE(transaction_attrs));
1493 else
1494 err = setup_events(transaction_limited_attrs,
1495 ARRAY_SIZE(transaction_limited_attrs));
1496 if (err < 0) {
1497 fprintf(stderr, "Cannot set up transaction events\n");
1498 return -1;
1499 }
1500 return 0;
1501 }
1502
1358 if (!evsel_list->nr_entries) { 1503 if (!evsel_list->nr_entries) {
1359 if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0) 1504 if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0)
1360 return -1; 1505 return -1;
@@ -1389,6 +1534,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1389 int output_fd = 0; 1534 int output_fd = 0;
1390 const char *output_name = NULL; 1535 const char *output_name = NULL;
1391 const struct option options[] = { 1536 const struct option options[] = {
1537 OPT_BOOLEAN('T', "transaction", &transaction_run,
1538 "hardware transaction statistics"),
1392 OPT_CALLBACK('e', "event", &evsel_list, "event", 1539 OPT_CALLBACK('e', "event", &evsel_list, "event",
1393 "event selector. use 'perf list' to list available events", 1540 "event selector. use 'perf list' to list available events",
1394 parse_events_option), 1541 parse_events_option),
@@ -1448,7 +1595,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1448 "perf stat [<options>] [<command>]", 1595 "perf stat [<options>] [<command>]",
1449 NULL 1596 NULL
1450 }; 1597 };
1451 int status = -ENOMEM, run_idx; 1598 int status = -EINVAL, run_idx;
1452 const char *mode; 1599 const char *mode;
1453 1600
1454 setlocale(LC_ALL, ""); 1601 setlocale(LC_ALL, "");
@@ -1466,12 +1613,15 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1466 1613
1467 if (output_name && output_fd) { 1614 if (output_name && output_fd) {
1468 fprintf(stderr, "cannot use both --output and --log-fd\n"); 1615 fprintf(stderr, "cannot use both --output and --log-fd\n");
1469 usage_with_options(stat_usage, options); 1616 parse_options_usage(stat_usage, options, "o", 1);
1617 parse_options_usage(NULL, options, "log-fd", 0);
1618 goto out;
1470 } 1619 }
1471 1620
1472 if (output_fd < 0) { 1621 if (output_fd < 0) {
1473 fprintf(stderr, "argument to --log-fd must be a > 0\n"); 1622 fprintf(stderr, "argument to --log-fd must be a > 0\n");
1474 usage_with_options(stat_usage, options); 1623 parse_options_usage(stat_usage, options, "log-fd", 0);
1624 goto out;
1475 } 1625 }
1476 1626
1477 if (!output) { 1627 if (!output) {
@@ -1508,56 +1658,66 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1508 /* User explicitly passed -B? */ 1658 /* User explicitly passed -B? */
1509 if (big_num_opt == 1) { 1659 if (big_num_opt == 1) {
1510 fprintf(stderr, "-B option not supported with -x\n"); 1660 fprintf(stderr, "-B option not supported with -x\n");
1511 usage_with_options(stat_usage, options); 1661 parse_options_usage(stat_usage, options, "B", 1);
1662 parse_options_usage(NULL, options, "x", 1);
1663 goto out;
1512 } else /* Nope, so disable big number formatting */ 1664 } else /* Nope, so disable big number formatting */
1513 big_num = false; 1665 big_num = false;
1514 } else if (big_num_opt == 0) /* User passed --no-big-num */ 1666 } else if (big_num_opt == 0) /* User passed --no-big-num */
1515 big_num = false; 1667 big_num = false;
1516 1668
1517 if (!argc && !perf_target__has_task(&target)) 1669 if (!argc && target__none(&target))
1518 usage_with_options(stat_usage, options); 1670 usage_with_options(stat_usage, options);
1671
1519 if (run_count < 0) { 1672 if (run_count < 0) {
1520 usage_with_options(stat_usage, options); 1673 pr_err("Run count must be a positive number\n");
1674 parse_options_usage(stat_usage, options, "r", 1);
1675 goto out;
1521 } else if (run_count == 0) { 1676 } else if (run_count == 0) {
1522 forever = true; 1677 forever = true;
1523 run_count = 1; 1678 run_count = 1;
1524 } 1679 }
1525 1680
1526 /* no_aggr, cgroup are for system-wide only */ 1681 /* no_aggr, cgroup are for system-wide only */
1527 if ((aggr_mode != AGGR_GLOBAL || nr_cgroups) 1682 if ((aggr_mode != AGGR_GLOBAL || nr_cgroups) &&
1528 && !perf_target__has_cpu(&target)) { 1683 !target__has_cpu(&target)) {
1529 fprintf(stderr, "both cgroup and no-aggregation " 1684 fprintf(stderr, "both cgroup and no-aggregation "
1530 "modes only available in system-wide mode\n"); 1685 "modes only available in system-wide mode\n");
1531 1686
1532 usage_with_options(stat_usage, options); 1687 parse_options_usage(stat_usage, options, "G", 1);
1533 return -1; 1688 parse_options_usage(NULL, options, "A", 1);
1689 parse_options_usage(NULL, options, "a", 1);
1690 goto out;
1534 } 1691 }
1535 1692
1536 if (add_default_attributes()) 1693 if (add_default_attributes())
1537 goto out; 1694 goto out;
1538 1695
1539 perf_target__validate(&target); 1696 target__validate(&target);
1540 1697
1541 if (perf_evlist__create_maps(evsel_list, &target) < 0) { 1698 if (perf_evlist__create_maps(evsel_list, &target) < 0) {
1542 if (perf_target__has_task(&target)) 1699 if (target__has_task(&target)) {
1543 pr_err("Problems finding threads of monitor\n"); 1700 pr_err("Problems finding threads of monitor\n");
1544 if (perf_target__has_cpu(&target)) 1701 parse_options_usage(stat_usage, options, "p", 1);
1702 parse_options_usage(NULL, options, "t", 1);
1703 } else if (target__has_cpu(&target)) {
1545 perror("failed to parse CPUs map"); 1704 perror("failed to parse CPUs map");
1546 1705 parse_options_usage(stat_usage, options, "C", 1);
1547 usage_with_options(stat_usage, options); 1706 parse_options_usage(NULL, options, "a", 1);
1548 return -1; 1707 }
1708 goto out;
1549 } 1709 }
1550 if (interval && interval < 100) { 1710 if (interval && interval < 100) {
1551 pr_err("print interval must be >= 100ms\n"); 1711 pr_err("print interval must be >= 100ms\n");
1552 usage_with_options(stat_usage, options); 1712 parse_options_usage(stat_usage, options, "I", 1);
1553 return -1; 1713 goto out_free_maps;
1554 } 1714 }
1555 1715
1556 if (perf_evlist__alloc_stats(evsel_list, interval)) 1716 if (perf_evlist__alloc_stats(evsel_list, interval))
1557 goto out_free_maps; 1717 goto out_free_maps;
1558 1718
1559 if (perf_stat_init_aggr_mode()) 1719 if (perf_stat_init_aggr_mode())
1560 goto out; 1720 goto out_free_maps;
1561 1721
1562 /* 1722 /*
1563 * We dont want to block the signals - that would cause 1723 * We dont want to block the signals - that would cause
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index c2e02319347a..41c9bde2fb67 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -36,6 +36,7 @@
36#include "util/session.h" 36#include "util/session.h"
37#include "util/svghelper.h" 37#include "util/svghelper.h"
38#include "util/tool.h" 38#include "util/tool.h"
39#include "util/data.h"
39 40
40#define SUPPORT_OLD_POWER_EVENTS 1 41#define SUPPORT_OLD_POWER_EVENTS 1
41#define PWR_EVENT_EXIT -1 42#define PWR_EVENT_EXIT -1
@@ -482,8 +483,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
482 if (sample->cpu > numcpus) 483 if (sample->cpu > numcpus)
483 numcpus = sample->cpu; 484 numcpus = sample->cpu;
484 485
485 if (evsel->handler.func != NULL) { 486 if (evsel->handler != NULL) {
486 tracepoint_handler f = evsel->handler.func; 487 tracepoint_handler f = evsel->handler;
487 return f(evsel, sample); 488 return f(evsel, sample);
488 } 489 }
489 490
@@ -990,8 +991,13 @@ static int __cmd_timechart(const char *output_name)
990 { "power:power_frequency", process_sample_power_frequency }, 991 { "power:power_frequency", process_sample_power_frequency },
991#endif 992#endif
992 }; 993 };
993 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 994 struct perf_data_file file = {
994 0, false, &perf_timechart); 995 .path = input_name,
996 .mode = PERF_DATA_MODE_READ,
997 };
998
999 struct perf_session *session = perf_session__new(&file, false,
1000 &perf_timechart);
995 int ret = -EINVAL; 1001 int ret = -EINVAL;
996 1002
997 if (session == NULL) 1003 if (session == NULL)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 212214162bb2..71e6402729a8 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -246,10 +246,10 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
246 struct hist_entry *he; 246 struct hist_entry *he;
247 247
248 pthread_mutex_lock(&evsel->hists.lock); 248 pthread_mutex_lock(&evsel->hists.lock);
249 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period, 249 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL,
250 sample->weight); 250 sample->period, sample->weight,
251 sample->transaction);
251 pthread_mutex_unlock(&evsel->hists.lock); 252 pthread_mutex_unlock(&evsel->hists.lock);
252
253 if (he == NULL) 253 if (he == NULL)
254 return NULL; 254 return NULL;
255 255
@@ -287,7 +287,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
287 return; 287 return;
288 } 288 }
289 289
290 hists__collapse_resort(&top->sym_evsel->hists); 290 hists__collapse_resort(&top->sym_evsel->hists, NULL);
291 hists__output_resort(&top->sym_evsel->hists); 291 hists__output_resort(&top->sym_evsel->hists);
292 hists__decay_entries(&top->sym_evsel->hists, 292 hists__decay_entries(&top->sym_evsel->hists,
293 top->hide_user_symbols, 293 top->hide_user_symbols,
@@ -553,7 +553,7 @@ static void perf_top__sort_new_samples(void *arg)
553 if (t->evlist->selected != NULL) 553 if (t->evlist->selected != NULL)
554 t->sym_evsel = t->evlist->selected; 554 t->sym_evsel = t->evlist->selected;
555 555
556 hists__collapse_resort(&t->sym_evsel->hists); 556 hists__collapse_resort(&t->sym_evsel->hists, NULL);
557 hists__output_resort(&t->sym_evsel->hists); 557 hists__output_resort(&t->sym_evsel->hists);
558 hists__decay_entries(&t->sym_evsel->hists, 558 hists__decay_entries(&t->sym_evsel->hists,
559 t->hide_user_symbols, 559 t->hide_user_symbols,
@@ -771,7 +771,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
771 sample->callchain) { 771 sample->callchain) {
772 err = machine__resolve_callchain(machine, evsel, 772 err = machine__resolve_callchain(machine, evsel,
773 al.thread, sample, 773 al.thread, sample,
774 &parent, &al); 774 &parent, &al,
775 top->max_stack);
775 if (err) 776 if (err)
776 return; 777 return;
777 } 778 }
@@ -810,7 +811,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
810 ret = perf_evlist__parse_sample(top->evlist, event, &sample); 811 ret = perf_evlist__parse_sample(top->evlist, event, &sample);
811 if (ret) { 812 if (ret) {
812 pr_err("Can't parse sample, err = %d\n", ret); 813 pr_err("Can't parse sample, err = %d\n", ret);
813 continue; 814 goto next_event;
814 } 815 }
815 816
816 evsel = perf_evlist__id2evsel(session->evlist, sample.id); 817 evsel = perf_evlist__id2evsel(session->evlist, sample.id);
@@ -825,13 +826,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
825 case PERF_RECORD_MISC_USER: 826 case PERF_RECORD_MISC_USER:
826 ++top->us_samples; 827 ++top->us_samples;
827 if (top->hide_user_symbols) 828 if (top->hide_user_symbols)
828 continue; 829 goto next_event;
829 machine = &session->machines.host; 830 machine = &session->machines.host;
830 break; 831 break;
831 case PERF_RECORD_MISC_KERNEL: 832 case PERF_RECORD_MISC_KERNEL:
832 ++top->kernel_samples; 833 ++top->kernel_samples;
833 if (top->hide_kernel_symbols) 834 if (top->hide_kernel_symbols)
834 continue; 835 goto next_event;
835 machine = &session->machines.host; 836 machine = &session->machines.host;
836 break; 837 break;
837 case PERF_RECORD_MISC_GUEST_KERNEL: 838 case PERF_RECORD_MISC_GUEST_KERNEL:
@@ -847,7 +848,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
847 */ 848 */
848 /* Fall thru */ 849 /* Fall thru */
849 default: 850 default:
850 continue; 851 goto next_event;
851 } 852 }
852 853
853 854
@@ -856,9 +857,11 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
856 &sample, machine); 857 &sample, machine);
857 } else if (event->header.type < PERF_RECORD_MAX) { 858 } else if (event->header.type < PERF_RECORD_MAX) {
858 hists__inc_nr_events(&evsel->hists, event->header.type); 859 hists__inc_nr_events(&evsel->hists, event->header.type);
859 machine__process_event(machine, event); 860 machine__process_event(machine, event, &sample);
860 } else 861 } else
861 ++session->stats.nr_unknown_events; 862 ++session->stats.nr_unknown_events;
863next_event:
864 perf_evlist__mmap_consume(top->evlist, idx);
862 } 865 }
863} 866}
864 867
@@ -930,11 +933,8 @@ static int __cmd_top(struct perf_top *top)
930 struct perf_record_opts *opts = &top->record_opts; 933 struct perf_record_opts *opts = &top->record_opts;
931 pthread_t thread; 934 pthread_t thread;
932 int ret; 935 int ret;
933 /* 936
934 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 937 top->session = perf_session__new(NULL, false, NULL);
935 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
936 */
937 top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
938 if (top->session == NULL) 938 if (top->session == NULL)
939 return -ENOMEM; 939 return -ENOMEM;
940 940
@@ -950,14 +950,8 @@ static int __cmd_top(struct perf_top *top)
950 if (ret) 950 if (ret)
951 goto out_delete; 951 goto out_delete;
952 952
953 if (perf_target__has_task(&opts->target)) 953 machine__synthesize_threads(&top->session->machines.host, &opts->target,
954 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, 954 top->evlist->threads, false);
955 perf_event__process,
956 &top->session->machines.host);
957 else
958 perf_event__synthesize_threads(&top->tool, perf_event__process,
959 &top->session->machines.host);
960
961 ret = perf_top__start_counters(top); 955 ret = perf_top__start_counters(top);
962 if (ret) 956 if (ret)
963 goto out_delete; 957 goto out_delete;
@@ -973,7 +967,7 @@ static int __cmd_top(struct perf_top *top)
973 * XXX 'top' still doesn't start workloads like record, trace, but should, 967 * XXX 'top' still doesn't start workloads like record, trace, but should,
974 * so leave the check here. 968 * so leave the check here.
975 */ 969 */
976 if (!perf_target__none(&opts->target)) 970 if (!target__none(&opts->target))
977 perf_evlist__enable(top->evlist); 971 perf_evlist__enable(top->evlist);
978 972
979 /* Wait for a minimal set of events before starting the snapshot */ 973 /* Wait for a minimal set of events before starting the snapshot */
@@ -1016,16 +1010,16 @@ out_delete:
1016} 1010}
1017 1011
1018static int 1012static int
1019parse_callchain_opt(const struct option *opt, const char *arg, int unset) 1013callchain_opt(const struct option *opt, const char *arg, int unset)
1020{ 1014{
1021 /*
1022 * --no-call-graph
1023 */
1024 if (unset)
1025 return 0;
1026
1027 symbol_conf.use_callchain = true; 1015 symbol_conf.use_callchain = true;
1016 return record_callchain_opt(opt, arg, unset);
1017}
1028 1018
1019static int
1020parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1021{
1022 symbol_conf.use_callchain = true;
1029 return record_parse_callchain_opt(opt, arg, unset); 1023 return record_parse_callchain_opt(opt, arg, unset);
1030} 1024}
1031 1025
@@ -1041,7 +1035,7 @@ parse_percent_limit(const struct option *opt, const char *arg,
1041 1035
1042int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) 1036int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1043{ 1037{
1044 int status; 1038 int status = -1;
1045 char errbuf[BUFSIZ]; 1039 char errbuf[BUFSIZ];
1046 struct perf_top top = { 1040 struct perf_top top = {
1047 .count_filter = 5, 1041 .count_filter = 5,
@@ -1051,14 +1045,15 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1051 .user_freq = UINT_MAX, 1045 .user_freq = UINT_MAX,
1052 .user_interval = ULLONG_MAX, 1046 .user_interval = ULLONG_MAX,
1053 .freq = 4000, /* 4 KHz */ 1047 .freq = 4000, /* 4 KHz */
1054 .target = { 1048 .target = {
1055 .uses_mmap = true, 1049 .uses_mmap = true,
1056 }, 1050 },
1057 }, 1051 },
1052 .max_stack = PERF_MAX_STACK_DEPTH,
1058 .sym_pcnt_filter = 5, 1053 .sym_pcnt_filter = 5,
1059 }; 1054 };
1060 struct perf_record_opts *opts = &top.record_opts; 1055 struct perf_record_opts *opts = &top.record_opts;
1061 struct perf_target *target = &opts->target; 1056 struct target *target = &opts->target;
1062 const struct option options[] = { 1057 const struct option options[] = {
1063 OPT_CALLBACK('e', "event", &top.evlist, "event", 1058 OPT_CALLBACK('e', "event", &top.evlist, "event",
1064 "event selector. use 'perf list' to list available events", 1059 "event selector. use 'perf list' to list available events",
@@ -1074,10 +1069,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1074 "list of cpus to monitor"), 1069 "list of cpus to monitor"),
1075 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1070 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1076 "file", "vmlinux pathname"), 1071 "file", "vmlinux pathname"),
1072 OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux,
1073 "don't load vmlinux even if found"),
1077 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, 1074 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1078 "hide kernel symbols"), 1075 "hide kernel symbols"),
1079 OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages, 1076 OPT_CALLBACK('m', "mmap-pages", &opts->mmap_pages, "pages",
1080 "number of mmap data pages"), 1077 "number of mmap data pages",
1078 perf_evlist__parse_mmap_pages),
1081 OPT_INTEGER('r', "realtime", &top.realtime_prio, 1079 OPT_INTEGER('r', "realtime", &top.realtime_prio,
1082 "collect data with this RT SCHED_FIFO priority"), 1080 "collect data with this RT SCHED_FIFO priority"),
1083 OPT_INTEGER('d', "delay", &top.delay_secs, 1081 OPT_INTEGER('d', "delay", &top.delay_secs,
@@ -1103,12 +1101,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1103 OPT_INCR('v', "verbose", &verbose, 1101 OPT_INCR('v', "verbose", &verbose,
1104 "be more verbose (show counter open errors, etc)"), 1102 "be more verbose (show counter open errors, etc)"),
1105 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1103 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1106 "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"), 1104 "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight,"
1105 " abort, in_tx, transaction"),
1107 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1106 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1108 "Show a column with the number of samples"), 1107 "Show a column with the number of samples"),
1109 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, 1108 OPT_CALLBACK_NOOPT('G', NULL, &top.record_opts,
1110 "mode[,dump_size]", record_callchain_help, 1109 NULL, "enables call-graph recording",
1111 &parse_callchain_opt, "fp"), 1110 &callchain_opt),
1111 OPT_CALLBACK(0, "call-graph", &top.record_opts,
1112 "mode[,dump_size]", record_callchain_help,
1113 &parse_callchain_opt),
1114 OPT_INTEGER(0, "max-stack", &top.max_stack,
1115 "Set the maximum stack depth when parsing the callchain. "
1116 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
1112 OPT_CALLBACK(0, "ignore-callees", NULL, "regex", 1117 OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
1113 "ignore callees of these functions in call graphs", 1118 "ignore callees of these functions in call graphs",
1114 report_parse_ignore_callees_opt), 1119 report_parse_ignore_callees_opt),
@@ -1149,8 +1154,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1149 if (sort_order == default_sort_order) 1154 if (sort_order == default_sort_order)
1150 sort_order = "dso,symbol"; 1155 sort_order = "dso,symbol";
1151 1156
1152 if (setup_sorting() < 0) 1157 if (setup_sorting() < 0) {
1153 usage_with_options(top_usage, options); 1158 parse_options_usage(top_usage, options, "s", 1);
1159 goto out_delete_evlist;
1160 }
1154 1161
1155 /* display thread wants entries to be collapsed in a different tree */ 1162 /* display thread wants entries to be collapsed in a different tree */
1156 sort__need_collapse = 1; 1163 sort__need_collapse = 1;
@@ -1162,24 +1169,24 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1162 1169
1163 setup_browser(false); 1170 setup_browser(false);
1164 1171
1165 status = perf_target__validate(target); 1172 status = target__validate(target);
1166 if (status) { 1173 if (status) {
1167 perf_target__strerror(target, status, errbuf, BUFSIZ); 1174 target__strerror(target, status, errbuf, BUFSIZ);
1168 ui__warning("%s", errbuf); 1175 ui__warning("%s\n", errbuf);
1169 } 1176 }
1170 1177
1171 status = perf_target__parse_uid(target); 1178 status = target__parse_uid(target);
1172 if (status) { 1179 if (status) {
1173 int saved_errno = errno; 1180 int saved_errno = errno;
1174 1181
1175 perf_target__strerror(target, status, errbuf, BUFSIZ); 1182 target__strerror(target, status, errbuf, BUFSIZ);
1176 ui__error("%s", errbuf); 1183 ui__error("%s\n", errbuf);
1177 1184
1178 status = -saved_errno; 1185 status = -saved_errno;
1179 goto out_delete_evlist; 1186 goto out_delete_evlist;
1180 } 1187 }
1181 1188
1182 if (perf_target__none(target)) 1189 if (target__none(target))
1183 target->system_wide = true; 1190 target->system_wide = true;
1184 1191
1185 if (perf_evlist__create_maps(top.evlist, target) < 0) 1192 if (perf_evlist__create_maps(top.evlist, target) < 0)
@@ -1196,20 +1203,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1196 if (top.delay_secs < 1) 1203 if (top.delay_secs < 1)
1197 top.delay_secs = 1; 1204 top.delay_secs = 1;
1198 1205
1199 if (opts->user_interval != ULLONG_MAX) 1206 if (perf_record_opts__config(opts)) {
1200 opts->default_interval = opts->user_interval;
1201 if (opts->user_freq != UINT_MAX)
1202 opts->freq = opts->user_freq;
1203
1204 /*
1205 * User specified count overrides default frequency.
1206 */
1207 if (opts->default_interval)
1208 opts->freq = 0;
1209 else if (opts->freq) {
1210 opts->default_interval = opts->freq;
1211 } else {
1212 ui__error("frequency and count are zero, aborting\n");
1213 status = -EINVAL; 1207 status = -EINVAL;
1214 goto out_delete_maps; 1208 goto out_delete_maps;
1215 } 1209 }
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 71aa3e35406b..8be17fc462ba 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -10,9 +10,11 @@
10#include "util/strlist.h" 10#include "util/strlist.h"
11#include "util/intlist.h" 11#include "util/intlist.h"
12#include "util/thread_map.h" 12#include "util/thread_map.h"
13#include "util/stat.h"
13 14
14#include <libaudit.h> 15#include <libaudit.h>
15#include <stdlib.h> 16#include <stdlib.h>
17#include <sys/eventfd.h>
16#include <sys/mman.h> 18#include <sys/mman.h>
17#include <linux/futex.h> 19#include <linux/futex.h>
18 20
@@ -33,49 +35,289 @@
33# define MADV_UNMERGEABLE 13 35# define MADV_UNMERGEABLE 13
34#endif 36#endif
35 37
36static size_t syscall_arg__scnprintf_hex(char *bf, size_t size, 38struct tp_field {
37 unsigned long arg, 39 int offset;
38 u8 arg_idx __maybe_unused, 40 union {
39 u8 *arg_mask __maybe_unused) 41 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
42 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
43 };
44};
45
46#define TP_UINT_FIELD(bits) \
47static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
48{ \
49 return *(u##bits *)(sample->raw_data + field->offset); \
50}
51
52TP_UINT_FIELD(8);
53TP_UINT_FIELD(16);
54TP_UINT_FIELD(32);
55TP_UINT_FIELD(64);
56
57#define TP_UINT_FIELD__SWAPPED(bits) \
58static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
59{ \
60 u##bits value = *(u##bits *)(sample->raw_data + field->offset); \
61 return bswap_##bits(value);\
62}
63
64TP_UINT_FIELD__SWAPPED(16);
65TP_UINT_FIELD__SWAPPED(32);
66TP_UINT_FIELD__SWAPPED(64);
67
68static int tp_field__init_uint(struct tp_field *field,
69 struct format_field *format_field,
70 bool needs_swap)
40{ 71{
41 return scnprintf(bf, size, "%#lx", arg); 72 field->offset = format_field->offset;
73
74 switch (format_field->size) {
75 case 1:
76 field->integer = tp_field__u8;
77 break;
78 case 2:
79 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
80 break;
81 case 4:
82 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
83 break;
84 case 8:
85 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
86 break;
87 default:
88 return -1;
89 }
90
91 return 0;
42} 92}
43 93
44#define SCA_HEX syscall_arg__scnprintf_hex 94static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
95{
96 return sample->raw_data + field->offset;
97}
45 98
46static size_t syscall_arg__scnprintf_whence(char *bf, size_t size, 99static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
47 unsigned long arg,
48 u8 arg_idx __maybe_unused,
49 u8 *arg_mask __maybe_unused)
50{ 100{
51 int whence = arg; 101 field->offset = format_field->offset;
102 field->pointer = tp_field__ptr;
103 return 0;
104}
52 105
53 switch (whence) { 106struct syscall_tp {
54#define P_WHENCE(n) case SEEK_##n: return scnprintf(bf, size, #n) 107 struct tp_field id;
55 P_WHENCE(SET); 108 union {
56 P_WHENCE(CUR); 109 struct tp_field args, ret;
57 P_WHENCE(END); 110 };
58#ifdef SEEK_DATA 111};
59 P_WHENCE(DATA); 112
60#endif 113static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
61#ifdef SEEK_HOLE 114 struct tp_field *field,
62 P_WHENCE(HOLE); 115 const char *name)
63#endif 116{
64#undef P_WHENCE 117 struct format_field *format_field = perf_evsel__field(evsel, name);
65 default: break; 118
119 if (format_field == NULL)
120 return -1;
121
122 return tp_field__init_uint(field, format_field, evsel->needs_swap);
123}
124
125#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
126 ({ struct syscall_tp *sc = evsel->priv;\
127 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
128
129static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
130 struct tp_field *field,
131 const char *name)
132{
133 struct format_field *format_field = perf_evsel__field(evsel, name);
134
135 if (format_field == NULL)
136 return -1;
137
138 return tp_field__init_ptr(field, format_field);
139}
140
141#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
142 ({ struct syscall_tp *sc = evsel->priv;\
143 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
144
145static void perf_evsel__delete_priv(struct perf_evsel *evsel)
146{
147 free(evsel->priv);
148 evsel->priv = NULL;
149 perf_evsel__delete(evsel);
150}
151
152static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
153{
154 evsel->priv = malloc(sizeof(struct syscall_tp));
155 if (evsel->priv != NULL) {
156 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
157 goto out_delete;
158
159 evsel->handler = handler;
160 return 0;
66 } 161 }
67 162
68 return scnprintf(bf, size, "%#x", whence); 163 return -ENOMEM;
164
165out_delete:
166 free(evsel->priv);
167 evsel->priv = NULL;
168 return -ENOENT;
169}
170
171static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
172{
173 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
174
175 if (evsel) {
176 if (perf_evsel__init_syscall_tp(evsel, handler))
177 goto out_delete;
178 }
179
180 return evsel;
181
182out_delete:
183 perf_evsel__delete_priv(evsel);
184 return NULL;
185}
186
187#define perf_evsel__sc_tp_uint(evsel, name, sample) \
188 ({ struct syscall_tp *fields = evsel->priv; \
189 fields->name.integer(&fields->name, sample); })
190
191#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
192 ({ struct syscall_tp *fields = evsel->priv; \
193 fields->name.pointer(&fields->name, sample); })
194
195static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
196 void *sys_enter_handler,
197 void *sys_exit_handler)
198{
199 int ret = -1;
200 struct perf_evsel *sys_enter, *sys_exit;
201
202 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
203 if (sys_enter == NULL)
204 goto out;
205
206 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
207 goto out_delete_sys_enter;
208
209 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
210 if (sys_exit == NULL)
211 goto out_delete_sys_enter;
212
213 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
214 goto out_delete_sys_exit;
215
216 perf_evlist__add(evlist, sys_enter);
217 perf_evlist__add(evlist, sys_exit);
218
219 ret = 0;
220out:
221 return ret;
222
223out_delete_sys_exit:
224 perf_evsel__delete_priv(sys_exit);
225out_delete_sys_enter:
226 perf_evsel__delete_priv(sys_enter);
227 goto out;
228}
229
230
231struct syscall_arg {
232 unsigned long val;
233 struct thread *thread;
234 struct trace *trace;
235 void *parm;
236 u8 idx;
237 u8 mask;
238};
239
240struct strarray {
241 int offset;
242 int nr_entries;
243 const char **entries;
244};
245
246#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
247 .nr_entries = ARRAY_SIZE(array), \
248 .entries = array, \
249}
250
251#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
252 .offset = off, \
253 .nr_entries = ARRAY_SIZE(array), \
254 .entries = array, \
255}
256
257static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
258 const char *intfmt,
259 struct syscall_arg *arg)
260{
261 struct strarray *sa = arg->parm;
262 int idx = arg->val - sa->offset;
263
264 if (idx < 0 || idx >= sa->nr_entries)
265 return scnprintf(bf, size, intfmt, arg->val);
266
267 return scnprintf(bf, size, "%s", sa->entries[idx]);
69} 268}
70 269
71#define SCA_WHENCE syscall_arg__scnprintf_whence 270static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
271 struct syscall_arg *arg)
272{
273 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
274}
275
276#define SCA_STRARRAY syscall_arg__scnprintf_strarray
277
278static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
279 struct syscall_arg *arg)
280{
281 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
282}
283
284#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
285
286static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
287 struct syscall_arg *arg);
288
289#define SCA_FD syscall_arg__scnprintf_fd
290
291static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
292 struct syscall_arg *arg)
293{
294 int fd = arg->val;
295
296 if (fd == AT_FDCWD)
297 return scnprintf(bf, size, "CWD");
298
299 return syscall_arg__scnprintf_fd(bf, size, arg);
300}
301
302#define SCA_FDAT syscall_arg__scnprintf_fd_at
303
304static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
305 struct syscall_arg *arg);
306
307#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
308
309static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
310 struct syscall_arg *arg)
311{
312 return scnprintf(bf, size, "%#lx", arg->val);
313}
314
315#define SCA_HEX syscall_arg__scnprintf_hex
72 316
73static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, 317static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
74 unsigned long arg, 318 struct syscall_arg *arg)
75 u8 arg_idx __maybe_unused,
76 u8 *arg_mask __maybe_unused)
77{ 319{
78 int printed = 0, prot = arg; 320 int printed = 0, prot = arg->val;
79 321
80 if (prot == PROT_NONE) 322 if (prot == PROT_NONE)
81 return scnprintf(bf, size, "NONE"); 323 return scnprintf(bf, size, "NONE");
@@ -104,10 +346,9 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
104#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot 346#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
105 347
106static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, 348static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
107 unsigned long arg, u8 arg_idx __maybe_unused, 349 struct syscall_arg *arg)
108 u8 *arg_mask __maybe_unused)
109{ 350{
110 int printed = 0, flags = arg; 351 int printed = 0, flags = arg->val;
111 352
112#define P_MMAP_FLAG(n) \ 353#define P_MMAP_FLAG(n) \
113 if (flags & MAP_##n) { \ 354 if (flags & MAP_##n) { \
@@ -148,10 +389,9 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
148#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags 389#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
149 390
150static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, 391static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
151 unsigned long arg, u8 arg_idx __maybe_unused, 392 struct syscall_arg *arg)
152 u8 *arg_mask __maybe_unused)
153{ 393{
154 int behavior = arg; 394 int behavior = arg->val;
155 395
156 switch (behavior) { 396 switch (behavior) {
157#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n) 397#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
@@ -190,8 +430,38 @@ static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
190 430
191#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior 431#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
192 432
193static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned long arg, 433static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
194 u8 arg_idx __maybe_unused, u8 *arg_mask) 434 struct syscall_arg *arg)
435{
436 int printed = 0, op = arg->val;
437
438 if (op == 0)
439 return scnprintf(bf, size, "NONE");
440#define P_CMD(cmd) \
441 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
442 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
443 op &= ~LOCK_##cmd; \
444 }
445
446 P_CMD(SH);
447 P_CMD(EX);
448 P_CMD(NB);
449 P_CMD(UN);
450 P_CMD(MAND);
451 P_CMD(RW);
452 P_CMD(READ);
453 P_CMD(WRITE);
454#undef P_OP
455
456 if (op)
457 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
458
459 return printed;
460}
461
462#define SCA_FLOCK syscall_arg__scnprintf_flock
463
464static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
195{ 465{
196 enum syscall_futex_args { 466 enum syscall_futex_args {
197 SCF_UADDR = (1 << 0), 467 SCF_UADDR = (1 << 0),
@@ -201,24 +471,24 @@ static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned lo
201 SCF_UADDR2 = (1 << 4), 471 SCF_UADDR2 = (1 << 4),
202 SCF_VAL3 = (1 << 5), 472 SCF_VAL3 = (1 << 5),
203 }; 473 };
204 int op = arg; 474 int op = arg->val;
205 int cmd = op & FUTEX_CMD_MASK; 475 int cmd = op & FUTEX_CMD_MASK;
206 size_t printed = 0; 476 size_t printed = 0;
207 477
208 switch (cmd) { 478 switch (cmd) {
209#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n); 479#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
210 P_FUTEX_OP(WAIT); *arg_mask |= SCF_VAL3|SCF_UADDR2; break; 480 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
211 P_FUTEX_OP(WAKE); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; 481 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
212 P_FUTEX_OP(FD); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; 482 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
213 P_FUTEX_OP(REQUEUE); *arg_mask |= SCF_VAL3|SCF_TIMEOUT; break; 483 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
214 P_FUTEX_OP(CMP_REQUEUE); *arg_mask |= SCF_TIMEOUT; break; 484 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
215 P_FUTEX_OP(CMP_REQUEUE_PI); *arg_mask |= SCF_TIMEOUT; break; 485 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
216 P_FUTEX_OP(WAKE_OP); break; 486 P_FUTEX_OP(WAKE_OP); break;
217 P_FUTEX_OP(LOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; 487 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
218 P_FUTEX_OP(UNLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; 488 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
219 P_FUTEX_OP(TRYLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2; break; 489 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
220 P_FUTEX_OP(WAIT_BITSET); *arg_mask |= SCF_UADDR2; break; 490 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
221 P_FUTEX_OP(WAKE_BITSET); *arg_mask |= SCF_UADDR2; break; 491 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
222 P_FUTEX_OP(WAIT_REQUEUE_PI); break; 492 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
223 default: printed = scnprintf(bf, size, "%#x", cmd); break; 493 default: printed = scnprintf(bf, size, "%#x", cmd); break;
224 } 494 }
@@ -234,14 +504,194 @@ static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned lo
234 504
235#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op 505#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
236 506
507static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
508static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
509
510static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
511static DEFINE_STRARRAY(itimers);
512
513static const char *whences[] = { "SET", "CUR", "END",
514#ifdef SEEK_DATA
515"DATA",
516#endif
517#ifdef SEEK_HOLE
518"HOLE",
519#endif
520};
521static DEFINE_STRARRAY(whences);
522
523static const char *fcntl_cmds[] = {
524 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
525 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
526 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
527 "F_GETOWNER_UIDS",
528};
529static DEFINE_STRARRAY(fcntl_cmds);
530
531static const char *rlimit_resources[] = {
532 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
533 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
534 "RTTIME",
535};
536static DEFINE_STRARRAY(rlimit_resources);
537
538static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
539static DEFINE_STRARRAY(sighow);
540
541static const char *clockid[] = {
542 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
543 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
544};
545static DEFINE_STRARRAY(clockid);
546
547static const char *socket_families[] = {
548 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
549 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
550 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
551 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
552 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
553 "ALG", "NFC", "VSOCK",
554};
555static DEFINE_STRARRAY(socket_families);
556
557#ifndef SOCK_TYPE_MASK
558#define SOCK_TYPE_MASK 0xf
559#endif
560
561static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
562 struct syscall_arg *arg)
563{
564 size_t printed;
565 int type = arg->val,
566 flags = type & ~SOCK_TYPE_MASK;
567
568 type &= SOCK_TYPE_MASK;
569 /*
570 * Can't use a strarray, MIPS may override for ABI reasons.
571 */
572 switch (type) {
573#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
574 P_SK_TYPE(STREAM);
575 P_SK_TYPE(DGRAM);
576 P_SK_TYPE(RAW);
577 P_SK_TYPE(RDM);
578 P_SK_TYPE(SEQPACKET);
579 P_SK_TYPE(DCCP);
580 P_SK_TYPE(PACKET);
581#undef P_SK_TYPE
582 default:
583 printed = scnprintf(bf, size, "%#x", type);
584 }
585
586#define P_SK_FLAG(n) \
587 if (flags & SOCK_##n) { \
588 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
589 flags &= ~SOCK_##n; \
590 }
591
592 P_SK_FLAG(CLOEXEC);
593 P_SK_FLAG(NONBLOCK);
594#undef P_SK_FLAG
595
596 if (flags)
597 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
598
599 return printed;
600}
601
602#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
603
604#ifndef MSG_PROBE
605#define MSG_PROBE 0x10
606#endif
607#ifndef MSG_WAITFORONE
608#define MSG_WAITFORONE 0x10000
609#endif
610#ifndef MSG_SENDPAGE_NOTLAST
611#define MSG_SENDPAGE_NOTLAST 0x20000
612#endif
613#ifndef MSG_FASTOPEN
614#define MSG_FASTOPEN 0x20000000
615#endif
616
617static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
618 struct syscall_arg *arg)
619{
620 int printed = 0, flags = arg->val;
621
622 if (flags == 0)
623 return scnprintf(bf, size, "NONE");
624#define P_MSG_FLAG(n) \
625 if (flags & MSG_##n) { \
626 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
627 flags &= ~MSG_##n; \
628 }
629
630 P_MSG_FLAG(OOB);
631 P_MSG_FLAG(PEEK);
632 P_MSG_FLAG(DONTROUTE);
633 P_MSG_FLAG(TRYHARD);
634 P_MSG_FLAG(CTRUNC);
635 P_MSG_FLAG(PROBE);
636 P_MSG_FLAG(TRUNC);
637 P_MSG_FLAG(DONTWAIT);
638 P_MSG_FLAG(EOR);
639 P_MSG_FLAG(WAITALL);
640 P_MSG_FLAG(FIN);
641 P_MSG_FLAG(SYN);
642 P_MSG_FLAG(CONFIRM);
643 P_MSG_FLAG(RST);
644 P_MSG_FLAG(ERRQUEUE);
645 P_MSG_FLAG(NOSIGNAL);
646 P_MSG_FLAG(MORE);
647 P_MSG_FLAG(WAITFORONE);
648 P_MSG_FLAG(SENDPAGE_NOTLAST);
649 P_MSG_FLAG(FASTOPEN);
650 P_MSG_FLAG(CMSG_CLOEXEC);
651#undef P_MSG_FLAG
652
653 if (flags)
654 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
655
656 return printed;
657}
658
659#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
660
661static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
662 struct syscall_arg *arg)
663{
664 size_t printed = 0;
665 int mode = arg->val;
666
667 if (mode == F_OK) /* 0 */
668 return scnprintf(bf, size, "F");
669#define P_MODE(n) \
670 if (mode & n##_OK) { \
671 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
672 mode &= ~n##_OK; \
673 }
674
675 P_MODE(R);
676 P_MODE(W);
677 P_MODE(X);
678#undef P_MODE
679
680 if (mode)
681 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
682
683 return printed;
684}
685
686#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
687
237static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, 688static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
238 unsigned long arg, 689 struct syscall_arg *arg)
239 u8 arg_idx, u8 *arg_mask)
240{ 690{
241 int printed = 0, flags = arg; 691 int printed = 0, flags = arg->val;
242 692
243 if (!(flags & O_CREAT)) 693 if (!(flags & O_CREAT))
244 *arg_mask |= 1 << (arg_idx + 1); /* Mask the mode parm */ 694 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
245 695
246 if (flags == 0) 696 if (flags == 0)
247 return scnprintf(bf, size, "RDONLY"); 697 return scnprintf(bf, size, "RDONLY");
@@ -291,60 +741,321 @@ static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
291 741
292#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags 742#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
293 743
744static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
745 struct syscall_arg *arg)
746{
747 int printed = 0, flags = arg->val;
748
749 if (flags == 0)
750 return scnprintf(bf, size, "NONE");
751#define P_FLAG(n) \
752 if (flags & EFD_##n) { \
753 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
754 flags &= ~EFD_##n; \
755 }
756
757 P_FLAG(SEMAPHORE);
758 P_FLAG(CLOEXEC);
759 P_FLAG(NONBLOCK);
760#undef P_FLAG
761
762 if (flags)
763 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
764
765 return printed;
766}
767
768#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
769
770static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
771 struct syscall_arg *arg)
772{
773 int printed = 0, flags = arg->val;
774
775#define P_FLAG(n) \
776 if (flags & O_##n) { \
777 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
778 flags &= ~O_##n; \
779 }
780
781 P_FLAG(CLOEXEC);
782 P_FLAG(NONBLOCK);
783#undef P_FLAG
784
785 if (flags)
786 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
787
788 return printed;
789}
790
791#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
792
793static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
794{
795 int sig = arg->val;
796
797 switch (sig) {
798#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
799 P_SIGNUM(HUP);
800 P_SIGNUM(INT);
801 P_SIGNUM(QUIT);
802 P_SIGNUM(ILL);
803 P_SIGNUM(TRAP);
804 P_SIGNUM(ABRT);
805 P_SIGNUM(BUS);
806 P_SIGNUM(FPE);
807 P_SIGNUM(KILL);
808 P_SIGNUM(USR1);
809 P_SIGNUM(SEGV);
810 P_SIGNUM(USR2);
811 P_SIGNUM(PIPE);
812 P_SIGNUM(ALRM);
813 P_SIGNUM(TERM);
814 P_SIGNUM(STKFLT);
815 P_SIGNUM(CHLD);
816 P_SIGNUM(CONT);
817 P_SIGNUM(STOP);
818 P_SIGNUM(TSTP);
819 P_SIGNUM(TTIN);
820 P_SIGNUM(TTOU);
821 P_SIGNUM(URG);
822 P_SIGNUM(XCPU);
823 P_SIGNUM(XFSZ);
824 P_SIGNUM(VTALRM);
825 P_SIGNUM(PROF);
826 P_SIGNUM(WINCH);
827 P_SIGNUM(IO);
828 P_SIGNUM(PWR);
829 P_SIGNUM(SYS);
830 default: break;
831 }
832
833 return scnprintf(bf, size, "%#x", sig);
834}
835
836#define SCA_SIGNUM syscall_arg__scnprintf_signum
837
838#define TCGETS 0x5401
839
840static const char *tioctls[] = {
841 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
842 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
843 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
844 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
845 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
846 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
847 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
848 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
849 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
850 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
851 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
852 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
853 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
854 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
855 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
856};
857
858static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
859
860#define STRARRAY(arg, name, array) \
861 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
862 .arg_parm = { [arg] = &strarray__##array, }
863
294static struct syscall_fmt { 864static struct syscall_fmt {
295 const char *name; 865 const char *name;
296 const char *alias; 866 const char *alias;
297 size_t (*arg_scnprintf[6])(char *bf, size_t size, unsigned long arg, u8 arg_idx, u8 *arg_mask); 867 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
868 void *arg_parm[6];
298 bool errmsg; 869 bool errmsg;
299 bool timeout; 870 bool timeout;
300 bool hexret; 871 bool hexret;
301} syscall_fmts[] = { 872} syscall_fmts[] = {
302 { .name = "access", .errmsg = true, }, 873 { .name = "access", .errmsg = true,
874 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
303 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, 875 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
304 { .name = "brk", .hexret = true, 876 { .name = "brk", .hexret = true,
305 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, 877 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
306 { .name = "mmap", .hexret = true, }, 878 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
879 { .name = "close", .errmsg = true,
880 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
307 { .name = "connect", .errmsg = true, }, 881 { .name = "connect", .errmsg = true, },
308 { .name = "fstat", .errmsg = true, .alias = "newfstat", }, 882 { .name = "dup", .errmsg = true,
309 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, 883 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
884 { .name = "dup2", .errmsg = true,
885 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
886 { .name = "dup3", .errmsg = true,
887 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
888 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
889 { .name = "eventfd2", .errmsg = true,
890 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
891 { .name = "faccessat", .errmsg = true,
892 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
893 { .name = "fadvise64", .errmsg = true,
894 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
895 { .name = "fallocate", .errmsg = true,
896 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
897 { .name = "fchdir", .errmsg = true,
898 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
899 { .name = "fchmod", .errmsg = true,
900 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
901 { .name = "fchmodat", .errmsg = true,
902 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
903 { .name = "fchown", .errmsg = true,
904 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
905 { .name = "fchownat", .errmsg = true,
906 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
907 { .name = "fcntl", .errmsg = true,
908 .arg_scnprintf = { [0] = SCA_FD, /* fd */
909 [1] = SCA_STRARRAY, /* cmd */ },
910 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
911 { .name = "fdatasync", .errmsg = true,
912 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
913 { .name = "flock", .errmsg = true,
914 .arg_scnprintf = { [0] = SCA_FD, /* fd */
915 [1] = SCA_FLOCK, /* cmd */ }, },
916 { .name = "fsetxattr", .errmsg = true,
917 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
918 { .name = "fstat", .errmsg = true, .alias = "newfstat",
919 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
920 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
921 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
922 { .name = "fstatfs", .errmsg = true,
923 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
924 { .name = "fsync", .errmsg = true,
925 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
926 { .name = "ftruncate", .errmsg = true,
927 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
310 { .name = "futex", .errmsg = true, 928 { .name = "futex", .errmsg = true,
311 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, }, 929 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
930 { .name = "futimesat", .errmsg = true,
931 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
932 { .name = "getdents", .errmsg = true,
933 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
934 { .name = "getdents64", .errmsg = true,
935 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
936 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
937 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
312 { .name = "ioctl", .errmsg = true, 938 { .name = "ioctl", .errmsg = true,
313 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, }, 939 .arg_scnprintf = { [0] = SCA_FD, /* fd */
940 [1] = SCA_STRHEXARRAY, /* cmd */
941 [2] = SCA_HEX, /* arg */ },
942 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
943 { .name = "kill", .errmsg = true,
944 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
945 { .name = "linkat", .errmsg = true,
946 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
314 { .name = "lseek", .errmsg = true, 947 { .name = "lseek", .errmsg = true,
315 .arg_scnprintf = { [2] = SCA_WHENCE, /* whence */ }, }, 948 .arg_scnprintf = { [0] = SCA_FD, /* fd */
949 [2] = SCA_STRARRAY, /* whence */ },
950 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
316 { .name = "lstat", .errmsg = true, .alias = "newlstat", }, 951 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
317 { .name = "madvise", .errmsg = true, 952 { .name = "madvise", .errmsg = true,
318 .arg_scnprintf = { [0] = SCA_HEX, /* start */ 953 .arg_scnprintf = { [0] = SCA_HEX, /* start */
319 [2] = SCA_MADV_BHV, /* behavior */ }, }, 954 [2] = SCA_MADV_BHV, /* behavior */ }, },
955 { .name = "mkdirat", .errmsg = true,
956 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
957 { .name = "mknodat", .errmsg = true,
958 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
959 { .name = "mlock", .errmsg = true,
960 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
961 { .name = "mlockall", .errmsg = true,
962 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
320 { .name = "mmap", .hexret = true, 963 { .name = "mmap", .hexret = true,
321 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ 964 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
322 [2] = SCA_MMAP_PROT, /* prot */ 965 [2] = SCA_MMAP_PROT, /* prot */
323 [3] = SCA_MMAP_FLAGS, /* flags */ }, }, 966 [3] = SCA_MMAP_FLAGS, /* flags */
967 [4] = SCA_FD, /* fd */ }, },
324 { .name = "mprotect", .errmsg = true, 968 { .name = "mprotect", .errmsg = true,
325 .arg_scnprintf = { [0] = SCA_HEX, /* start */ 969 .arg_scnprintf = { [0] = SCA_HEX, /* start */
326 [2] = SCA_MMAP_PROT, /* prot */ }, }, 970 [2] = SCA_MMAP_PROT, /* prot */ }, },
327 { .name = "mremap", .hexret = true, 971 { .name = "mremap", .hexret = true,
328 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ 972 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
329 [4] = SCA_HEX, /* new_addr */ }, }, 973 [4] = SCA_HEX, /* new_addr */ }, },
974 { .name = "munlock", .errmsg = true,
975 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
330 { .name = "munmap", .errmsg = true, 976 { .name = "munmap", .errmsg = true,
331 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, 977 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
978 { .name = "name_to_handle_at", .errmsg = true,
979 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
980 { .name = "newfstatat", .errmsg = true,
981 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
332 { .name = "open", .errmsg = true, 982 { .name = "open", .errmsg = true,
333 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, }, 983 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
334 { .name = "open_by_handle_at", .errmsg = true, 984 { .name = "open_by_handle_at", .errmsg = true,
335 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, }, 985 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
986 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
336 { .name = "openat", .errmsg = true, 987 { .name = "openat", .errmsg = true,
337 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, }, 988 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
989 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
990 { .name = "pipe2", .errmsg = true,
991 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
338 { .name = "poll", .errmsg = true, .timeout = true, }, 992 { .name = "poll", .errmsg = true, .timeout = true, },
339 { .name = "ppoll", .errmsg = true, .timeout = true, }, 993 { .name = "ppoll", .errmsg = true, .timeout = true, },
340 { .name = "pread", .errmsg = true, .alias = "pread64", }, 994 { .name = "pread", .errmsg = true, .alias = "pread64",
341 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", }, 995 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
342 { .name = "read", .errmsg = true, }, 996 { .name = "preadv", .errmsg = true, .alias = "pread",
343 { .name = "recvfrom", .errmsg = true, }, 997 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
998 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
999 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
1000 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1001 { .name = "pwritev", .errmsg = true,
1002 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1003 { .name = "read", .errmsg = true,
1004 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1005 { .name = "readlinkat", .errmsg = true,
1006 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1007 { .name = "readv", .errmsg = true,
1008 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1009 { .name = "recvfrom", .errmsg = true,
1010 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1011 { .name = "recvmmsg", .errmsg = true,
1012 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1013 { .name = "recvmsg", .errmsg = true,
1014 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1015 { .name = "renameat", .errmsg = true,
1016 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1017 { .name = "rt_sigaction", .errmsg = true,
1018 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
1019 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
1020 { .name = "rt_sigqueueinfo", .errmsg = true,
1021 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1022 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1023 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
344 { .name = "select", .errmsg = true, .timeout = true, }, 1024 { .name = "select", .errmsg = true, .timeout = true, },
345 { .name = "socket", .errmsg = true, }, 1025 { .name = "sendmmsg", .errmsg = true,
1026 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1027 { .name = "sendmsg", .errmsg = true,
1028 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1029 { .name = "sendto", .errmsg = true,
1030 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1031 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1032 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
1033 { .name = "shutdown", .errmsg = true,
1034 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1035 { .name = "socket", .errmsg = true,
1036 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1037 [1] = SCA_SK_TYPE, /* type */ },
1038 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
1039 { .name = "socketpair", .errmsg = true,
1040 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1041 [1] = SCA_SK_TYPE, /* type */ },
1042 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
346 { .name = "stat", .errmsg = true, .alias = "newstat", }, 1043 { .name = "stat", .errmsg = true, .alias = "newstat", },
1044 { .name = "symlinkat", .errmsg = true,
1045 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1046 { .name = "tgkill", .errmsg = true,
1047 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1048 { .name = "tkill", .errmsg = true,
1049 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
347 { .name = "uname", .errmsg = true, .alias = "newuname", }, 1050 { .name = "uname", .errmsg = true, .alias = "newuname", },
1051 { .name = "unlinkat", .errmsg = true,
1052 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1053 { .name = "utimensat", .errmsg = true,
1054 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1055 { .name = "write", .errmsg = true,
1056 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1057 { .name = "writev", .errmsg = true,
1058 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
348}; 1059};
349 1060
350static int syscall_fmt__cmp(const void *name, const void *fmtp) 1061static int syscall_fmt__cmp(const void *name, const void *fmtp)
@@ -364,8 +1075,8 @@ struct syscall {
364 const char *name; 1075 const char *name;
365 bool filtered; 1076 bool filtered;
366 struct syscall_fmt *fmt; 1077 struct syscall_fmt *fmt;
367 size_t (**arg_scnprintf)(char *bf, size_t size, 1078 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
368 unsigned long arg, u8 arg_idx, u8 *args_mask); 1079 void **arg_parm;
369}; 1080};
370 1081
371static size_t fprintf_duration(unsigned long t, FILE *fp) 1082static size_t fprintf_duration(unsigned long t, FILE *fp)
@@ -389,11 +1100,24 @@ struct thread_trace {
389 unsigned long nr_events; 1100 unsigned long nr_events;
390 char *entry_str; 1101 char *entry_str;
391 double runtime_ms; 1102 double runtime_ms;
1103 struct {
1104 int max;
1105 char **table;
1106 } paths;
1107
1108 struct intlist *syscall_stats;
392}; 1109};
393 1110
394static struct thread_trace *thread_trace__new(void) 1111static struct thread_trace *thread_trace__new(void)
395{ 1112{
396 return zalloc(sizeof(struct thread_trace)); 1113 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1114
1115 if (ttrace)
1116 ttrace->paths.max = -1;
1117
1118 ttrace->syscall_stats = intlist__new(NULL);
1119
1120 return ttrace;
397} 1121}
398 1122
399static struct thread_trace *thread__trace(struct thread *thread, FILE *fp) 1123static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
@@ -421,26 +1145,141 @@ fail:
421 1145
422struct trace { 1146struct trace {
423 struct perf_tool tool; 1147 struct perf_tool tool;
424 int audit_machine; 1148 struct {
1149 int machine;
1150 int open_id;
1151 } audit;
425 struct { 1152 struct {
426 int max; 1153 int max;
427 struct syscall *table; 1154 struct syscall *table;
428 } syscalls; 1155 } syscalls;
429 struct perf_record_opts opts; 1156 struct perf_record_opts opts;
430 struct machine host; 1157 struct machine *host;
431 u64 base_time; 1158 u64 base_time;
1159 bool full_time;
432 FILE *output; 1160 FILE *output;
433 unsigned long nr_events; 1161 unsigned long nr_events;
434 struct strlist *ev_qualifier; 1162 struct strlist *ev_qualifier;
435 bool not_ev_qualifier; 1163 bool not_ev_qualifier;
1164 bool live;
1165 const char *last_vfs_getname;
436 struct intlist *tid_list; 1166 struct intlist *tid_list;
437 struct intlist *pid_list; 1167 struct intlist *pid_list;
438 bool sched; 1168 bool sched;
439 bool multiple_threads; 1169 bool multiple_threads;
1170 bool summary;
1171 bool summary_only;
1172 bool show_comm;
1173 bool show_tool_stats;
440 double duration_filter; 1174 double duration_filter;
441 double runtime_ms; 1175 double runtime_ms;
1176 struct {
1177 u64 vfs_getname, proc_getname;
1178 } stats;
442}; 1179};
443 1180
1181static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
1182{
1183 struct thread_trace *ttrace = thread->priv;
1184
1185 if (fd > ttrace->paths.max) {
1186 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1187
1188 if (npath == NULL)
1189 return -1;
1190
1191 if (ttrace->paths.max != -1) {
1192 memset(npath + ttrace->paths.max + 1, 0,
1193 (fd - ttrace->paths.max) * sizeof(char *));
1194 } else {
1195 memset(npath, 0, (fd + 1) * sizeof(char *));
1196 }
1197
1198 ttrace->paths.table = npath;
1199 ttrace->paths.max = fd;
1200 }
1201
1202 ttrace->paths.table[fd] = strdup(pathname);
1203
1204 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1205}
1206
1207static int thread__read_fd_path(struct thread *thread, int fd)
1208{
1209 char linkname[PATH_MAX], pathname[PATH_MAX];
1210 struct stat st;
1211 int ret;
1212
1213 if (thread->pid_ == thread->tid) {
1214 scnprintf(linkname, sizeof(linkname),
1215 "/proc/%d/fd/%d", thread->pid_, fd);
1216 } else {
1217 scnprintf(linkname, sizeof(linkname),
1218 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1219 }
1220
1221 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1222 return -1;
1223
1224 ret = readlink(linkname, pathname, sizeof(pathname));
1225
1226 if (ret < 0 || ret > st.st_size)
1227 return -1;
1228
1229 pathname[ret] = '\0';
1230 return trace__set_fd_pathname(thread, fd, pathname);
1231}
1232
1233static const char *thread__fd_path(struct thread *thread, int fd,
1234 struct trace *trace)
1235{
1236 struct thread_trace *ttrace = thread->priv;
1237
1238 if (ttrace == NULL)
1239 return NULL;
1240
1241 if (fd < 0)
1242 return NULL;
1243
1244 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1245 if (!trace->live)
1246 return NULL;
1247 ++trace->stats.proc_getname;
1248 if (thread__read_fd_path(thread, fd)) {
1249 return NULL;
1250 }
1251
1252 return ttrace->paths.table[fd];
1253}
1254
1255static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1256 struct syscall_arg *arg)
1257{
1258 int fd = arg->val;
1259 size_t printed = scnprintf(bf, size, "%d", fd);
1260 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
1261
1262 if (path)
1263 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1264
1265 return printed;
1266}
1267
1268static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1269 struct syscall_arg *arg)
1270{
1271 int fd = arg->val;
1272 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1273 struct thread_trace *ttrace = arg->thread->priv;
1274
1275 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1276 free(ttrace->paths.table[fd]);
1277 ttrace->paths.table[fd] = NULL;
1278 }
1279
1280 return printed;
1281}
1282
444static bool trace__filter_duration(struct trace *trace, double t) 1283static bool trace__filter_duration(struct trace *trace, double t)
445{ 1284{
446 return t < (trace->duration_filter * NSEC_PER_MSEC); 1285 return t < (trace->duration_filter * NSEC_PER_MSEC);
@@ -454,10 +1293,12 @@ static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
454} 1293}
455 1294
456static bool done = false; 1295static bool done = false;
1296static bool interrupted = false;
457 1297
458static void sig_handler(int sig __maybe_unused) 1298static void sig_handler(int sig)
459{ 1299{
460 done = true; 1300 done = true;
1301 interrupted = sig == SIGINT;
461} 1302}
462 1303
463static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread, 1304static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
@@ -466,14 +1307,17 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
466 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp); 1307 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
467 printed += fprintf_duration(duration, fp); 1308 printed += fprintf_duration(duration, fp);
468 1309
469 if (trace->multiple_threads) 1310 if (trace->multiple_threads) {
1311 if (trace->show_comm)
1312 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
470 printed += fprintf(fp, "%d ", thread->tid); 1313 printed += fprintf(fp, "%d ", thread->tid);
1314 }
471 1315
472 return printed; 1316 return printed;
473} 1317}
474 1318
475static int trace__process_event(struct trace *trace, struct machine *machine, 1319static int trace__process_event(struct trace *trace, struct machine *machine,
476 union perf_event *event) 1320 union perf_event *event, struct perf_sample *sample)
477{ 1321{
478 int ret = 0; 1322 int ret = 0;
479 1323
@@ -481,9 +1325,9 @@ static int trace__process_event(struct trace *trace, struct machine *machine,
481 case PERF_RECORD_LOST: 1325 case PERF_RECORD_LOST:
482 color_fprintf(trace->output, PERF_COLOR_RED, 1326 color_fprintf(trace->output, PERF_COLOR_RED,
483 "LOST %" PRIu64 " events!\n", event->lost.lost); 1327 "LOST %" PRIu64 " events!\n", event->lost.lost);
484 ret = machine__process_lost_event(machine, event); 1328 ret = machine__process_lost_event(machine, event, sample);
485 default: 1329 default:
486 ret = machine__process_event(machine, event); 1330 ret = machine__process_event(machine, event, sample);
487 break; 1331 break;
488 } 1332 }
489 1333
@@ -492,11 +1336,11 @@ static int trace__process_event(struct trace *trace, struct machine *machine,
492 1336
493static int trace__tool_process(struct perf_tool *tool, 1337static int trace__tool_process(struct perf_tool *tool,
494 union perf_event *event, 1338 union perf_event *event,
495 struct perf_sample *sample __maybe_unused, 1339 struct perf_sample *sample,
496 struct machine *machine) 1340 struct machine *machine)
497{ 1341{
498 struct trace *trace = container_of(tool, struct trace, tool); 1342 struct trace *trace = container_of(tool, struct trace, tool);
499 return trace__process_event(trace, machine, event); 1343 return trace__process_event(trace, machine, event, sample);
500} 1344}
501 1345
502static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) 1346static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
@@ -506,18 +1350,12 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
506 if (err) 1350 if (err)
507 return err; 1351 return err;
508 1352
509 machine__init(&trace->host, "", HOST_KERNEL_ID); 1353 trace->host = machine__new_host();
510 machine__create_kernel_maps(&trace->host); 1354 if (trace->host == NULL)
511 1355 return -ENOMEM;
512 if (perf_target__has_task(&trace->opts.target)) {
513 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
514 trace__tool_process,
515 &trace->host);
516 } else {
517 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
518 &trace->host);
519 }
520 1356
1357 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1358 evlist->threads, trace__tool_process, false);
521 if (err) 1359 if (err)
522 symbol__exit(); 1360 symbol__exit();
523 1361
@@ -533,6 +1371,9 @@ static int syscall__set_arg_fmts(struct syscall *sc)
533 if (sc->arg_scnprintf == NULL) 1371 if (sc->arg_scnprintf == NULL)
534 return -1; 1372 return -1;
535 1373
1374 if (sc->fmt)
1375 sc->arg_parm = sc->fmt->arg_parm;
1376
536 for (field = sc->tp_format->format.fields->next; field; field = field->next) { 1377 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
537 if (sc->fmt && sc->fmt->arg_scnprintf[idx]) 1378 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
538 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; 1379 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
@@ -548,7 +1389,7 @@ static int trace__read_syscall_info(struct trace *trace, int id)
548{ 1389{
549 char tp_name[128]; 1390 char tp_name[128];
550 struct syscall *sc; 1391 struct syscall *sc;
551 const char *name = audit_syscall_to_name(id, trace->audit_machine); 1392 const char *name = audit_syscall_to_name(id, trace->audit.machine);
552 1393
553 if (name == NULL) 1394 if (name == NULL)
554 return -1; 1395 return -1;
@@ -603,32 +1444,52 @@ static int trace__read_syscall_info(struct trace *trace, int id)
603} 1444}
604 1445
605static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, 1446static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
606 unsigned long *args) 1447 unsigned long *args, struct trace *trace,
1448 struct thread *thread)
607{ 1449{
608 int i = 0;
609 size_t printed = 0; 1450 size_t printed = 0;
610 1451
611 if (sc->tp_format != NULL) { 1452 if (sc->tp_format != NULL) {
612 struct format_field *field; 1453 struct format_field *field;
613 u8 mask = 0, bit = 1; 1454 u8 bit = 1;
1455 struct syscall_arg arg = {
1456 .idx = 0,
1457 .mask = 0,
1458 .trace = trace,
1459 .thread = thread,
1460 };
614 1461
615 for (field = sc->tp_format->format.fields->next; field; 1462 for (field = sc->tp_format->format.fields->next; field;
616 field = field->next, ++i, bit <<= 1) { 1463 field = field->next, ++arg.idx, bit <<= 1) {
617 if (mask & bit) 1464 if (arg.mask & bit)
1465 continue;
1466 /*
1467 * Suppress this argument if its value is zero and
1468 * and we don't have a string associated in an
1469 * strarray for it.
1470 */
1471 if (args[arg.idx] == 0 &&
1472 !(sc->arg_scnprintf &&
1473 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1474 sc->arg_parm[arg.idx]))
618 continue; 1475 continue;
619 1476
620 printed += scnprintf(bf + printed, size - printed, 1477 printed += scnprintf(bf + printed, size - printed,
621 "%s%s: ", printed ? ", " : "", field->name); 1478 "%s%s: ", printed ? ", " : "", field->name);
622 1479 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
623 if (sc->arg_scnprintf && sc->arg_scnprintf[i]) { 1480 arg.val = args[arg.idx];
624 printed += sc->arg_scnprintf[i](bf + printed, size - printed, 1481 if (sc->arg_parm)
625 args[i], i, &mask); 1482 arg.parm = sc->arg_parm[arg.idx];
1483 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1484 size - printed, &arg);
626 } else { 1485 } else {
627 printed += scnprintf(bf + printed, size - printed, 1486 printed += scnprintf(bf + printed, size - printed,
628 "%ld", args[i]); 1487 "%ld", args[arg.idx]);
629 } 1488 }
630 } 1489 }
631 } else { 1490 } else {
1491 int i = 0;
1492
632 while (i < 6) { 1493 while (i < 6) {
633 printed += scnprintf(bf + printed, size - printed, 1494 printed += scnprintf(bf + printed, size - printed,
634 "%sarg%d: %ld", 1495 "%sarg%d: %ld",
@@ -644,10 +1505,8 @@ typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
644 struct perf_sample *sample); 1505 struct perf_sample *sample);
645 1506
646static struct syscall *trace__syscall_info(struct trace *trace, 1507static struct syscall *trace__syscall_info(struct trace *trace,
647 struct perf_evsel *evsel, 1508 struct perf_evsel *evsel, int id)
648 struct perf_sample *sample)
649{ 1509{
650 int id = perf_evsel__intval(evsel, sample, "id");
651 1510
652 if (id < 0) { 1511 if (id < 0) {
653 1512
@@ -688,6 +1547,32 @@ out_cant_read:
688 return NULL; 1547 return NULL;
689} 1548}
690 1549
1550static void thread__update_stats(struct thread_trace *ttrace,
1551 int id, struct perf_sample *sample)
1552{
1553 struct int_node *inode;
1554 struct stats *stats;
1555 u64 duration = 0;
1556
1557 inode = intlist__findnew(ttrace->syscall_stats, id);
1558 if (inode == NULL)
1559 return;
1560
1561 stats = inode->priv;
1562 if (stats == NULL) {
1563 stats = malloc(sizeof(struct stats));
1564 if (stats == NULL)
1565 return;
1566 init_stats(stats);
1567 inode->priv = stats;
1568 }
1569
1570 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1571 duration = sample->time - ttrace->entry_time;
1572
1573 update_stats(stats, duration);
1574}
1575
691static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 1576static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
692 struct perf_sample *sample) 1577 struct perf_sample *sample)
693{ 1578{
@@ -695,7 +1580,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
695 void *args; 1580 void *args;
696 size_t printed = 0; 1581 size_t printed = 0;
697 struct thread *thread; 1582 struct thread *thread;
698 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 1583 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
1584 struct syscall *sc = trace__syscall_info(trace, evsel, id);
699 struct thread_trace *ttrace; 1585 struct thread_trace *ttrace;
700 1586
701 if (sc == NULL) 1587 if (sc == NULL)
@@ -704,18 +1590,12 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
704 if (sc->filtered) 1590 if (sc->filtered)
705 return 0; 1591 return 0;
706 1592
707 thread = machine__findnew_thread(&trace->host, sample->pid, 1593 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
708 sample->tid);
709 ttrace = thread__trace(thread, trace->output); 1594 ttrace = thread__trace(thread, trace->output);
710 if (ttrace == NULL) 1595 if (ttrace == NULL)
711 return -1; 1596 return -1;
712 1597
713 args = perf_evsel__rawptr(evsel, sample, "args"); 1598 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
714 if (args == NULL) {
715 fprintf(trace->output, "Problems reading syscall arguments\n");
716 return -1;
717 }
718
719 ttrace = thread->priv; 1599 ttrace = thread->priv;
720 1600
721 if (ttrace->entry_str == NULL) { 1601 if (ttrace->entry_str == NULL) {
@@ -728,10 +1608,11 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
728 msg = ttrace->entry_str; 1608 msg = ttrace->entry_str;
729 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name); 1609 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
730 1610
731 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args); 1611 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1612 args, trace, thread);
732 1613
733 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { 1614 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
734 if (!trace->duration_filter) { 1615 if (!trace->duration_filter && !trace->summary_only) {
735 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); 1616 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
736 fprintf(trace->output, "%-70s\n", ttrace->entry_str); 1617 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
737 } 1618 }
@@ -747,7 +1628,8 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
747 int ret; 1628 int ret;
748 u64 duration = 0; 1629 u64 duration = 0;
749 struct thread *thread; 1630 struct thread *thread;
750 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 1631 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
1632 struct syscall *sc = trace__syscall_info(trace, evsel, id);
751 struct thread_trace *ttrace; 1633 struct thread_trace *ttrace;
752 1634
753 if (sc == NULL) 1635 if (sc == NULL)
@@ -756,13 +1638,21 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
756 if (sc->filtered) 1638 if (sc->filtered)
757 return 0; 1639 return 0;
758 1640
759 thread = machine__findnew_thread(&trace->host, sample->pid, 1641 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
760 sample->tid);
761 ttrace = thread__trace(thread, trace->output); 1642 ttrace = thread__trace(thread, trace->output);
762 if (ttrace == NULL) 1643 if (ttrace == NULL)
763 return -1; 1644 return -1;
764 1645
765 ret = perf_evsel__intval(evsel, sample, "ret"); 1646 if (trace->summary)
1647 thread__update_stats(ttrace, id, sample);
1648
1649 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
1650
1651 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1652 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1653 trace->last_vfs_getname = NULL;
1654 ++trace->stats.vfs_getname;
1655 }
766 1656
767 ttrace = thread->priv; 1657 ttrace = thread->priv;
768 1658
@@ -775,6 +1665,9 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
775 } else if (trace->duration_filter) 1665 } else if (trace->duration_filter)
776 goto out; 1666 goto out;
777 1667
1668 if (trace->summary_only)
1669 goto out;
1670
778 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output); 1671 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
779 1672
780 if (ttrace->entry_pending) { 1673 if (ttrace->entry_pending) {
@@ -808,12 +1701,19 @@ out:
808 return 0; 1701 return 0;
809} 1702}
810 1703
1704static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1705 struct perf_sample *sample)
1706{
1707 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1708 return 0;
1709}
1710
811static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, 1711static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
812 struct perf_sample *sample) 1712 struct perf_sample *sample)
813{ 1713{
814 u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 1714 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
815 double runtime_ms = (double)runtime / NSEC_PER_MSEC; 1715 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
816 struct thread *thread = machine__findnew_thread(&trace->host, 1716 struct thread *thread = machine__findnew_thread(trace->host,
817 sample->pid, 1717 sample->pid,
818 sample->tid); 1718 sample->tid);
819 struct thread_trace *ttrace = thread__trace(thread, trace->output); 1719 struct thread_trace *ttrace = thread__trace(thread, trace->output);
@@ -856,12 +1756,12 @@ static int trace__process_sample(struct perf_tool *tool,
856 struct trace *trace = container_of(tool, struct trace, tool); 1756 struct trace *trace = container_of(tool, struct trace, tool);
857 int err = 0; 1757 int err = 0;
858 1758
859 tracepoint_handler handler = evsel->handler.func; 1759 tracepoint_handler handler = evsel->handler;
860 1760
861 if (skip_sample(trace, sample)) 1761 if (skip_sample(trace, sample))
862 return 0; 1762 return 0;
863 1763
864 if (trace->base_time == 0) 1764 if (!trace->full_time && trace->base_time == 0)
865 trace->base_time = sample->time; 1765 trace->base_time = sample->time;
866 1766
867 if (handler) 1767 if (handler)
@@ -870,16 +1770,6 @@ static int trace__process_sample(struct perf_tool *tool,
870 return err; 1770 return err;
871} 1771}
872 1772
873static bool
874perf_session__has_tp(struct perf_session *session, const char *name)
875{
876 struct perf_evsel *evsel;
877
878 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
879
880 return evsel != NULL;
881}
882
883static int parse_target_str(struct trace *trace) 1773static int parse_target_str(struct trace *trace)
884{ 1774{
885 if (trace->opts.target.pid) { 1775 if (trace->opts.target.pid) {
@@ -901,6 +1791,50 @@ static int parse_target_str(struct trace *trace)
901 return 0; 1791 return 0;
902} 1792}
903 1793
1794static int trace__record(int argc, const char **argv)
1795{
1796 unsigned int rec_argc, i, j;
1797 const char **rec_argv;
1798 const char * const record_args[] = {
1799 "record",
1800 "-R",
1801 "-m", "1024",
1802 "-c", "1",
1803 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1804 };
1805
1806 rec_argc = ARRAY_SIZE(record_args) + argc;
1807 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1808
1809 if (rec_argv == NULL)
1810 return -ENOMEM;
1811
1812 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1813 rec_argv[i] = record_args[i];
1814
1815 for (j = 0; j < (unsigned int)argc; j++, i++)
1816 rec_argv[i] = argv[j];
1817
1818 return cmd_record(i, rec_argv, NULL);
1819}
1820
1821static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1822
1823static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1824{
1825 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
1826 if (evsel == NULL)
1827 return;
1828
1829 if (perf_evsel__field(evsel, "pathname") == NULL) {
1830 perf_evsel__delete(evsel);
1831 return;
1832 }
1833
1834 evsel->handler = trace__vfs_getname;
1835 perf_evlist__add(evlist, evsel);
1836}
1837
904static int trace__run(struct trace *trace, int argc, const char **argv) 1838static int trace__run(struct trace *trace, int argc, const char **argv)
905{ 1839{
906 struct perf_evlist *evlist = perf_evlist__new(); 1840 struct perf_evlist *evlist = perf_evlist__new();
@@ -909,23 +1843,22 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
909 unsigned long before; 1843 unsigned long before;
910 const bool forks = argc > 0; 1844 const bool forks = argc > 0;
911 1845
1846 trace->live = true;
1847
912 if (evlist == NULL) { 1848 if (evlist == NULL) {
913 fprintf(trace->output, "Not enough memory to run!\n"); 1849 fprintf(trace->output, "Not enough memory to run!\n");
914 goto out; 1850 goto out;
915 } 1851 }
916 1852
917 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || 1853 if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit))
918 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) { 1854 goto out_error_tp;
919 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n"); 1855
920 goto out_delete_evlist; 1856 perf_evlist__add_vfs_getname(evlist);
921 }
922 1857
923 if (trace->sched && 1858 if (trace->sched &&
924 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 1859 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
925 trace__sched_stat_runtime)) { 1860 trace__sched_stat_runtime))
926 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n"); 1861 goto out_error_tp;
927 goto out_delete_evlist;
928 }
929 1862
930 err = perf_evlist__create_maps(evlist, &trace->opts.target); 1863 err = perf_evlist__create_maps(evlist, &trace->opts.target);
931 if (err < 0) { 1864 if (err < 0) {
@@ -954,10 +1887,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
954 } 1887 }
955 1888
956 err = perf_evlist__open(evlist); 1889 err = perf_evlist__open(evlist);
957 if (err < 0) { 1890 if (err < 0)
958 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno)); 1891 goto out_error_open;
959 goto out_delete_maps;
960 }
961 1892
962 err = perf_evlist__mmap(evlist, UINT_MAX, false); 1893 err = perf_evlist__mmap(evlist, UINT_MAX, false);
963 if (err < 0) { 1894 if (err < 0) {
@@ -987,51 +1918,65 @@ again:
987 err = perf_evlist__parse_sample(evlist, event, &sample); 1918 err = perf_evlist__parse_sample(evlist, event, &sample);
988 if (err) { 1919 if (err) {
989 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err); 1920 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
990 continue; 1921 goto next_event;
991 } 1922 }
992 1923
993 if (trace->base_time == 0) 1924 if (!trace->full_time && trace->base_time == 0)
994 trace->base_time = sample.time; 1925 trace->base_time = sample.time;
995 1926
996 if (type != PERF_RECORD_SAMPLE) { 1927 if (type != PERF_RECORD_SAMPLE) {
997 trace__process_event(trace, &trace->host, event); 1928 trace__process_event(trace, trace->host, event, &sample);
998 continue; 1929 continue;
999 } 1930 }
1000 1931
1001 evsel = perf_evlist__id2evsel(evlist, sample.id); 1932 evsel = perf_evlist__id2evsel(evlist, sample.id);
1002 if (evsel == NULL) { 1933 if (evsel == NULL) {
1003 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); 1934 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
1004 continue; 1935 goto next_event;
1005 } 1936 }
1006 1937
1007 if (sample.raw_data == NULL) { 1938 if (sample.raw_data == NULL) {
1008 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 1939 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
1009 perf_evsel__name(evsel), sample.tid, 1940 perf_evsel__name(evsel), sample.tid,
1010 sample.cpu, sample.raw_size); 1941 sample.cpu, sample.raw_size);
1011 continue; 1942 goto next_event;
1012 } 1943 }
1013 1944
1014 handler = evsel->handler.func; 1945 handler = evsel->handler;
1015 handler(trace, evsel, &sample); 1946 handler(trace, evsel, &sample);
1947next_event:
1948 perf_evlist__mmap_consume(evlist, i);
1016 1949
1017 if (done) 1950 if (interrupted)
1018 goto out_unmap_evlist; 1951 goto out_disable;
1019 } 1952 }
1020 } 1953 }
1021 1954
1022 if (trace->nr_events == before) { 1955 if (trace->nr_events == before) {
1023 if (done) 1956 int timeout = done ? 100 : -1;
1024 goto out_unmap_evlist;
1025 1957
1026 poll(evlist->pollfd, evlist->nr_fds, -1); 1958 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1959 goto again;
1960 } else {
1961 goto again;
1027 } 1962 }
1028 1963
1029 if (done) 1964out_disable:
1030 perf_evlist__disable(evlist); 1965 perf_evlist__disable(evlist);
1966
1967 if (!err) {
1968 if (trace->summary)
1969 trace__fprintf_thread_summary(trace, trace->output);
1031 1970
1032 goto again; 1971 if (trace->show_tool_stats) {
1972 fprintf(trace->output, "Stats:\n "
1973 " vfs_getname : %" PRIu64 "\n"
1974 " proc_getname: %" PRIu64 "\n",
1975 trace->stats.vfs_getname,
1976 trace->stats.proc_getname);
1977 }
1978 }
1033 1979
1034out_unmap_evlist:
1035 perf_evlist__munmap(evlist); 1980 perf_evlist__munmap(evlist);
1036out_close_evlist: 1981out_close_evlist:
1037 perf_evlist__close(evlist); 1982 perf_evlist__close(evlist);
@@ -1040,17 +1985,35 @@ out_delete_maps:
1040out_delete_evlist: 1985out_delete_evlist:
1041 perf_evlist__delete(evlist); 1986 perf_evlist__delete(evlist);
1042out: 1987out:
1988 trace->live = false;
1043 return err; 1989 return err;
1990{
1991 char errbuf[BUFSIZ];
1992
1993out_error_tp:
1994 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
1995 goto out_error;
1996
1997out_error_open:
1998 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
1999
2000out_error:
2001 fprintf(trace->output, "%s\n", errbuf);
2002 goto out_delete_evlist;
2003}
1044} 2004}
1045 2005
1046static int trace__replay(struct trace *trace) 2006static int trace__replay(struct trace *trace)
1047{ 2007{
1048 const struct perf_evsel_str_handler handlers[] = { 2008 const struct perf_evsel_str_handler handlers[] = {
1049 { "raw_syscalls:sys_enter", trace__sys_enter, }, 2009 { "probe:vfs_getname", trace__vfs_getname, },
1050 { "raw_syscalls:sys_exit", trace__sys_exit, }, 2010 };
2011 struct perf_data_file file = {
2012 .path = input_name,
2013 .mode = PERF_DATA_MODE_READ,
1051 }; 2014 };
1052
1053 struct perf_session *session; 2015 struct perf_session *session;
2016 struct perf_evsel *evsel;
1054 int err = -1; 2017 int err = -1;
1055 2018
1056 trace->tool.sample = trace__process_sample; 2019 trace->tool.sample = trace__process_sample;
@@ -1072,22 +2035,39 @@ static int trace__replay(struct trace *trace)
1072 if (symbol__init() < 0) 2035 if (symbol__init() < 0)
1073 return -1; 2036 return -1;
1074 2037
1075 session = perf_session__new(input_name, O_RDONLY, 0, false, 2038 session = perf_session__new(&file, false, &trace->tool);
1076 &trace->tool);
1077 if (session == NULL) 2039 if (session == NULL)
1078 return -ENOMEM; 2040 return -ENOMEM;
1079 2041
2042 trace->host = &session->machines.host;
2043
1080 err = perf_session__set_tracepoints_handlers(session, handlers); 2044 err = perf_session__set_tracepoints_handlers(session, handlers);
1081 if (err) 2045 if (err)
1082 goto out; 2046 goto out;
1083 2047
1084 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) { 2048 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
1085 pr_err("Data file does not have raw_syscalls:sys_enter events\n"); 2049 "raw_syscalls:sys_enter");
2050 if (evsel == NULL) {
2051 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
2052 goto out;
2053 }
2054
2055 if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2056 perf_evsel__init_sc_tp_ptr_field(evsel, args)) {
2057 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2058 goto out;
2059 }
2060
2061 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2062 "raw_syscalls:sys_exit");
2063 if (evsel == NULL) {
2064 pr_err("Data file does not have raw_syscalls:sys_exit event\n");
1086 goto out; 2065 goto out;
1087 } 2066 }
1088 2067
1089 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) { 2068 if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
1090 pr_err("Data file does not have raw_syscalls:sys_exit events\n"); 2069 perf_evsel__init_sc_tp_uint_field(evsel, ret)) {
2070 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
1091 goto out; 2071 goto out;
1092 } 2072 }
1093 2073
@@ -1101,6 +2081,9 @@ static int trace__replay(struct trace *trace)
1101 if (err) 2081 if (err)
1102 pr_err("Failed to process events, error %d", err); 2082 pr_err("Failed to process events, error %d", err);
1103 2083
2084 else if (trace->summary)
2085 trace__fprintf_thread_summary(trace, trace->output);
2086
1104out: 2087out:
1105 perf_session__delete(session); 2088 perf_session__delete(session);
1106 2089
@@ -1111,47 +2094,110 @@ static size_t trace__fprintf_threads_header(FILE *fp)
1111{ 2094{
1112 size_t printed; 2095 size_t printed;
1113 2096
1114 printed = fprintf(fp, "\n _____________________________________________________________________\n"); 2097 printed = fprintf(fp, "\n Summary of events:\n\n");
1115 printed += fprintf(fp," __) Summary of events (__\n\n");
1116 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1117 printed += fprintf(fp," _____________________________________________________________________\n\n");
1118 2098
1119 return printed; 2099 return printed;
1120} 2100}
1121 2101
1122static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) 2102static size_t thread__dump_stats(struct thread_trace *ttrace,
2103 struct trace *trace, FILE *fp)
1123{ 2104{
1124 size_t printed = trace__fprintf_threads_header(fp); 2105 struct stats *stats;
1125 struct rb_node *nd; 2106 size_t printed = 0;
1126 2107 struct syscall *sc;
1127 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) { 2108 struct int_node *inode = intlist__first(ttrace->syscall_stats);
1128 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1129 struct thread_trace *ttrace = thread->priv;
1130 const char *color;
1131 double ratio;
1132
1133 if (ttrace == NULL)
1134 continue;
1135 2109
1136 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; 2110 if (inode == NULL)
2111 return 0;
1137 2112
1138 color = PERF_COLOR_NORMAL; 2113 printed += fprintf(fp, "\n");
1139 if (ratio > 50.0) 2114
1140 color = PERF_COLOR_RED; 2115 printed += fprintf(fp, " syscall calls min avg max stddev\n");
1141 else if (ratio > 25.0) 2116 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
1142 color = PERF_COLOR_GREEN; 2117 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
1143 else if (ratio > 5.0) 2118
1144 color = PERF_COLOR_YELLOW; 2119 /* each int_node is a syscall */
2120 while (inode) {
2121 stats = inode->priv;
2122 if (stats) {
2123 double min = (double)(stats->min) / NSEC_PER_MSEC;
2124 double max = (double)(stats->max) / NSEC_PER_MSEC;
2125 double avg = avg_stats(stats);
2126 double pct;
2127 u64 n = (u64) stats->n;
2128
2129 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2130 avg /= NSEC_PER_MSEC;
2131
2132 sc = &trace->syscalls.table[inode->i];
2133 printed += fprintf(fp, " %-15s", sc->name);
2134 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
2135 n, min, avg);
2136 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
2137 }
1145 2138
1146 printed += color_fprintf(fp, color, "%20s", thread->comm); 2139 inode = intlist__next(inode);
1147 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1148 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1149 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1150 } 2140 }
1151 2141
2142 printed += fprintf(fp, "\n\n");
2143
1152 return printed; 2144 return printed;
1153} 2145}
1154 2146
2147/* struct used to pass data to per-thread function */
2148struct summary_data {
2149 FILE *fp;
2150 struct trace *trace;
2151 size_t printed;
2152};
2153
2154static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2155{
2156 struct summary_data *data = priv;
2157 FILE *fp = data->fp;
2158 size_t printed = data->printed;
2159 struct trace *trace = data->trace;
2160 struct thread_trace *ttrace = thread->priv;
2161 const char *color;
2162 double ratio;
2163
2164 if (ttrace == NULL)
2165 return 0;
2166
2167 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2168
2169 color = PERF_COLOR_NORMAL;
2170 if (ratio > 50.0)
2171 color = PERF_COLOR_RED;
2172 else if (ratio > 25.0)
2173 color = PERF_COLOR_GREEN;
2174 else if (ratio > 5.0)
2175 color = PERF_COLOR_YELLOW;
2176
2177 printed += color_fprintf(fp, color, " %s (%d), ", thread__comm_str(thread), thread->tid);
2178 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
2179 printed += color_fprintf(fp, color, "%.1f%%", ratio);
2180 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2181 printed += thread__dump_stats(ttrace, trace, fp);
2182
2183 data->printed += printed;
2184
2185 return 0;
2186}
2187
2188static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2189{
2190 struct summary_data data = {
2191 .fp = fp,
2192 .trace = trace
2193 };
2194 data.printed = trace__fprintf_threads_header(fp);
2195
2196 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
2197
2198 return data.printed;
2199}
2200
1155static int trace__set_duration(const struct option *opt, const char *str, 2201static int trace__set_duration(const struct option *opt, const char *str,
1156 int unset __maybe_unused) 2202 int unset __maybe_unused)
1157{ 2203{
@@ -1183,10 +2229,15 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1183 const char * const trace_usage[] = { 2229 const char * const trace_usage[] = {
1184 "perf trace [<options>] [<command>]", 2230 "perf trace [<options>] [<command>]",
1185 "perf trace [<options>] -- <command> [<options>]", 2231 "perf trace [<options>] -- <command> [<options>]",
2232 "perf trace record [<options>] [<command>]",
2233 "perf trace record [<options>] -- <command> [<options>]",
1186 NULL 2234 NULL
1187 }; 2235 };
1188 struct trace trace = { 2236 struct trace trace = {
1189 .audit_machine = audit_detect_machine(), 2237 .audit = {
2238 .machine = audit_detect_machine(),
2239 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2240 },
1190 .syscalls = { 2241 .syscalls = {
1191 . max = -1, 2242 . max = -1,
1192 }, 2243 },
@@ -1201,10 +2252,14 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1201 .mmap_pages = 1024, 2252 .mmap_pages = 1024,
1202 }, 2253 },
1203 .output = stdout, 2254 .output = stdout,
2255 .show_comm = true,
1204 }; 2256 };
1205 const char *output_name = NULL; 2257 const char *output_name = NULL;
1206 const char *ev_qualifier_str = NULL; 2258 const char *ev_qualifier_str = NULL;
1207 const struct option trace_options[] = { 2259 const struct option trace_options[] = {
2260 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2261 "show the thread COMM next to its id"),
2262 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
1208 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", 2263 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1209 "list of events to trace"), 2264 "list of events to trace"),
1210 OPT_STRING('o', "output", &output_name, "file", "output file name"), 2265 OPT_STRING('o', "output", &output_name, "file", "output file name"),
@@ -1219,8 +2274,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1219 "list of cpus to monitor"), 2274 "list of cpus to monitor"),
1220 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit, 2275 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
1221 "child tasks do not inherit counters"), 2276 "child tasks do not inherit counters"),
1222 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages, 2277 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1223 "number of mmap data pages"), 2278 "number of mmap data pages",
2279 perf_evlist__parse_mmap_pages),
1224 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user", 2280 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
1225 "user to profile"), 2281 "user to profile"),
1226 OPT_CALLBACK(0, "duration", &trace, "float", 2282 OPT_CALLBACK(0, "duration", &trace, "float",
@@ -1228,13 +2284,26 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1228 trace__set_duration), 2284 trace__set_duration),
1229 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"), 2285 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
1230 OPT_INCR('v', "verbose", &verbose, "be more verbose"), 2286 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
2287 OPT_BOOLEAN('T', "time", &trace.full_time,
2288 "Show full timestamp, not time relative to first start"),
2289 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2290 "Show only syscall summary with statistics"),
2291 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2292 "Show all syscalls and summary with statistics"),
1231 OPT_END() 2293 OPT_END()
1232 }; 2294 };
1233 int err; 2295 int err;
1234 char bf[BUFSIZ]; 2296 char bf[BUFSIZ];
1235 2297
2298 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2299 return trace__record(argc-2, &argv[2]);
2300
1236 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 2301 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
1237 2302
2303 /* summary_only implies summary option, but don't overwrite summary if set */
2304 if (trace.summary_only)
2305 trace.summary = trace.summary_only;
2306
1238 if (output_name != NULL) { 2307 if (output_name != NULL) {
1239 err = trace__open_output(&trace, output_name); 2308 err = trace__open_output(&trace, output_name);
1240 if (err < 0) { 2309 if (err < 0) {
@@ -1258,21 +2327,21 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1258 } 2327 }
1259 } 2328 }
1260 2329
1261 err = perf_target__validate(&trace.opts.target); 2330 err = target__validate(&trace.opts.target);
1262 if (err) { 2331 if (err) {
1263 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 2332 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
1264 fprintf(trace.output, "%s", bf); 2333 fprintf(trace.output, "%s", bf);
1265 goto out_close; 2334 goto out_close;
1266 } 2335 }
1267 2336
1268 err = perf_target__parse_uid(&trace.opts.target); 2337 err = target__parse_uid(&trace.opts.target);
1269 if (err) { 2338 if (err) {
1270 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 2339 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
1271 fprintf(trace.output, "%s", bf); 2340 fprintf(trace.output, "%s", bf);
1272 goto out_close; 2341 goto out_close;
1273 } 2342 }
1274 2343
1275 if (!argc && perf_target__none(&trace.opts.target)) 2344 if (!argc && target__none(&trace.opts.target))
1276 trace.opts.target.system_wide = true; 2345 trace.opts.target.system_wide = true;
1277 2346
1278 if (input_name) 2347 if (input_name)
@@ -1280,9 +2349,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1280 else 2349 else
1281 err = trace__run(&trace, argc, argv); 2350 err = trace__run(&trace, argc, argv);
1282 2351
1283 if (trace.sched && !err)
1284 trace__fprintf_thread_summary(&trace, trace.output);
1285
1286out_close: 2352out_close:
1287 if (output_name != NULL) 2353 if (output_name != NULL)
1288 fclose(trace.output); 2354 fclose(trace.output);
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 5f6f9b3271bb..f7d11a811c74 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -23,15 +23,21 @@ ifeq ($(ARCH),x86_64)
23 endif 23 endif
24 ifeq (${IS_X86_64}, 1) 24 ifeq (${IS_X86_64}, 1)
25 RAW_ARCH := x86_64 25 RAW_ARCH := x86_64
26 CFLAGS += -DARCH_X86_64 26 CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
27 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S 27 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
28 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
29 else
30 LIBUNWIND_LIBS = -lunwind -lunwind-x86
28 endif 31 endif
29 NO_PERF_REGS := 0 32 NO_PERF_REGS := 0
30 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 33endif
34ifeq ($(ARCH),arm)
35 NO_PERF_REGS := 0
36 LIBUNWIND_LIBS = -lunwind -lunwind-arm
31endif 37endif
32 38
33ifeq ($(NO_PERF_REGS),0) 39ifeq ($(NO_PERF_REGS),0)
34 CFLAGS += -DHAVE_PERF_REGS 40 CFLAGS += -DHAVE_PERF_REGS_SUPPORT
35endif 41endif
36 42
37ifeq ($(src-perf),) 43ifeq ($(src-perf),)
@@ -51,7 +57,6 @@ LIB_INCLUDE := $(srctree)/tools/lib/
51# include ARCH specific config 57# include ARCH specific config
52-include $(src-perf)/arch/$(ARCH)/Makefile 58-include $(src-perf)/arch/$(ARCH)/Makefile
53 59
54include $(src-perf)/config/feature-tests.mak
55include $(src-perf)/config/utilities.mak 60include $(src-perf)/config/utilities.mak
56 61
57ifeq ($(call get-executable,$(FLEX)),) 62ifeq ($(call get-executable,$(FLEX)),)
@@ -67,10 +72,11 @@ ifneq ($(WERROR),0)
67 CFLAGS += -Werror 72 CFLAGS += -Werror
68endif 73endif
69 74
70ifeq ("$(origin DEBUG)", "command line") 75ifndef DEBUG
71 PERF_DEBUG = $(DEBUG) 76 DEBUG := 0
72endif 77endif
73ifndef PERF_DEBUG 78
79ifeq ($(DEBUG),0)
74 CFLAGS += -O6 80 CFLAGS += -O6
75endif 81endif
76 82
@@ -89,20 +95,126 @@ CFLAGS += -std=gnu99
89 95
90EXTLIBS = -lelf -lpthread -lrt -lm -ldl 96EXTLIBS = -lelf -lpthread -lrt -lm -ldl
91 97
92ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) 98ifneq ($(OUTPUT),)
93 CFLAGS += -fstack-protector-all 99 OUTPUT_FEATURES = $(OUTPUT)config/feature-checks/
100 $(shell mkdir -p $(OUTPUT_FEATURES))
94endif 101endif
95 102
96ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y) 103feature_check = $(eval $(feature_check_code))
97 CFLAGS += -Wstack-protector 104define feature_check_code
105 feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBUNWIND_LIBS="$(LIBUNWIND_LIBS)" -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0)
106endef
107
108feature_set = $(eval $(feature_set_code))
109define feature_set_code
110 feature-$(1) := 1
111endef
112
113#
114# Build the feature check binaries in parallel, ignore errors, ignore return value and suppress output:
115#
116
117#
118# Note that this is not a complete list of all feature tests, just
119# those that are typically built on a fully configured system.
120#
121# [ Feature tests not mentioned here have to be built explicitly in
122# the rule that uses them - an example for that is the 'bionic'
123# feature check. ]
124#
125CORE_FEATURE_TESTS = \
126 backtrace \
127 dwarf \
128 fortify-source \
129 glibc \
130 gtk2 \
131 gtk2-infobar \
132 libaudit \
133 libbfd \
134 libelf \
135 libelf-getphdrnum \
136 libelf-mmap \
137 libnuma \
138 libperl \
139 libpython \
140 libpython-version \
141 libslang \
142 libunwind \
143 on-exit \
144 stackprotector \
145 stackprotector-all \
146 timerfd
147
148#
149# So here we detect whether test-all was rebuilt, to be able
150# to skip the print-out of the long features list if the file
151# existed before and after it was built:
152#
153ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all),)
154 test-all-failed := 1
155else
156 test-all-failed := 0
157endif
158
159#
160# Special fast-path for the 'all features are available' case:
161#
162$(call feature_check,all,$(MSG))
163
164#
165# Just in case the build freshly failed, make sure we print the
166# feature matrix:
167#
168ifeq ($(feature-all), 0)
169 test-all-failed := 1
170endif
171
172ifeq ($(test-all-failed),1)
173 $(info )
174 $(info Auto-detecting system features:)
175endif
176
177ifeq ($(feature-all), 1)
178 #
179 # test-all.c passed - just set all the core feature flags to 1:
180 #
181 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat)))
182else
183 $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(CORE_FEATURE_TESTS) >/dev/null 2>&1)
184 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat)))
185endif
186
187#
188# Print the result of the feature test:
189#
190feature_print = $(eval $(feature_print_code)) $(info $(MSG))
191
192define feature_print_code
193 ifeq ($(feature-$(1)), 1)
194 MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(1))
195 else
196 MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1))
197 endif
198endef
199
200#
201# Only print out our features if we rebuilt the testcases or if a test failed:
202#
203ifeq ($(test-all-failed), 1)
204 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_print,$(feat)))
205 $(info )
98endif 206endif
99 207
100ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y) 208ifeq ($(feature-stackprotector-all), 1)
101 CFLAGS += -Wvolatile-register-var 209 CFLAGS += -fstack-protector-all
102endif 210endif
103 211
104ifndef PERF_DEBUG 212ifeq ($(feature-stackprotector), 1)
105 ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -D_FORTIFY_SOURCE=2,-D_FORTIFY_SOURCE=2),y) 213 CFLAGS += -Wstack-protector
214endif
215
216ifeq ($(DEBUG),0)
217 ifeq ($(feature-fortify-source), 1)
106 CFLAGS += -D_FORTIFY_SOURCE=2 218 CFLAGS += -D_FORTIFY_SOURCE=2
107 endif 219 endif
108endif 220endif
@@ -128,120 +240,121 @@ CFLAGS += -I$(LIB_INCLUDE)
128CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 240CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
129 241
130ifndef NO_BIONIC 242ifndef NO_BIONIC
131ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y) 243 $(call feature_check,bionic)
132 BIONIC := 1 244 ifeq ($(feature-bionic), 1)
133 EXTLIBS := $(filter-out -lrt,$(EXTLIBS)) 245 BIONIC := 1
134 EXTLIBS := $(filter-out -lpthread,$(EXTLIBS)) 246 EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
247 EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
248 endif
135endif 249endif
136endif # NO_BIONIC
137 250
138ifdef NO_LIBELF 251ifdef NO_LIBELF
139 NO_DWARF := 1 252 NO_DWARF := 1
140 NO_DEMANGLE := 1 253 NO_DEMANGLE := 1
141 NO_LIBUNWIND := 1 254 NO_LIBUNWIND := 1
142else 255else
143FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) 256 ifeq ($(feature-libelf), 0)
144ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y) 257 ifeq ($(feature-glibc), 1)
145 FLAGS_GLIBC=$(CFLAGS) $(LDFLAGS) 258 LIBC_SUPPORT := 1
146 ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y) 259 endif
147 LIBC_SUPPORT := 1 260 ifeq ($(BIONIC),1)
148 endif 261 LIBC_SUPPORT := 1
149 ifeq ($(BIONIC),1) 262 endif
150 LIBC_SUPPORT := 1 263 ifeq ($(LIBC_SUPPORT),1)
151 endif 264 msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
152 ifeq ($(LIBC_SUPPORT),1)
153 msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
154 265
155 NO_LIBELF := 1 266 NO_LIBELF := 1
156 NO_DWARF := 1 267 NO_DWARF := 1
157 NO_DEMANGLE := 1 268 NO_DEMANGLE := 1
269 else
270 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
271 endif
158 else 272 else
159 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 273 # for linking with debug library, run like:
160 endif 274 # make DEBUG=1 LIBDW_DIR=/opt/libdw/
161else 275 ifdef LIBDW_DIR
162 # for linking with debug library, run like: 276 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
163 # make DEBUG=1 LIBDW_DIR=/opt/libdw/ 277 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
164 ifdef LIBDW_DIR 278 endif
165 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
166 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
167 endif
168 279
169 FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lz -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS) 280 ifneq ($(feature-dwarf), 1)
170 ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y) 281 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
171 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); 282 NO_DWARF := 1
172 NO_DWARF := 1 283 endif # Dwarf support
173 endif # Dwarf support 284 endif # libelf support
174endif # SOURCE_LIBELF
175endif # NO_LIBELF 285endif # NO_LIBELF
176 286
177ifndef NO_LIBELF 287ifndef NO_LIBELF
178CFLAGS += -DLIBELF_SUPPORT 288 CFLAGS += -DHAVE_LIBELF_SUPPORT
179FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
180ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
181 CFLAGS += -DLIBELF_MMAP
182endif
183ifeq ($(call try-cc,$(SOURCE_ELF_GETPHDRNUM),$(FLAGS_LIBELF),-DHAVE_ELF_GETPHDRNUM),y)
184 CFLAGS += -DHAVE_ELF_GETPHDRNUM
185endif
186 289
187# include ARCH specific config 290 ifeq ($(feature-libelf-mmap), 1)
188-include $(src-perf)/arch/$(ARCH)/Makefile 291 CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT
292 endif
189 293
190ifndef NO_DWARF 294 ifeq ($(feature-libelf-getphdrnum), 1)
191ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) 295 CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT
192 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); 296 endif
193 NO_DWARF := 1
194else
195 CFLAGS += -DDWARF_SUPPORT $(LIBDW_CFLAGS)
196 LDFLAGS += $(LIBDW_LDFLAGS)
197 EXTLIBS += -lelf -ldw
198endif # PERF_HAVE_DWARF_REGS
199endif # NO_DWARF
200 297
201endif # NO_LIBELF 298 # include ARCH specific config
299 -include $(src-perf)/arch/$(ARCH)/Makefile
202 300
203ifndef NO_LIBELF 301 ifndef NO_DWARF
204CFLAGS += -DLIBELF_SUPPORT 302 ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
205FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) 303 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
206ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y) 304 NO_DWARF := 1
207 CFLAGS += -DLIBELF_MMAP 305 else
208endif # try-cc 306 CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS)
307 LDFLAGS += $(LIBDW_LDFLAGS)
308 EXTLIBS += -lelf -ldw
309 endif # PERF_HAVE_DWARF_REGS
310 endif # NO_DWARF
209endif # NO_LIBELF 311endif # NO_LIBELF
210 312
211# There's only x86 (both 32 and 64) support for CFI unwind so far 313ifeq ($(LIBUNWIND_LIBS),)
212ifneq ($(ARCH),x86)
213 NO_LIBUNWIND := 1 314 NO_LIBUNWIND := 1
214endif 315endif
215 316
216ifndef NO_LIBUNWIND 317ifndef NO_LIBUNWIND
217# for linking with debug library, run like: 318 #
218# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ 319 # For linking with debug library, run like:
219ifdef LIBUNWIND_DIR 320 #
220 LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include 321 # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
221 LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib 322 #
222endif 323 ifdef LIBUNWIND_DIR
324 LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
325 LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
326 endif
223 327
224FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(CFLAGS) $(LIBUNWIND_LDFLAGS) $(LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS) 328 ifneq ($(feature-libunwind), 1)
225ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y) 329 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1);
226 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99); 330 NO_LIBUNWIND := 1
227 NO_LIBUNWIND := 1 331 else
228endif # Libunwind support 332 ifeq ($(ARCH),arm)
229endif # NO_LIBUNWIND 333 $(call feature_check,libunwind-debug-frame)
334 ifneq ($(feature-libunwind-debug-frame), 1)
335 msg := $(warning No debug_frame support found in libunwind);
336 CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
337 endif
338 else
339 # non-ARM has no dwarf_find_debug_frame() function:
340 CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
341 endif
342 endif
343endif
230 344
231ifndef NO_LIBUNWIND 345ifndef NO_LIBUNWIND
232 CFLAGS += -DLIBUNWIND_SUPPORT 346 CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
233 EXTLIBS += $(LIBUNWIND_LIBS) 347 EXTLIBS += $(LIBUNWIND_LIBS)
234 CFLAGS += $(LIBUNWIND_CFLAGS) 348 CFLAGS += $(LIBUNWIND_CFLAGS)
235 LDFLAGS += $(LIBUNWIND_LDFLAGS) 349 LDFLAGS += $(LIBUNWIND_LDFLAGS)
236endif # NO_LIBUNWIND 350endif
237 351
238ifndef NO_LIBAUDIT 352ifndef NO_LIBAUDIT
239 FLAGS_LIBAUDIT = $(CFLAGS) $(LDFLAGS) -laudit 353 ifneq ($(feature-libaudit), 1)
240 ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
241 msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); 354 msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
242 NO_LIBAUDIT := 1 355 NO_LIBAUDIT := 1
243 else 356 else
244 CFLAGS += -DLIBAUDIT_SUPPORT 357 CFLAGS += -DHAVE_LIBAUDIT_SUPPORT
245 EXTLIBS += -laudit 358 EXTLIBS += -laudit
246 endif 359 endif
247endif 360endif
@@ -251,30 +364,30 @@ ifdef NO_NEWT
251endif 364endif
252 365
253ifndef NO_SLANG 366ifndef NO_SLANG
254 FLAGS_SLANG=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang 367 ifneq ($(feature-libslang), 1)
255 ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y)
256 msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev); 368 msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev);
257 NO_SLANG := 1 369 NO_SLANG := 1
258 else 370 else
259 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h 371 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
260 CFLAGS += -I/usr/include/slang 372 CFLAGS += -I/usr/include/slang
261 CFLAGS += -DSLANG_SUPPORT 373 CFLAGS += -DHAVE_SLANG_SUPPORT
262 EXTLIBS += -lslang 374 EXTLIBS += -lslang
263 endif 375 endif
264endif 376endif
265 377
266ifndef NO_GTK2 378ifndef NO_GTK2
267 FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) 379 FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
268 ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y) 380 ifneq ($(feature-gtk2), 1)
269 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); 381 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
270 NO_GTK2 := 1 382 NO_GTK2 := 1
271 else 383 else
272 ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y) 384 ifeq ($(feature-gtk2-infobar), 1)
273 CFLAGS += -DHAVE_GTK_INFO_BAR 385 GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT
274 endif 386 endif
275 CFLAGS += -DGTK2_SUPPORT 387 CFLAGS += -DHAVE_GTK2_SUPPORT
276 CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) 388 GTK_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
277 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) 389 GTK_LIBS := $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
390 EXTLIBS += -ldl
278 endif 391 endif
279endif 392endif
280 393
@@ -290,7 +403,7 @@ else
290 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 403 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
291 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) 404 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
292 405
293 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y) 406 ifneq ($(feature-libperl), 1)
294 CFLAGS += -DNO_LIBPERL 407 CFLAGS += -DNO_LIBPERL
295 NO_LIBPERL := 1 408 NO_LIBPERL := 1
296 else 409 else
@@ -299,6 +412,12 @@ else
299 endif 412 endif
300endif 413endif
301 414
415ifeq ($(feature-timerfd), 1)
416 CFLAGS += -DHAVE_TIMERFD_SUPPORT
417else
418 msg := $(warning No timerfd support. Disables 'perf kvm stat live');
419endif
420
302disable-python = $(eval $(disable-python_code)) 421disable-python = $(eval $(disable-python_code))
303define disable-python_code 422define disable-python_code
304 CFLAGS += -DNO_LIBPYTHON 423 CFLAGS += -DNO_LIBPYTHON
@@ -335,11 +454,11 @@ else
335 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) 454 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
336 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 455 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
337 456
338 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y) 457 ifneq ($(feature-libpython), 1)
339 $(call disable-python,Python.h (for Python 2.x)) 458 $(call disable-python,Python.h (for Python 2.x))
340 else 459 else
341 460
342 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y) 461 ifneq ($(feature-libpython-version), 1)
343 $(warning Python 3 is not yet supported; please set) 462 $(warning Python 3 is not yet supported; please set)
344 $(warning PYTHON and/or PYTHON_CONFIG appropriately.) 463 $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
345 $(warning If you also have Python 2 installed, then) 464 $(warning If you also have Python 2 installed, then)
@@ -362,33 +481,30 @@ else
362 endif 481 endif
363endif 482endif
364 483
484ifeq ($(feature-libbfd), 1)
485 EXTLIBS += -lbfd
486endif
487
365ifdef NO_DEMANGLE 488ifdef NO_DEMANGLE
366 CFLAGS += -DNO_DEMANGLE 489 CFLAGS += -DNO_DEMANGLE
367else 490else
368 ifdef HAVE_CPLUS_DEMANGLE 491 ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
369 EXTLIBS += -liberty 492 EXTLIBS += -liberty
370 CFLAGS += -DHAVE_CPLUS_DEMANGLE 493 CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
371 else 494 else
372 FLAGS_BFD=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd 495 ifneq ($(feature-libbfd), 1)
373 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd) 496 $(call feature_check,liberty)
374 ifeq ($(has_bfd),y) 497 ifeq ($(feature-liberty), 1)
375 EXTLIBS += -lbfd
376 else
377 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
378 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
379 ifeq ($(has_bfd_iberty),y)
380 EXTLIBS += -lbfd -liberty 498 EXTLIBS += -lbfd -liberty
381 else 499 else
382 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz 500 $(call feature_check,liberty-z)
383 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz) 501 ifeq ($(feature-liberty-z), 1)
384 ifeq ($(has_bfd_iberty_z),y)
385 EXTLIBS += -lbfd -liberty -lz 502 EXTLIBS += -lbfd -liberty -lz
386 else 503 else
387 FLAGS_CPLUS_DEMANGLE=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -liberty 504 $(call feature_check,cplus-demangle)
388 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle) 505 ifeq ($(feature-cplus-demangle), 1)
389 ifeq ($(has_cplus_demangle),y)
390 EXTLIBS += -liberty 506 EXTLIBS += -liberty
391 CFLAGS += -DHAVE_CPLUS_DEMANGLE 507 CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
392 else 508 else
393 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) 509 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
394 CFLAGS += -DNO_DEMANGLE 510 CFLAGS += -DNO_DEMANGLE
@@ -399,31 +515,28 @@ else
399 endif 515 endif
400endif 516endif
401 517
402ifndef NO_STRLCPY 518ifneq ($(filter -lbfd,$(EXTLIBS)),)
403 ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y) 519 CFLAGS += -DHAVE_LIBBFD_SUPPORT
404 CFLAGS += -DHAVE_STRLCPY
405 endif
406endif 520endif
407 521
408ifndef NO_ON_EXIT 522ifndef NO_ON_EXIT
409 ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y) 523 ifeq ($(feature-on-exit), 1)
410 CFLAGS += -DHAVE_ON_EXIT 524 CFLAGS += -DHAVE_ON_EXIT_SUPPORT
411 endif 525 endif
412endif 526endif
413 527
414ifndef NO_BACKTRACE 528ifndef NO_BACKTRACE
415 ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y) 529 ifeq ($(feature-backtrace), 1)
416 CFLAGS += -DBACKTRACE_SUPPORT 530 CFLAGS += -DHAVE_BACKTRACE_SUPPORT
417 endif 531 endif
418endif 532endif
419 533
420ifndef NO_LIBNUMA 534ifndef NO_LIBNUMA
421 FLAGS_LIBNUMA = $(CFLAGS) $(LDFLAGS) -lnuma 535 ifeq ($(feature-libnuma), 0)
422 ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y)
423 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev); 536 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev);
424 NO_LIBNUMA := 1 537 NO_LIBNUMA := 1
425 else 538 else
426 CFLAGS += -DLIBNUMA_SUPPORT 539 CFLAGS += -DHAVE_LIBNUMA_SUPPORT
427 EXTLIBS += -lnuma 540 EXTLIBS += -lnuma
428 endif 541 endif
429endif 542endif
@@ -459,7 +572,12 @@ else
459sysconfdir = $(prefix)/etc 572sysconfdir = $(prefix)/etc
460ETC_PERFCONFIG = etc/perfconfig 573ETC_PERFCONFIG = etc/perfconfig
461endif 574endif
575ifeq ($(IS_X86_64),1)
576lib = lib64
577else
462lib = lib 578lib = lib
579endif
580libdir = $(prefix)/$(lib)
463 581
464# Shell quote (do not use $(call) to accommodate ancient setups); 582# Shell quote (do not use $(call) to accommodate ancient setups);
465ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) 583ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
@@ -472,6 +590,7 @@ template_dir_SQ = $(subst ','\'',$(template_dir))
472htmldir_SQ = $(subst ','\'',$(htmldir)) 590htmldir_SQ = $(subst ','\'',$(htmldir))
473prefix_SQ = $(subst ','\'',$(prefix)) 591prefix_SQ = $(subst ','\'',$(prefix))
474sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) 592sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
593libdir_SQ = $(subst ','\'',$(libdir))
475 594
476ifneq ($(filter /%,$(firstword $(perfexecdir))),) 595ifneq ($(filter /%,$(firstword $(perfexecdir))),)
477perfexec_instdir = $(perfexecdir) 596perfexec_instdir = $(perfexecdir)
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
new file mode 100644
index 000000000000..87e790017c69
--- /dev/null
+++ b/tools/perf/config/feature-checks/Makefile
@@ -0,0 +1,152 @@
1
2FILES= \
3 test-all \
4 test-backtrace \
5 test-bionic \
6 test-dwarf \
7 test-fortify-source \
8 test-glibc \
9 test-gtk2 \
10 test-gtk2-infobar \
11 test-hello \
12 test-libaudit \
13 test-libbfd \
14 test-liberty \
15 test-liberty-z \
16 test-cplus-demangle \
17 test-libelf \
18 test-libelf-getphdrnum \
19 test-libelf-mmap \
20 test-libnuma \
21 test-libperl \
22 test-libpython \
23 test-libpython-version \
24 test-libslang \
25 test-libunwind \
26 test-libunwind-debug-frame \
27 test-on-exit \
28 test-stackprotector-all \
29 test-stackprotector \
30 test-timerfd
31
32CC := $(CC) -MD
33
34all: $(FILES)
35
36BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c
37
38###############################
39
40test-all:
41 $(BUILD) -Werror -fstack-protector -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
42
43test-hello:
44 $(BUILD)
45
46test-stackprotector-all:
47 $(BUILD) -Werror -fstack-protector-all
48
49test-stackprotector:
50 $(BUILD) -Werror -fstack-protector -Wstack-protector
51
52test-fortify-source:
53 $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2
54
55test-bionic:
56 $(BUILD)
57
58test-libelf:
59 $(BUILD) -lelf
60
61test-glibc:
62 $(BUILD)
63
64test-dwarf:
65 $(BUILD) -ldw
66
67test-libelf-mmap:
68 $(BUILD) -lelf
69
70test-libelf-getphdrnum:
71 $(BUILD) -lelf
72
73test-libnuma:
74 $(BUILD) -lnuma
75
76test-libunwind:
77 $(BUILD) $(LIBUNWIND_LIBS) -lelf
78
79test-libunwind-debug-frame:
80 $(BUILD) $(LIBUNWIND_LIBS) -lelf
81
82test-libaudit:
83 $(BUILD) -laudit
84
85test-libslang:
86 $(BUILD) -I/usr/include/slang -lslang
87
88test-gtk2:
89 $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
90
91test-gtk2-infobar:
92 $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
93
94grep-libs = $(filter -l%,$(1))
95strip-libs = $(filter-out -l%,$(1))
96
97PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
98PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
99PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
100PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
101FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
102
103test-libperl:
104 $(BUILD) $(FLAGS_PERL_EMBED)
105
106override PYTHON := python
107override PYTHON_CONFIG := python-config
108
109escape-for-shell-sq = $(subst ','\'',$(1))
110shell-sq = '$(escape-for-shell-sq)'
111
112PYTHON_CONFIG_SQ = $(call shell-sq,$(PYTHON_CONFIG))
113
114PYTHON_EMBED_LDOPTS = $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
115PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
116PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
117PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
118FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
119
120test-libpython:
121 $(BUILD) $(FLAGS_PYTHON_EMBED)
122
123test-libpython-version:
124 $(BUILD) $(FLAGS_PYTHON_EMBED)
125
126test-libbfd:
127 $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
128
129test-liberty:
130 $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty
131
132test-liberty-z:
133 $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz
134
135test-cplus-demangle:
136 $(BUILD) -liberty
137
138test-on-exit:
139 $(BUILD)
140
141test-backtrace:
142 $(BUILD)
143
144test-timerfd:
145 $(BUILD)
146
147-include *.d
148
149###############################
150
151clean:
152 rm -f $(FILES) *.d
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
new file mode 100644
index 000000000000..59e7a705e146
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -0,0 +1,111 @@
1/*
2 * test-all.c: Try to build all the main testcases at once.
3 *
4 * A well-configured system will have all the prereqs installed, so we can speed
5 * up auto-detection on such systems.
6 */
7
8/*
9 * Quirk: Python and Perl headers cannot be in arbitrary places, so keep
10 * these 3 testcases at the top:
11 */
12#define main main_test_libpython
13# include "test-libpython.c"
14#undef main
15
16#define main main_test_libpython_version
17# include "test-libpython-version.c"
18#undef main
19
20#define main main_test_libperl
21# include "test-libperl.c"
22#undef main
23
24#define main main_test_hello
25# include "test-hello.c"
26#undef main
27
28#define main main_test_libelf
29# include "test-libelf.c"
30#undef main
31
32#define main main_test_libelf_mmap
33# include "test-libelf-mmap.c"
34#undef main
35
36#define main main_test_glibc
37# include "test-glibc.c"
38#undef main
39
40#define main main_test_dwarf
41# include "test-dwarf.c"
42#undef main
43
44#define main main_test_libelf_getphdrnum
45# include "test-libelf-getphdrnum.c"
46#undef main
47
48#define main main_test_libunwind
49# include "test-libunwind.c"
50#undef main
51
52#define main main_test_libaudit
53# include "test-libaudit.c"
54#undef main
55
56#define main main_test_libslang
57# include "test-libslang.c"
58#undef main
59
60#define main main_test_gtk2
61# include "test-gtk2.c"
62#undef main
63
64#define main main_test_gtk2_infobar
65# include "test-gtk2-infobar.c"
66#undef main
67
68#define main main_test_libbfd
69# include "test-libbfd.c"
70#undef main
71
72#define main main_test_on_exit
73# include "test-on-exit.c"
74#undef main
75
76#define main main_test_backtrace
77# include "test-backtrace.c"
78#undef main
79
80#define main main_test_libnuma
81# include "test-libnuma.c"
82#undef main
83
84#define main main_test_timerfd
85# include "test-timerfd.c"
86#undef main
87
88int main(int argc, char *argv[])
89{
90 main_test_libpython();
91 main_test_libpython_version();
92 main_test_libperl();
93 main_test_hello();
94 main_test_libelf();
95 main_test_libelf_mmap();
96 main_test_glibc();
97 main_test_dwarf();
98 main_test_libelf_getphdrnum();
99 main_test_libunwind();
100 main_test_libaudit();
101 main_test_libslang();
102 main_test_gtk2(argc, argv);
103 main_test_gtk2_infobar(argc, argv);
104 main_test_libbfd();
105 main_test_on_exit();
106 main_test_backtrace();
107 main_test_libnuma();
108 main_test_timerfd();
109
110 return 0;
111}
diff --git a/tools/perf/config/feature-checks/test-backtrace.c b/tools/perf/config/feature-checks/test-backtrace.c
new file mode 100644
index 000000000000..7124aa1dc8fb
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-backtrace.c
@@ -0,0 +1,13 @@
1#include <execinfo.h>
2#include <stdio.h>
3
4int main(void)
5{
6 void *backtrace_fns[10];
7 size_t entries;
8
9 entries = backtrace(backtrace_fns, 10);
10 backtrace_symbols_fd(backtrace_fns, entries, 1);
11
12 return 0;
13}
diff --git a/tools/perf/config/feature-checks/test-bionic.c b/tools/perf/config/feature-checks/test-bionic.c
new file mode 100644
index 000000000000..eac24e9513eb
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-bionic.c
@@ -0,0 +1,6 @@
1#include <android/api-level.h>
2
3int main(void)
4{
5 return __ANDROID_API__;
6}
diff --git a/tools/perf/config/feature-checks/test-cplus-demangle.c b/tools/perf/config/feature-checks/test-cplus-demangle.c
new file mode 100644
index 000000000000..610c686e0009
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-cplus-demangle.c
@@ -0,0 +1,14 @@
1extern int printf(const char *format, ...);
2extern char *cplus_demangle(const char *, int);
3
4int main(void)
5{
6 char symbol[4096] = "FieldName__9ClassNameFd";
7 char *tmp;
8
9 tmp = cplus_demangle(symbol, 0);
10
11 printf("demangled symbol: {%s}\n", tmp);
12
13 return 0;
14}
diff --git a/tools/perf/config/feature-checks/test-dwarf.c b/tools/perf/config/feature-checks/test-dwarf.c
new file mode 100644
index 000000000000..3fc1801ce4a9
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-dwarf.c
@@ -0,0 +1,10 @@
1#include <dwarf.h>
2#include <elfutils/libdw.h>
3#include <elfutils/version.h>
4
5int main(void)
6{
7 Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
8
9 return (long)dbg;
10}
diff --git a/tools/perf/config/feature-checks/test-fortify-source.c b/tools/perf/config/feature-checks/test-fortify-source.c
new file mode 100644
index 000000000000..c9f398d87868
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-fortify-source.c
@@ -0,0 +1,6 @@
1#include <stdio.h>
2
3int main(void)
4{
5 return puts("hi");
6}
diff --git a/tools/perf/config/feature-checks/test-glibc.c b/tools/perf/config/feature-checks/test-glibc.c
new file mode 100644
index 000000000000..b0820345cd98
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-glibc.c
@@ -0,0 +1,8 @@
1#include <gnu/libc-version.h>
2
3int main(void)
4{
5 const char *version = gnu_get_libc_version();
6
7 return (long)version;
8}
diff --git a/tools/perf/config/feature-checks/test-gtk2-infobar.c b/tools/perf/config/feature-checks/test-gtk2-infobar.c
new file mode 100644
index 000000000000..397b4646d066
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-gtk2-infobar.c
@@ -0,0 +1,11 @@
1#pragma GCC diagnostic ignored "-Wstrict-prototypes"
2#include <gtk/gtk.h>
3#pragma GCC diagnostic error "-Wstrict-prototypes"
4
5int main(int argc, char *argv[])
6{
7 gtk_init(&argc, &argv);
8 gtk_info_bar_new();
9
10 return 0;
11}
diff --git a/tools/perf/config/feature-checks/test-gtk2.c b/tools/perf/config/feature-checks/test-gtk2.c
new file mode 100644
index 000000000000..6bd80e509439
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-gtk2.c
@@ -0,0 +1,10 @@
1#pragma GCC diagnostic ignored "-Wstrict-prototypes"
2#include <gtk/gtk.h>
3#pragma GCC diagnostic error "-Wstrict-prototypes"
4
5int main(int argc, char *argv[])
6{
7 gtk_init(&argc, &argv);
8
9 return 0;
10}
diff --git a/tools/perf/config/feature-checks/test-hello.c b/tools/perf/config/feature-checks/test-hello.c
new file mode 100644
index 000000000000..c9f398d87868
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-hello.c
@@ -0,0 +1,6 @@
1#include <stdio.h>
2
3int main(void)
4{
5 return puts("hi");
6}
diff --git a/tools/perf/config/feature-checks/test-libaudit.c b/tools/perf/config/feature-checks/test-libaudit.c
new file mode 100644
index 000000000000..afc019f08641
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libaudit.c
@@ -0,0 +1,10 @@
1#include <libaudit.h>
2
3extern int printf(const char *format, ...);
4
5int main(void)
6{
7 printf("error message: %s\n", audit_errno_to_name(0));
8
9 return audit_open();
10}
diff --git a/tools/perf/config/feature-checks/test-libbfd.c b/tools/perf/config/feature-checks/test-libbfd.c
new file mode 100644
index 000000000000..24059907e990
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libbfd.c
@@ -0,0 +1,15 @@
1#include <bfd.h>
2
3extern int printf(const char *format, ...);
4
5int main(void)
6{
7 char symbol[4096] = "FieldName__9ClassNameFd";
8 char *tmp;
9
10 tmp = bfd_demangle(0, symbol, 0);
11
12 printf("demangled symbol: {%s}\n", tmp);
13
14 return 0;
15}
diff --git a/tools/perf/config/feature-checks/test-libelf-getphdrnum.c b/tools/perf/config/feature-checks/test-libelf-getphdrnum.c
new file mode 100644
index 000000000000..d710459306c3
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libelf-getphdrnum.c
@@ -0,0 +1,8 @@
1#include <libelf.h>
2
3int main(void)
4{
5 size_t dst;
6
7 return elf_getphdrnum(0, &dst);
8}
diff --git a/tools/perf/config/feature-checks/test-libelf-mmap.c b/tools/perf/config/feature-checks/test-libelf-mmap.c
new file mode 100644
index 000000000000..564427d7ef18
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libelf-mmap.c
@@ -0,0 +1,8 @@
1#include <libelf.h>
2
3int main(void)
4{
5 Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0);
6
7 return (long)elf;
8}
diff --git a/tools/perf/config/feature-checks/test-libelf.c b/tools/perf/config/feature-checks/test-libelf.c
new file mode 100644
index 000000000000..08db322d8957
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libelf.c
@@ -0,0 +1,8 @@
1#include <libelf.h>
2
3int main(void)
4{
5 Elf *elf = elf_begin(0, ELF_C_READ, 0);
6
7 return (long)elf;
8}
diff --git a/tools/perf/config/feature-checks/test-libnuma.c b/tools/perf/config/feature-checks/test-libnuma.c
new file mode 100644
index 000000000000..4763d9cd587d
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libnuma.c
@@ -0,0 +1,9 @@
1#include <numa.h>
2#include <numaif.h>
3
4int main(void)
5{
6 numa_available();
7
8 return 0;
9}
diff --git a/tools/perf/config/feature-checks/test-libperl.c b/tools/perf/config/feature-checks/test-libperl.c
new file mode 100644
index 000000000000..8871f6a0fdb4
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libperl.c
@@ -0,0 +1,9 @@
1#include <EXTERN.h>
2#include <perl.h>
3
4int main(void)
5{
6 perl_alloc();
7
8 return 0;
9}
diff --git a/tools/perf/config/feature-checks/test-libpython-version.c b/tools/perf/config/feature-checks/test-libpython-version.c
new file mode 100644
index 000000000000..facea122d812
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libpython-version.c
@@ -0,0 +1,10 @@
1#include <Python.h>
2
3#if PY_VERSION_HEX >= 0x03000000
4 #error
5#endif
6
7int main(void)
8{
9 return 0;
10}
diff --git a/tools/perf/config/feature-checks/test-libpython.c b/tools/perf/config/feature-checks/test-libpython.c
new file mode 100644
index 000000000000..b24b28ad6324
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libpython.c
@@ -0,0 +1,8 @@
1#include <Python.h>
2
3int main(void)
4{
5 Py_Initialize();
6
7 return 0;
8}
diff --git a/tools/perf/config/feature-checks/test-libslang.c b/tools/perf/config/feature-checks/test-libslang.c
new file mode 100644
index 000000000000..22ff22ed94d1
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libslang.c
@@ -0,0 +1,6 @@
1#include <slang.h>
2
3int main(void)
4{
5 return SLsmg_init_smg();
6}
diff --git a/tools/perf/config/feature-checks/test-libunwind-debug-frame.c b/tools/perf/config/feature-checks/test-libunwind-debug-frame.c
new file mode 100644
index 000000000000..0ef8087a104a
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libunwind-debug-frame.c
@@ -0,0 +1,16 @@
1#include <libunwind.h>
2#include <stdlib.h>
3
4extern int
5UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
6 unw_word_t ip, unw_word_t segbase,
7 const char *obj_name, unw_word_t start,
8 unw_word_t end);
9
10#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
11
12int main(void)
13{
14 dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0);
15 return 0;
16}
diff --git a/tools/perf/config/feature-checks/test-libunwind.c b/tools/perf/config/feature-checks/test-libunwind.c
new file mode 100644
index 000000000000..43b9369bcab7
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libunwind.c
@@ -0,0 +1,27 @@
1#include <libunwind.h>
2#include <stdlib.h>
3
4extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
5 unw_word_t ip,
6 unw_dyn_info_t *di,
7 unw_proc_info_t *pi,
8 int need_unwind_info, void *arg);
9
10
11#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
12
13static unw_accessors_t accessors;
14
15int main(void)
16{
17 unw_addr_space_t addr_space;
18
19 addr_space = unw_create_addr_space(&accessors, 0);
20 if (addr_space)
21 return 0;
22
23 unw_init_remote(NULL, addr_space, NULL);
24 dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
25
26 return 0;
27}
diff --git a/tools/perf/config/feature-checks/test-on-exit.c b/tools/perf/config/feature-checks/test-on-exit.c
new file mode 100644
index 000000000000..8e88b16e6ded
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-on-exit.c
@@ -0,0 +1,16 @@
1#include <stdio.h>
2#include <stdlib.h>
3
4static void exit_fn(int status, void *__data)
5{
6 printf("exit status: %d, data: %d\n", status, *(int *)__data);
7}
8
9static int data = 123;
10
11int main(void)
12{
13 on_exit(exit_fn, &data);
14
15 return 321;
16}
diff --git a/tools/perf/config/feature-checks/test-stackprotector-all.c b/tools/perf/config/feature-checks/test-stackprotector-all.c
new file mode 100644
index 000000000000..c9f398d87868
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-stackprotector-all.c
@@ -0,0 +1,6 @@
1#include <stdio.h>
2
3int main(void)
4{
5 return puts("hi");
6}
diff --git a/tools/perf/config/feature-checks/test-stackprotector.c b/tools/perf/config/feature-checks/test-stackprotector.c
new file mode 100644
index 000000000000..c9f398d87868
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-stackprotector.c
@@ -0,0 +1,6 @@
1#include <stdio.h>
2
3int main(void)
4{
5 return puts("hi");
6}
diff --git a/tools/perf/config/feature-checks/test-timerfd.c b/tools/perf/config/feature-checks/test-timerfd.c
new file mode 100644
index 000000000000..8c5c083b4d3c
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-timerfd.c
@@ -0,0 +1,18 @@
1/*
2 * test for timerfd functions used by perf-kvm-stat-live
3 */
4#include <sys/timerfd.h>
5
6int main(void)
7{
8 struct itimerspec new_value;
9
10 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
11 if (fd < 0)
12 return 1;
13
14 if (timerfd_settime(fd, 0, &new_value, NULL) != 0)
15 return 1;
16
17 return 0;
18}
diff --git a/tools/perf/config/feature-checks/test-volatile-register-var.c b/tools/perf/config/feature-checks/test-volatile-register-var.c
new file mode 100644
index 000000000000..c9f398d87868
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-volatile-register-var.c
@@ -0,0 +1,6 @@
1#include <stdio.h>
2
3int main(void)
4{
5 return puts("hi");
6}
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
deleted file mode 100644
index f79305739ecc..000000000000
--- a/tools/perf/config/feature-tests.mak
+++ /dev/null
@@ -1,246 +0,0 @@
1define SOURCE_HELLO
2#include <stdio.h>
3int main(void)
4{
5 return puts(\"hi\");
6}
7endef
8
9ifndef NO_DWARF
10define SOURCE_DWARF
11#include <dwarf.h>
12#include <elfutils/libdw.h>
13#include <elfutils/version.h>
14#ifndef _ELFUTILS_PREREQ
15#error
16#endif
17
18int main(void)
19{
20 Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
21 return (long)dbg;
22}
23endef
24endif
25
26define SOURCE_LIBELF
27#include <libelf.h>
28
29int main(void)
30{
31 Elf *elf = elf_begin(0, ELF_C_READ, 0);
32 return (long)elf;
33}
34endef
35
36define SOURCE_GLIBC
37#include <gnu/libc-version.h>
38
39int main(void)
40{
41 const char *version = gnu_get_libc_version();
42 return (long)version;
43}
44endef
45
46define SOURCE_BIONIC
47#include <android/api-level.h>
48
49int main(void)
50{
51 return __ANDROID_API__;
52}
53endef
54
55define SOURCE_ELF_MMAP
56#include <libelf.h>
57int main(void)
58{
59 Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0);
60 return (long)elf;
61}
62endef
63
64define SOURCE_ELF_GETPHDRNUM
65#include <libelf.h>
66int main(void)
67{
68 size_t dst;
69 return elf_getphdrnum(0, &dst);
70}
71endef
72
73ifndef NO_SLANG
74define SOURCE_SLANG
75#include <slang.h>
76
77int main(void)
78{
79 return SLsmg_init_smg();
80}
81endef
82endif
83
84ifndef NO_GTK2
85define SOURCE_GTK2
86#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
87#include <gtk/gtk.h>
88#pragma GCC diagnostic error \"-Wstrict-prototypes\"
89
90int main(int argc, char *argv[])
91{
92 gtk_init(&argc, &argv);
93
94 return 0;
95}
96endef
97
98define SOURCE_GTK2_INFOBAR
99#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
100#include <gtk/gtk.h>
101#pragma GCC diagnostic error \"-Wstrict-prototypes\"
102
103int main(void)
104{
105 gtk_info_bar_new();
106
107 return 0;
108}
109endef
110endif
111
112ifndef NO_LIBPERL
113define SOURCE_PERL_EMBED
114#include <EXTERN.h>
115#include <perl.h>
116
117int main(void)
118{
119perl_alloc();
120return 0;
121}
122endef
123endif
124
125ifndef NO_LIBPYTHON
126define SOURCE_PYTHON_VERSION
127#include <Python.h>
128#if PY_VERSION_HEX >= 0x03000000
129 #error
130#endif
131int main(void)
132{
133 return 0;
134}
135endef
136define SOURCE_PYTHON_EMBED
137#include <Python.h>
138int main(void)
139{
140 Py_Initialize();
141 return 0;
142}
143endef
144endif
145
146define SOURCE_BFD
147#include <bfd.h>
148
149int main(void)
150{
151 bfd_demangle(0, 0, 0);
152 return 0;
153}
154endef
155
156define SOURCE_CPLUS_DEMANGLE
157extern char *cplus_demangle(const char *, int);
158
159int main(void)
160{
161 cplus_demangle(0, 0);
162 return 0;
163}
164endef
165
166define SOURCE_STRLCPY
167#include <stdlib.h>
168extern size_t strlcpy(char *dest, const char *src, size_t size);
169
170int main(void)
171{
172 strlcpy(NULL, NULL, 0);
173 return 0;
174}
175endef
176
177ifndef NO_LIBUNWIND
178define SOURCE_LIBUNWIND
179#include <libunwind.h>
180#include <stdlib.h>
181
182extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
183 unw_word_t ip,
184 unw_dyn_info_t *di,
185 unw_proc_info_t *pi,
186 int need_unwind_info, void *arg);
187
188
189#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
190
191int main(void)
192{
193 unw_addr_space_t addr_space;
194 addr_space = unw_create_addr_space(NULL, 0);
195 unw_init_remote(NULL, addr_space, NULL);
196 dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
197 return 0;
198}
199endef
200endif
201
202ifndef NO_BACKTRACE
203define SOURCE_BACKTRACE
204#include <execinfo.h>
205#include <stdio.h>
206
207int main(void)
208{
209 backtrace(NULL, 0);
210 backtrace_symbols(NULL, 0);
211 return 0;
212}
213endef
214endif
215
216ifndef NO_LIBAUDIT
217define SOURCE_LIBAUDIT
218#include <libaudit.h>
219
220int main(void)
221{
222 printf(\"error message: %s\", audit_errno_to_name(0));
223 return audit_open();
224}
225endef
226endif
227
228define SOURCE_ON_EXIT
229#include <stdio.h>
230
231int main(void)
232{
233 return on_exit(NULL, NULL);
234}
235endef
236
237define SOURCE_LIBNUMA
238#include <numa.h>
239#include <numaif.h>
240
241int main(void)
242{
243 numa_available();
244 return 0;
245}
246endef
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index 94d2d4f9c35d..f168debc5be2 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -179,16 +179,9 @@ _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_e
179_gea_warn = $(warning The path '$(1)' is not executable.) 179_gea_warn = $(warning The path '$(1)' is not executable.)
180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) 180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
181 181
182# try-cc 182ifneq ($(findstring $(MAKEFLAGS),s),s)
183# Usage: option = $(call try-cc, source-to-build, cc-options, msg) 183 ifneq ($(V),1)
184ifneq ($(V),1) 184 QUIET_CLEAN = @printf ' CLEAN %s\n' $1;
185TRY_CC_OUTPUT= > /dev/null 2>&1 185 QUIET_INSTALL = @printf ' INSTALL %s\n' $1;
186 endif
186endif 187endif
187TRY_CC_MSG=echo " CHK $(3)" 1>&2;
188
189try-cc = $(shell sh -c \
190 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
191 $(TRY_CC_MSG) \
192 echo "$(1)" | \
193 $(CC) -x c - $(2) -o "$$TMP" $(TRY_CC_OUTPUT) && echo y; \
194 rm -f "$$TMP"')
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 85e1aed95204..8b38b4e80ec2 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -49,14 +49,14 @@ static struct cmd_struct commands[] = {
49 { "version", cmd_version, 0 }, 49 { "version", cmd_version, 0 },
50 { "script", cmd_script, 0 }, 50 { "script", cmd_script, 0 },
51 { "sched", cmd_sched, 0 }, 51 { "sched", cmd_sched, 0 },
52#ifdef LIBELF_SUPPORT 52#ifdef HAVE_LIBELF_SUPPORT
53 { "probe", cmd_probe, 0 }, 53 { "probe", cmd_probe, 0 },
54#endif 54#endif
55 { "kmem", cmd_kmem, 0 }, 55 { "kmem", cmd_kmem, 0 },
56 { "lock", cmd_lock, 0 }, 56 { "lock", cmd_lock, 0 },
57 { "kvm", cmd_kvm, 0 }, 57 { "kvm", cmd_kvm, 0 },
58 { "test", cmd_test, 0 }, 58 { "test", cmd_test, 0 },
59#ifdef LIBAUDIT_SUPPORT 59#ifdef HAVE_LIBAUDIT_SUPPORT
60 { "trace", cmd_trace, 0 }, 60 { "trace", cmd_trace, 0 },
61#endif 61#endif
62 { "inject", cmd_inject, 0 }, 62 { "inject", cmd_inject, 0 },
@@ -456,6 +456,7 @@ int main(int argc, const char **argv)
456{ 456{
457 const char *cmd; 457 const char *cmd;
458 458
459 /* The page_size is placed in util object. */
459 page_size = sysconf(_SC_PAGE_SIZE); 460 page_size = sysconf(_SC_PAGE_SIZE);
460 461
461 cmd = perf_extract_argv0_path(argv[0]); 462 cmd = perf_extract_argv0_path(argv[0]);
@@ -480,7 +481,14 @@ int main(int argc, const char **argv)
480 fprintf(stderr, "cannot handle %s internally", cmd); 481 fprintf(stderr, "cannot handle %s internally", cmd);
481 goto out; 482 goto out;
482 } 483 }
483 484#ifdef HAVE_LIBAUDIT_SUPPORT
485 if (!prefixcmp(cmd, "trace")) {
486 set_buildid_dir();
487 setup_path();
488 argv[0] = "trace";
489 return cmd_trace(argc, argv, NULL);
490 }
491#endif
484 /* Look for flags.. */ 492 /* Look for flags.. */
485 argv++; 493 argv++;
486 argc--; 494 argc--;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index cf20187eee0a..b079304bd53d 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -4,6 +4,8 @@
4#include <asm/unistd.h> 4#include <asm/unistd.h>
5 5
6#if defined(__i386__) 6#if defined(__i386__)
7#define mb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
8#define wmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
7#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") 9#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
8#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 10#define cpu_relax() asm volatile("rep; nop" ::: "memory");
9#define CPUINFO_PROC "model name" 11#define CPUINFO_PROC "model name"
@@ -13,6 +15,8 @@
13#endif 15#endif
14 16
15#if defined(__x86_64__) 17#if defined(__x86_64__)
18#define mb() asm volatile("mfence" ::: "memory")
19#define wmb() asm volatile("sfence" ::: "memory")
16#define rmb() asm volatile("lfence" ::: "memory") 20#define rmb() asm volatile("lfence" ::: "memory")
17#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 21#define cpu_relax() asm volatile("rep; nop" ::: "memory");
18#define CPUINFO_PROC "model name" 22#define CPUINFO_PROC "model name"
@@ -23,45 +27,61 @@
23 27
24#ifdef __powerpc__ 28#ifdef __powerpc__
25#include "../../arch/powerpc/include/uapi/asm/unistd.h" 29#include "../../arch/powerpc/include/uapi/asm/unistd.h"
30#define mb() asm volatile ("sync" ::: "memory")
31#define wmb() asm volatile ("sync" ::: "memory")
26#define rmb() asm volatile ("sync" ::: "memory") 32#define rmb() asm volatile ("sync" ::: "memory")
27#define cpu_relax() asm volatile ("" ::: "memory");
28#define CPUINFO_PROC "cpu" 33#define CPUINFO_PROC "cpu"
29#endif 34#endif
30 35
31#ifdef __s390__ 36#ifdef __s390__
37#define mb() asm volatile("bcr 15,0" ::: "memory")
38#define wmb() asm volatile("bcr 15,0" ::: "memory")
32#define rmb() asm volatile("bcr 15,0" ::: "memory") 39#define rmb() asm volatile("bcr 15,0" ::: "memory")
33#define cpu_relax() asm volatile("" ::: "memory");
34#endif 40#endif
35 41
36#ifdef __sh__ 42#ifdef __sh__
37#if defined(__SH4A__) || defined(__SH5__) 43#if defined(__SH4A__) || defined(__SH5__)
44# define mb() asm volatile("synco" ::: "memory")
45# define wmb() asm volatile("synco" ::: "memory")
38# define rmb() asm volatile("synco" ::: "memory") 46# define rmb() asm volatile("synco" ::: "memory")
39#else 47#else
48# define mb() asm volatile("" ::: "memory")
49# define wmb() asm volatile("" ::: "memory")
40# define rmb() asm volatile("" ::: "memory") 50# define rmb() asm volatile("" ::: "memory")
41#endif 51#endif
42#define cpu_relax() asm volatile("" ::: "memory")
43#define CPUINFO_PROC "cpu type" 52#define CPUINFO_PROC "cpu type"
44#endif 53#endif
45 54
46#ifdef __hppa__ 55#ifdef __hppa__
56#define mb() asm volatile("" ::: "memory")
57#define wmb() asm volatile("" ::: "memory")
47#define rmb() asm volatile("" ::: "memory") 58#define rmb() asm volatile("" ::: "memory")
48#define cpu_relax() asm volatile("" ::: "memory");
49#define CPUINFO_PROC "cpu" 59#define CPUINFO_PROC "cpu"
50#endif 60#endif
51 61
52#ifdef __sparc__ 62#ifdef __sparc__
63#ifdef __LP64__
64#define mb() asm volatile("ba,pt %%xcc, 1f\n" \
65 "membar #StoreLoad\n" \
66 "1:\n":::"memory")
67#else
68#define mb() asm volatile("":::"memory")
69#endif
70#define wmb() asm volatile("":::"memory")
53#define rmb() asm volatile("":::"memory") 71#define rmb() asm volatile("":::"memory")
54#define cpu_relax() asm volatile("":::"memory")
55#define CPUINFO_PROC "cpu" 72#define CPUINFO_PROC "cpu"
56#endif 73#endif
57 74
58#ifdef __alpha__ 75#ifdef __alpha__
76#define mb() asm volatile("mb" ::: "memory")
77#define wmb() asm volatile("wmb" ::: "memory")
59#define rmb() asm volatile("mb" ::: "memory") 78#define rmb() asm volatile("mb" ::: "memory")
60#define cpu_relax() asm volatile("" ::: "memory")
61#define CPUINFO_PROC "cpu model" 79#define CPUINFO_PROC "cpu model"
62#endif 80#endif
63 81
64#ifdef __ia64__ 82#ifdef __ia64__
83#define mb() asm volatile ("mf" ::: "memory")
84#define wmb() asm volatile ("mf" ::: "memory")
65#define rmb() asm volatile ("mf" ::: "memory") 85#define rmb() asm volatile ("mf" ::: "memory")
66#define cpu_relax() asm volatile ("hint @pause" ::: "memory") 86#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
67#define CPUINFO_PROC "model name" 87#define CPUINFO_PROC "model name"
@@ -72,40 +92,55 @@
72 * Use the __kuser_memory_barrier helper in the CPU helper page. See 92 * Use the __kuser_memory_barrier helper in the CPU helper page. See
73 * arch/arm/kernel/entry-armv.S in the kernel source for details. 93 * arch/arm/kernel/entry-armv.S in the kernel source for details.
74 */ 94 */
95#define mb() ((void(*)(void))0xffff0fa0)()
96#define wmb() ((void(*)(void))0xffff0fa0)()
75#define rmb() ((void(*)(void))0xffff0fa0)() 97#define rmb() ((void(*)(void))0xffff0fa0)()
76#define cpu_relax() asm volatile("":::"memory")
77#define CPUINFO_PROC "Processor" 98#define CPUINFO_PROC "Processor"
78#endif 99#endif
79 100
80#ifdef __aarch64__ 101#ifdef __aarch64__
81#define rmb() asm volatile("dmb ld" ::: "memory") 102#define mb() asm volatile("dmb ish" ::: "memory")
103#define wmb() asm volatile("dmb ishld" ::: "memory")
104#define rmb() asm volatile("dmb ishst" ::: "memory")
82#define cpu_relax() asm volatile("yield" ::: "memory") 105#define cpu_relax() asm volatile("yield" ::: "memory")
83#endif 106#endif
84 107
85#ifdef __mips__ 108#ifdef __mips__
86#define rmb() asm volatile( \ 109#define mb() asm volatile( \
87 ".set mips2\n\t" \ 110 ".set mips2\n\t" \
88 "sync\n\t" \ 111 "sync\n\t" \
89 ".set mips0" \ 112 ".set mips0" \
90 : /* no output */ \ 113 : /* no output */ \
91 : /* no input */ \ 114 : /* no input */ \
92 : "memory") 115 : "memory")
93#define cpu_relax() asm volatile("" ::: "memory") 116#define wmb() mb()
117#define rmb() mb()
94#define CPUINFO_PROC "cpu model" 118#define CPUINFO_PROC "cpu model"
95#endif 119#endif
96 120
97#ifdef __arc__ 121#ifdef __arc__
122#define mb() asm volatile("" ::: "memory")
123#define wmb() asm volatile("" ::: "memory")
98#define rmb() asm volatile("" ::: "memory") 124#define rmb() asm volatile("" ::: "memory")
99#define cpu_relax() rmb()
100#define CPUINFO_PROC "Processor" 125#define CPUINFO_PROC "Processor"
101#endif 126#endif
102 127
103#ifdef __metag__ 128#ifdef __metag__
129#define mb() asm volatile("" ::: "memory")
130#define wmb() asm volatile("" ::: "memory")
104#define rmb() asm volatile("" ::: "memory") 131#define rmb() asm volatile("" ::: "memory")
105#define cpu_relax() asm volatile("" ::: "memory")
106#define CPUINFO_PROC "CPU" 132#define CPUINFO_PROC "CPU"
107#endif 133#endif
108 134
135#define barrier() asm volatile ("" ::: "memory")
136
137#ifndef cpu_relax
138#define cpu_relax() barrier()
139#endif
140
141#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
142
143
109#include <time.h> 144#include <time.h>
110#include <unistd.h> 145#include <unistd.h>
111#include <sys/types.h> 146#include <sys/types.h>
@@ -182,7 +217,9 @@ struct ip_callchain {
182struct branch_flags { 217struct branch_flags {
183 u64 mispred:1; 218 u64 mispred:1;
184 u64 predicted:1; 219 u64 predicted:1;
185 u64 reserved:62; 220 u64 in_tx:1;
221 u64 abort:1;
222 u64 reserved:60;
186}; 223};
187 224
188struct branch_entry { 225struct branch_entry {
@@ -211,14 +248,13 @@ enum perf_call_graph_mode {
211}; 248};
212 249
213struct perf_record_opts { 250struct perf_record_opts {
214 struct perf_target target; 251 struct target target;
215 int call_graph; 252 int call_graph;
216 bool group; 253 bool group;
217 bool inherit_stat; 254 bool inherit_stat;
218 bool no_delay; 255 bool no_delay;
219 bool no_inherit; 256 bool no_inherit;
220 bool no_samples; 257 bool no_samples;
221 bool pipe_output;
222 bool raw_samples; 258 bool raw_samples;
223 bool sample_address; 259 bool sample_address;
224 bool sample_weight; 260 bool sample_weight;
@@ -231,6 +267,7 @@ struct perf_record_opts {
231 u64 default_interval; 267 u64 default_interval;
232 u64 user_interval; 268 u64 user_interval;
233 u16 stack_dump_size; 269 u16 stack_dump_size;
270 bool sample_transaction;
234}; 271};
235 272
236#endif 273#endif
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c
index 315067b8f552..fcd1dd667906 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c
+++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c
@@ -25,7 +25,7 @@
25 25
26PyMODINIT_FUNC initperf_trace_context(void); 26PyMODINIT_FUNC initperf_trace_context(void);
27 27
28static PyObject *perf_trace_context_common_pc(PyObject *self, PyObject *args) 28static PyObject *perf_trace_context_common_pc(PyObject *obj, PyObject *args)
29{ 29{
30 static struct scripting_context *scripting_context; 30 static struct scripting_context *scripting_context;
31 PyObject *context; 31 PyObject *context;
@@ -40,7 +40,7 @@ static PyObject *perf_trace_context_common_pc(PyObject *self, PyObject *args)
40 return Py_BuildValue("i", retval); 40 return Py_BuildValue("i", retval);
41} 41}
42 42
43static PyObject *perf_trace_context_common_flags(PyObject *self, 43static PyObject *perf_trace_context_common_flags(PyObject *obj,
44 PyObject *args) 44 PyObject *args)
45{ 45{
46 static struct scripting_context *scripting_context; 46 static struct scripting_context *scripting_context;
@@ -56,7 +56,7 @@ static PyObject *perf_trace_context_common_flags(PyObject *self,
56 return Py_BuildValue("i", retval); 56 return Py_BuildValue("i", retval);
57} 57}
58 58
59static PyObject *perf_trace_context_common_lock_depth(PyObject *self, 59static PyObject *perf_trace_context_common_lock_depth(PyObject *obj,
60 PyObject *args) 60 PyObject *args)
61{ 61{
62 static struct scripting_context *scripting_context; 62 static struct scripting_context *scripting_context;
diff --git a/tools/perf/tests/attr/README b/tools/perf/tests/attr/README
index d102957cd59a..430024f618f1 100644
--- a/tools/perf/tests/attr/README
+++ b/tools/perf/tests/attr/README
@@ -44,9 +44,9 @@ Following tests are defined (with perf commands):
44 perf record -c 123 kill (test-record-count) 44 perf record -c 123 kill (test-record-count)
45 perf record -d kill (test-record-data) 45 perf record -d kill (test-record-data)
46 perf record -F 100 kill (test-record-freq) 46 perf record -F 100 kill (test-record-freq)
47 perf record -g -- kill (test-record-graph-default) 47 perf record -g kill (test-record-graph-default)
48 perf record -g dwarf -- kill (test-record-graph-dwarf) 48 perf record --call-graph dwarf kill (test-record-graph-dwarf)
49 perf record -g fp kill (test-record-graph-fp) 49 perf record --call-graph fp kill (test-record-graph-fp)
50 perf record --group -e cycles,instructions kill (test-record-group) 50 perf record --group -e cycles,instructions kill (test-record-group)
51 perf record -e '{cycles,instructions}' kill (test-record-group1) 51 perf record -e '{cycles,instructions}' kill (test-record-group1)
52 perf record -D kill (test-record-no-delay) 52 perf record -D kill (test-record-no-delay)
diff --git a/tools/perf/tests/attr/test-record-graph-default b/tools/perf/tests/attr/test-record-graph-default
index 833d1849d767..853597a9a8f6 100644
--- a/tools/perf/tests/attr/test-record-graph-default
+++ b/tools/perf/tests/attr/test-record-graph-default
@@ -1,6 +1,6 @@
1[config] 1[config]
2command = record 2command = record
3args = -g -- kill >/dev/null 2>&1 3args = -g kill >/dev/null 2>&1
4 4
5[event:base-record] 5[event:base-record]
6sample_type=295 6sample_type=295
diff --git a/tools/perf/tests/attr/test-record-graph-dwarf b/tools/perf/tests/attr/test-record-graph-dwarf
index e93e082f5208..d6f324ea578c 100644
--- a/tools/perf/tests/attr/test-record-graph-dwarf
+++ b/tools/perf/tests/attr/test-record-graph-dwarf
@@ -1,6 +1,6 @@
1[config] 1[config]
2command = record 2command = record
3args = -g dwarf -- kill >/dev/null 2>&1 3args = --call-graph dwarf -- kill >/dev/null 2>&1
4 4
5[event:base-record] 5[event:base-record]
6sample_type=12583 6sample_type=12583
diff --git a/tools/perf/tests/attr/test-record-graph-fp b/tools/perf/tests/attr/test-record-graph-fp
index 7cef3743f03f..055e3bee7993 100644
--- a/tools/perf/tests/attr/test-record-graph-fp
+++ b/tools/perf/tests/attr/test-record-graph-fp
@@ -1,6 +1,6 @@
1[config] 1[config]
2command = record 2command = record
3args = -g fp kill >/dev/null 2>&1 3args = --call-graph fp kill >/dev/null 2>&1
4 4
5[event:base-record] 5[event:base-record]
6sample_type=295 6sample_type=295
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 6fb781d5586c..85d4919dd623 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -275,8 +275,19 @@ static int process_event(struct machine *machine, struct perf_evlist *evlist,
275 if (event->header.type == PERF_RECORD_SAMPLE) 275 if (event->header.type == PERF_RECORD_SAMPLE)
276 return process_sample_event(machine, evlist, event, state); 276 return process_sample_event(machine, evlist, event, state);
277 277
278 if (event->header.type < PERF_RECORD_MAX) 278 if (event->header.type == PERF_RECORD_THROTTLE ||
279 return machine__process_event(machine, event); 279 event->header.type == PERF_RECORD_UNTHROTTLE)
280 return 0;
281
282 if (event->header.type < PERF_RECORD_MAX) {
283 int ret;
284
285 ret = machine__process_event(machine, event, NULL);
286 if (ret < 0)
287 pr_debug("machine__process_event failed, event type %u\n",
288 event->header.type);
289 return ret;
290 }
280 291
281 return 0; 292 return 0;
282} 293}
@@ -290,6 +301,7 @@ static int process_events(struct machine *machine, struct perf_evlist *evlist,
290 for (i = 0; i < evlist->nr_mmaps; i++) { 301 for (i = 0; i < evlist->nr_mmaps; i++) {
291 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { 302 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
292 ret = process_event(machine, evlist, event, state); 303 ret = process_event(machine, evlist, event, state);
304 perf_evlist__mmap_consume(evlist, i);
293 if (ret < 0) 305 if (ret < 0)
294 return ret; 306 return ret;
295 } 307 }
@@ -440,7 +452,7 @@ static int do_test_code_reading(bool try_kcore)
440 } 452 }
441 453
442 ret = perf_event__synthesize_thread_map(NULL, threads, 454 ret = perf_event__synthesize_thread_map(NULL, threads,
443 perf_event__process, machine); 455 perf_event__process, machine, false);
444 if (ret < 0) { 456 if (ret < 0) {
445 pr_debug("perf_event__synthesize_thread_map failed\n"); 457 pr_debug("perf_event__synthesize_thread_map failed\n");
446 goto out_err; 458 goto out_err;
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index dffe0551acaa..9cc81a3eb9b4 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -35,6 +35,7 @@ static char *test_file(int size)
35 if (size != write(fd, buf, size)) 35 if (size != write(fd, buf, size))
36 templ = NULL; 36 templ = NULL;
37 37
38 free(buf);
38 close(fd); 39 close(fd);
39 return templ; 40 return templ;
40} 41}
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 9b98c1554833..4774f7fbb758 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -32,7 +32,7 @@ static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
32 32
33int test__perf_evsel__tp_sched_test(void) 33int test__perf_evsel__tp_sched_test(void)
34{ 34{
35 struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch", 0); 35 struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch");
36 int ret = 0; 36 int ret = 0;
37 37
38 if (evsel == NULL) { 38 if (evsel == NULL) {
@@ -63,7 +63,7 @@ int test__perf_evsel__tp_sched_test(void)
63 63
64 perf_evsel__delete(evsel); 64 perf_evsel__delete(evsel);
65 65
66 evsel = perf_evsel__newtp("sched", "sched_wakeup", 0); 66 evsel = perf_evsel__newtp("sched", "sched_wakeup");
67 67
68 if (perf_evsel__test_field(evsel, "comm", 16, true)) 68 if (perf_evsel__test_field(evsel, "comm", 16, true))
69 ret = -1; 69 ret = -1;
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 4228ffc0d968..173bf42cc03e 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -93,7 +93,7 @@ static struct machine *setup_fake_machine(struct machines *machines)
93 if (thread == NULL) 93 if (thread == NULL)
94 goto out; 94 goto out;
95 95
96 thread__set_comm(thread, fake_threads[i].comm); 96 thread__set_comm(thread, fake_threads[i].comm, 0);
97 } 97 }
98 98
99 for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) { 99 for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
@@ -110,7 +110,7 @@ static struct machine *setup_fake_machine(struct machines *machines)
110 strcpy(fake_mmap_event.mmap.filename, 110 strcpy(fake_mmap_event.mmap.filename,
111 fake_mmap_info[i].filename); 111 fake_mmap_info[i].filename);
112 112
113 machine__process_mmap_event(machine, &fake_mmap_event); 113 machine__process_mmap_event(machine, &fake_mmap_event, NULL);
114 } 114 }
115 115
116 for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) { 116 for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
@@ -222,7 +222,8 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
222 &sample) < 0) 222 &sample) < 0)
223 goto out; 223 goto out;
224 224
225 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); 225 he = __hists__add_entry(&evsel->hists, &al, NULL,
226 NULL, NULL, 1, 1, 0);
226 if (he == NULL) 227 if (he == NULL)
227 goto out; 228 goto out;
228 229
@@ -244,7 +245,8 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
244 &sample) < 0) 245 &sample) < 0)
245 goto out; 246 goto out;
246 247
247 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); 248 he = __hists__add_entry(&evsel->hists, &al, NULL,
249 NULL, NULL, 1, 1, 0);
248 if (he == NULL) 250 if (he == NULL)
249 goto out; 251 goto out;
250 252
@@ -419,7 +421,7 @@ static void print_hists(struct hists *hists)
419 he = rb_entry(node, struct hist_entry, rb_node_in); 421 he = rb_entry(node, struct hist_entry, rb_node_in);
420 422
421 pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n", 423 pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
422 i, he->thread->comm, he->ms.map->dso->short_name, 424 i, thread__comm_str(he->thread), he->ms.map->dso->short_name,
423 he->ms.sym->name, he->stat.period); 425 he->ms.sym->name, he->stat.period);
424 426
425 i++; 427 i++;
@@ -465,7 +467,7 @@ int test__hists_link(void)
465 goto out; 467 goto out;
466 468
467 list_for_each_entry(evsel, &evlist->entries, node) { 469 list_for_each_entry(evsel, &evlist->entries, node) {
468 hists__collapse_resort(&evsel->hists); 470 hists__collapse_resort(&evsel->hists, NULL);
469 471
470 if (verbose > 2) 472 if (verbose > 2)
471 print_hists(&evsel->hists); 473 print_hists(&evsel->hists);
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index d444ea2c47d9..376c35608534 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -36,6 +36,7 @@ static int find_comm(struct perf_evlist *evlist, const char *comm)
36 (pid_t)event->comm.tid == getpid() && 36 (pid_t)event->comm.tid == getpid() &&
37 strcmp(event->comm.comm, comm) == 0) 37 strcmp(event->comm.comm, comm) == 0)
38 found += 1; 38 found += 1;
39 perf_evlist__mmap_consume(evlist, i);
39 } 40 }
40 } 41 }
41 return found; 42 return found;
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index c4185b9aeb80..d64ab79c6d35 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -65,7 +65,7 @@ int test__basic_mmap(void)
65 char name[64]; 65 char name[64];
66 66
67 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]); 67 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
68 evsels[i] = perf_evsel__newtp("syscalls", name, i); 68 evsels[i] = perf_evsel__newtp("syscalls", name);
69 if (evsels[i] == NULL) { 69 if (evsels[i] == NULL) {
70 pr_debug("perf_evsel__new\n"); 70 pr_debug("perf_evsel__new\n");
71 goto out_free_evlist; 71 goto out_free_evlist;
@@ -122,6 +122,7 @@ int test__basic_mmap(void)
122 goto out_munmap; 122 goto out_munmap;
123 } 123 }
124 nr_events[evsel->idx]++; 124 nr_events[evsel->idx]++;
125 perf_evlist__mmap_consume(evlist, 0);
125 } 126 }
126 127
127 err = 0; 128 err = 0;
diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c
index b0657a9ccda6..5fecdbd2f5f7 100644
--- a/tools/perf/tests/open-syscall-all-cpus.c
+++ b/tools/perf/tests/open-syscall-all-cpus.c
@@ -26,7 +26,7 @@ int test__open_syscall_event_on_all_cpus(void)
26 26
27 CPU_ZERO(&cpu_set); 27 CPU_ZERO(&cpu_set);
28 28
29 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0); 29 evsel = perf_evsel__newtp("syscalls", "sys_enter_open");
30 if (evsel == NULL) { 30 if (evsel == NULL) {
31 pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); 31 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
32 goto out_thread_map_delete; 32 goto out_thread_map_delete;
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
index fc5b9fca8b47..41cc0badb74b 100644
--- a/tools/perf/tests/open-syscall-tp-fields.c
+++ b/tools/perf/tests/open-syscall-tp-fields.c
@@ -27,7 +27,7 @@ int test__syscall_open_tp_fields(void)
27 goto out; 27 goto out;
28 } 28 }
29 29
30 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0); 30 evsel = perf_evsel__newtp("syscalls", "sys_enter_open");
31 if (evsel == NULL) { 31 if (evsel == NULL) {
32 pr_debug("%s: perf_evsel__newtp\n", __func__); 32 pr_debug("%s: perf_evsel__newtp\n", __func__);
33 goto out_delete_evlist; 33 goto out_delete_evlist;
@@ -77,8 +77,10 @@ int test__syscall_open_tp_fields(void)
77 77
78 ++nr_events; 78 ++nr_events;
79 79
80 if (type != PERF_RECORD_SAMPLE) 80 if (type != PERF_RECORD_SAMPLE) {
81 perf_evlist__mmap_consume(evlist, i);
81 continue; 82 continue;
83 }
82 84
83 err = perf_evsel__parse_sample(evsel, event, &sample); 85 err = perf_evsel__parse_sample(evsel, event, &sample);
84 if (err) { 86 if (err) {
diff --git a/tools/perf/tests/open-syscall.c b/tools/perf/tests/open-syscall.c
index befc0671f95d..c1dc7d25f38c 100644
--- a/tools/perf/tests/open-syscall.c
+++ b/tools/perf/tests/open-syscall.c
@@ -15,7 +15,7 @@ int test__open_syscall_event(void)
15 return -1; 15 return -1;
16 } 16 }
17 17
18 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0); 18 evsel = perf_evsel__newtp("syscalls", "sys_enter_open");
19 if (evsel == NULL) { 19 if (evsel == NULL) {
20 pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); 20 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
21 goto out_thread_map_delete; 21 goto out_thread_map_delete;
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 48114d164e9f..3cbd10496087 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -2,7 +2,7 @@
2#include "parse-events.h" 2#include "parse-events.h"
3#include "evsel.h" 3#include "evsel.h"
4#include "evlist.h" 4#include "evlist.h"
5#include "sysfs.h" 5#include "fs.h"
6#include <lk/debugfs.h> 6#include <lk/debugfs.h>
7#include "tests.h" 7#include "tests.h"
8#include <linux/hw_breakpoint.h> 8#include <linux/hw_breakpoint.h>
@@ -441,9 +441,8 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
441 441
442static int test__checkevent_pmu_events(struct perf_evlist *evlist) 442static int test__checkevent_pmu_events(struct perf_evlist *evlist)
443{ 443{
444 struct perf_evsel *evsel; 444 struct perf_evsel *evsel = perf_evlist__first(evlist);
445 445
446 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
447 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); 446 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
448 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); 447 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
449 TEST_ASSERT_VAL("wrong exclude_user", 448 TEST_ASSERT_VAL("wrong exclude_user",
@@ -1456,7 +1455,7 @@ static int test_pmu(void)
1456 int ret; 1455 int ret;
1457 1456
1458 snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/", 1457 snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/",
1459 sysfs_find_mountpoint()); 1458 sysfs__mountpoint());
1460 1459
1461 ret = stat(path, &st); 1460 ret = stat(path, &st);
1462 if (ret) 1461 if (ret)
@@ -1473,7 +1472,7 @@ static int test_pmu_events(void)
1473 int ret; 1472 int ret;
1474 1473
1475 snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/events/", 1474 snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/events/",
1476 sysfs_find_mountpoint()); 1475 sysfs__mountpoint());
1477 1476
1478 ret = stat(path, &st); 1477 ret = stat(path, &st);
1479 if (ret) { 1478 if (ret) {
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index b8a7056519ac..93a62b06c3af 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -45,7 +45,7 @@ int test__PERF_RECORD(void)
45 }; 45 };
46 cpu_set_t cpu_mask; 46 cpu_set_t cpu_mask;
47 size_t cpu_mask_size = sizeof(cpu_mask); 47 size_t cpu_mask_size = sizeof(cpu_mask);
48 struct perf_evlist *evlist = perf_evlist__new(); 48 struct perf_evlist *evlist = perf_evlist__new_default();
49 struct perf_evsel *evsel; 49 struct perf_evsel *evsel;
50 struct perf_sample sample; 50 struct perf_sample sample;
51 const char *cmd = "sleep"; 51 const char *cmd = "sleep";
@@ -66,16 +66,6 @@ int test__PERF_RECORD(void)
66 } 66 }
67 67
68 /* 68 /*
69 * We need at least one evsel in the evlist, use the default
70 * one: "cycles".
71 */
72 err = perf_evlist__add_default(evlist);
73 if (err < 0) {
74 pr_debug("Not enough memory to create evsel\n");
75 goto out_delete_evlist;
76 }
77
78 /*
79 * Create maps of threads and cpus to monitor. In this case 69 * Create maps of threads and cpus to monitor. In this case
80 * we start with all threads and cpus (-1, -1) but then in 70 * we start with all threads and cpus (-1, -1) but then in
81 * perf_evlist__prepare_workload we'll fill in the only thread 71 * perf_evlist__prepare_workload we'll fill in the only thread
@@ -263,6 +253,8 @@ int test__PERF_RECORD(void)
263 type); 253 type);
264 ++errs; 254 ++errs;
265 } 255 }
256
257 perf_evlist__mmap_consume(evlist, i);
266 } 258 }
267 } 259 }
268 260
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index 0ab61b1f408e..4ca1b938f6a6 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -122,7 +122,7 @@ int test__perf_time_to_tsc(void)
122 if (event->header.type != PERF_RECORD_COMM || 122 if (event->header.type != PERF_RECORD_COMM ||
123 (pid_t)event->comm.pid != getpid() || 123 (pid_t)event->comm.pid != getpid() ||
124 (pid_t)event->comm.tid != getpid()) 124 (pid_t)event->comm.tid != getpid())
125 continue; 125 goto next_event;
126 126
127 if (strcmp(event->comm.comm, comm1) == 0) { 127 if (strcmp(event->comm.comm, comm1) == 0) {
128 CHECK__(perf_evsel__parse_sample(evsel, event, 128 CHECK__(perf_evsel__parse_sample(evsel, event,
@@ -134,6 +134,8 @@ int test__perf_time_to_tsc(void)
134 &sample)); 134 &sample));
135 comm2_time = sample.time; 135 comm2_time = sample.time;
136 } 136 }
137next_event:
138 perf_evlist__mmap_consume(evlist, i);
137 } 139 }
138 } 140 }
139 141
diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c
index ff94886aad99..46649c25fa5e 100644
--- a/tools/perf/tests/rdpmc.c
+++ b/tools/perf/tests/rdpmc.c
@@ -9,8 +9,6 @@
9 9
10#if defined(__x86_64__) || defined(__i386__) 10#if defined(__x86_64__) || defined(__i386__)
11 11
12#define barrier() asm volatile("" ::: "memory")
13
14static u64 rdpmc(unsigned int counter) 12static u64 rdpmc(unsigned int counter)
15{ 13{
16 unsigned int low, high; 14 unsigned int low, high;
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 77f598dbd97a..1b677202638d 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -121,6 +121,9 @@ static bool samples_same(const struct perf_sample *s1,
121 if (type & PERF_SAMPLE_DATA_SRC) 121 if (type & PERF_SAMPLE_DATA_SRC)
122 COMP(data_src); 122 COMP(data_src);
123 123
124 if (type & PERF_SAMPLE_TRANSACTION)
125 COMP(transaction);
126
124 return true; 127 return true;
125} 128}
126 129
@@ -165,6 +168,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
165 .cpu = 110, 168 .cpu = 110,
166 .raw_size = sizeof(raw_data), 169 .raw_size = sizeof(raw_data),
167 .data_src = 111, 170 .data_src = 111,
171 .transaction = 112,
168 .raw_data = (void *)raw_data, 172 .raw_data = (void *)raw_data,
169 .callchain = &callchain.callchain, 173 .callchain = &callchain.callchain,
170 .branch_stack = &branch_stack.branch_stack, 174 .branch_stack = &branch_stack.branch_stack,
@@ -273,10 +277,11 @@ int test__sample_parsing(void)
273 277
274 /* 278 /*
275 * Fail the test if it has not been updated when new sample format bits 279 * Fail the test if it has not been updated when new sample format bits
276 * were added. 280 * were added. Please actually update the test rather than just change
281 * the condition below.
277 */ 282 */
278 if (PERF_SAMPLE_MAX > PERF_SAMPLE_IDENTIFIER << 1) { 283 if (PERF_SAMPLE_MAX > PERF_SAMPLE_TRANSACTION << 1) {
279 pr_debug("sample format has changed - test needs updating\n"); 284 pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n");
280 return -1; 285 return -1;
281 } 286 }
282 287
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
index 2e41e2d32ccc..6664a7cd828c 100644
--- a/tools/perf/tests/sw-clock.c
+++ b/tools/perf/tests/sw-clock.c
@@ -9,7 +9,7 @@
9#include "util/cpumap.h" 9#include "util/cpumap.h"
10#include "util/thread_map.h" 10#include "util/thread_map.h"
11 11
12#define NR_LOOPS 1000000 12#define NR_LOOPS 10000000
13 13
14/* 14/*
15 * This test will open software clock events (cpu-clock, task-clock) 15 * This test will open software clock events (cpu-clock, task-clock)
@@ -34,7 +34,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
34 .freq = 1, 34 .freq = 1,
35 }; 35 };
36 36
37 attr.sample_freq = 10000; 37 attr.sample_freq = 500;
38 38
39 evlist = perf_evlist__new(); 39 evlist = perf_evlist__new();
40 if (evlist == NULL) { 40 if (evlist == NULL) {
@@ -42,7 +42,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
42 return -1; 42 return -1;
43 } 43 }
44 44
45 evsel = perf_evsel__new(&attr, 0); 45 evsel = perf_evsel__new(&attr);
46 if (evsel == NULL) { 46 if (evsel == NULL) {
47 pr_debug("perf_evsel__new\n"); 47 pr_debug("perf_evsel__new\n");
48 goto out_free_evlist; 48 goto out_free_evlist;
@@ -57,7 +57,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
57 goto out_delete_maps; 57 goto out_delete_maps;
58 } 58 }
59 59
60 perf_evlist__open(evlist); 60 if (perf_evlist__open(evlist)) {
61 const char *knob = "/proc/sys/kernel/perf_event_max_sample_rate";
62
63 err = -errno;
64 pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
65 strerror(errno), knob, (u64)attr.sample_freq);
66 goto out_delete_maps;
67 }
61 68
62 err = perf_evlist__mmap(evlist, 128, true); 69 err = perf_evlist__mmap(evlist, 128, true);
63 if (err < 0) { 70 if (err < 0) {
@@ -78,7 +85,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
78 struct perf_sample sample; 85 struct perf_sample sample;
79 86
80 if (event->header.type != PERF_RECORD_SAMPLE) 87 if (event->header.type != PERF_RECORD_SAMPLE)
81 continue; 88 goto next_event;
82 89
83 err = perf_evlist__parse_sample(evlist, event, &sample); 90 err = perf_evlist__parse_sample(evlist, event, &sample);
84 if (err < 0) { 91 if (err < 0) {
@@ -88,6 +95,8 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
88 95
89 total_periods += sample.period; 96 total_periods += sample.period;
90 nr_samples++; 97 nr_samples++;
98next_event:
99 perf_evlist__mmap_consume(evlist, 0);
91 } 100 }
92 101
93 if ((u64) nr_samples == total_periods) { 102 if ((u64) nr_samples == total_periods) {
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index 28fe5894b061..d09ab579119e 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -28,7 +28,7 @@ int test__task_exit(void)
28 union perf_event *event; 28 union perf_event *event;
29 struct perf_evsel *evsel; 29 struct perf_evsel *evsel;
30 struct perf_evlist *evlist; 30 struct perf_evlist *evlist;
31 struct perf_target target = { 31 struct target target = {
32 .uid = UINT_MAX, 32 .uid = UINT_MAX,
33 .uses_mmap = true, 33 .uses_mmap = true,
34 }; 34 };
@@ -37,20 +37,11 @@ int test__task_exit(void)
37 signal(SIGCHLD, sig_handler); 37 signal(SIGCHLD, sig_handler);
38 signal(SIGUSR1, sig_handler); 38 signal(SIGUSR1, sig_handler);
39 39
40 evlist = perf_evlist__new(); 40 evlist = perf_evlist__new_default();
41 if (evlist == NULL) { 41 if (evlist == NULL) {
42 pr_debug("perf_evlist__new\n"); 42 pr_debug("perf_evlist__new_default\n");
43 return -1; 43 return -1;
44 } 44 }
45 /*
46 * We need at least one evsel in the evlist, use the default
47 * one: "cycles".
48 */
49 err = perf_evlist__add_default(evlist);
50 if (err < 0) {
51 pr_debug("Not enough memory to create evsel\n");
52 goto out_free_evlist;
53 }
54 45
55 /* 46 /*
56 * Create maps of threads and cpus to monitor. In this case 47 * Create maps of threads and cpus to monitor. In this case
@@ -96,10 +87,10 @@ int test__task_exit(void)
96 87
97retry: 88retry:
98 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) { 89 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
99 if (event->header.type != PERF_RECORD_EXIT) 90 if (event->header.type == PERF_RECORD_EXIT)
100 continue; 91 nr_exit++;
101 92
102 nr_exit++; 93 perf_evlist__mmap_consume(evlist, 0);
103 } 94 }
104 95
105 if (!exited || !nr_exit) { 96 if (!exited || !nr_exit) {
@@ -117,7 +108,6 @@ out_close_evlist:
117 perf_evlist__close(evlist); 108 perf_evlist__close(evlist);
118out_delete_maps: 109out_delete_maps:
119 perf_evlist__delete_maps(evlist); 110 perf_evlist__delete_maps(evlist);
120out_free_evlist:
121 perf_evlist__delete(evlist); 111 perf_evlist__delete(evlist);
122 return err; 112 return err;
123} 113}
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index bbc782e364b0..cbaa7af45513 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -569,7 +569,7 @@ void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
569 browser->top = browser->top + browser->top_idx + offset; 569 browser->top = browser->top + browser->top_idx + offset;
570 break; 570 break;
571 case SEEK_END: 571 case SEEK_END:
572 browser->top = browser->top + browser->nr_entries + offset; 572 browser->top = browser->top + browser->nr_entries - 1 + offset;
573 break; 573 break;
574 default: 574 default:
575 return; 575 return;
@@ -680,7 +680,7 @@ static void __ui_browser__line_arrow_down(struct ui_browser *browser,
680 if (end >= browser->top_idx + browser->height) 680 if (end >= browser->top_idx + browser->height)
681 end_row = browser->height - 1; 681 end_row = browser->height - 1;
682 else 682 else
683 end_row = end - browser->top_idx;; 683 end_row = end - browser->top_idx;
684 684
685 ui_browser__gotorc(browser, row, column); 685 ui_browser__gotorc(browser, row, column);
686 SLsmg_draw_vline(end_row - row + 1); 686 SLsmg_draw_vline(end_row - row + 1);
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index 404ff66a3e36..7d45d2f53601 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -21,32 +21,32 @@ struct ui_browser {
21 void *priv; 21 void *priv;
22 const char *title; 22 const char *title;
23 char *helpline; 23 char *helpline;
24 unsigned int (*refresh)(struct ui_browser *self); 24 unsigned int (*refresh)(struct ui_browser *browser);
25 void (*write)(struct ui_browser *self, void *entry, int row); 25 void (*write)(struct ui_browser *browser, void *entry, int row);
26 void (*seek)(struct ui_browser *self, off_t offset, int whence); 26 void (*seek)(struct ui_browser *browser, off_t offset, int whence);
27 bool (*filter)(struct ui_browser *self, void *entry); 27 bool (*filter)(struct ui_browser *browser, void *entry);
28 u32 nr_entries; 28 u32 nr_entries;
29 bool navkeypressed; 29 bool navkeypressed;
30 bool use_navkeypressed; 30 bool use_navkeypressed;
31}; 31};
32 32
33int ui_browser__set_color(struct ui_browser *browser, int color); 33int ui_browser__set_color(struct ui_browser *browser, int color);
34void ui_browser__set_percent_color(struct ui_browser *self, 34void ui_browser__set_percent_color(struct ui_browser *browser,
35 double percent, bool current); 35 double percent, bool current);
36bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row); 36bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row);
37void ui_browser__refresh_dimensions(struct ui_browser *self); 37void ui_browser__refresh_dimensions(struct ui_browser *browser);
38void ui_browser__reset_index(struct ui_browser *self); 38void ui_browser__reset_index(struct ui_browser *browser);
39 39
40void ui_browser__gotorc(struct ui_browser *self, int y, int x); 40void ui_browser__gotorc(struct ui_browser *browser, int y, int x);
41void ui_browser__write_graph(struct ui_browser *browser, int graph); 41void ui_browser__write_graph(struct ui_browser *browser, int graph);
42void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column, 42void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
43 u64 start, u64 end); 43 u64 start, u64 end);
44void __ui_browser__show_title(struct ui_browser *browser, const char *title); 44void __ui_browser__show_title(struct ui_browser *browser, const char *title);
45void ui_browser__show_title(struct ui_browser *browser, const char *title); 45void ui_browser__show_title(struct ui_browser *browser, const char *title);
46int ui_browser__show(struct ui_browser *self, const char *title, 46int ui_browser__show(struct ui_browser *browser, const char *title,
47 const char *helpline, ...); 47 const char *helpline, ...);
48void ui_browser__hide(struct ui_browser *self); 48void ui_browser__hide(struct ui_browser *browser);
49int ui_browser__refresh(struct ui_browser *self); 49int ui_browser__refresh(struct ui_browser *browser);
50int ui_browser__run(struct ui_browser *browser, int delay_secs); 50int ui_browser__run(struct ui_browser *browser, int delay_secs);
51void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); 51void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
52void ui_browser__handle_resize(struct ui_browser *browser); 52void ui_browser__handle_resize(struct ui_browser *browser);
@@ -63,11 +63,11 @@ int ui_browser__input_window(const char *title, const char *text, char *input,
63void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); 63void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
64unsigned int ui_browser__argv_refresh(struct ui_browser *browser); 64unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
65 65
66void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); 66void ui_browser__rb_tree_seek(struct ui_browser *browser, off_t offset, int whence);
67unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); 67unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser);
68 68
69void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence); 69void ui_browser__list_head_seek(struct ui_browser *browser, off_t offset, int whence);
70unsigned int ui_browser__list_head_refresh(struct ui_browser *self); 70unsigned int ui_browser__list_head_refresh(struct ui_browser *browser);
71 71
72void ui_browser__init(void); 72void ui_browser__init(void);
73void annotate_browser__init(void); 73void annotate_browser__init(void);
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 08545ae46992..f0697a3aede0 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -442,35 +442,37 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
442{ 442{
443 struct map_symbol *ms = browser->b.priv; 443 struct map_symbol *ms = browser->b.priv;
444 struct disasm_line *dl = browser->selection; 444 struct disasm_line *dl = browser->selection;
445 struct symbol *sym = ms->sym;
446 struct annotation *notes; 445 struct annotation *notes;
447 struct symbol *target; 446 struct addr_map_symbol target = {
448 u64 ip; 447 .map = ms->map,
448 .addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
449 };
449 char title[SYM_TITLE_MAX_SIZE]; 450 char title[SYM_TITLE_MAX_SIZE];
450 451
451 if (!ins__is_call(dl->ins)) 452 if (!ins__is_call(dl->ins))
452 return false; 453 return false;
453 454
454 ip = ms->map->map_ip(ms->map, dl->ops.target.addr); 455 if (map_groups__find_ams(&target, NULL) ||
455 target = map__find_symbol(ms->map, ip, NULL); 456 map__rip_2objdump(target.map, target.map->map_ip(target.map,
456 if (target == NULL) { 457 target.addr)) !=
458 dl->ops.target.addr) {
457 ui_helpline__puts("The called function was not found."); 459 ui_helpline__puts("The called function was not found.");
458 return true; 460 return true;
459 } 461 }
460 462
461 notes = symbol__annotation(target); 463 notes = symbol__annotation(target.sym);
462 pthread_mutex_lock(&notes->lock); 464 pthread_mutex_lock(&notes->lock);
463 465
464 if (notes->src == NULL && symbol__alloc_hist(target) < 0) { 466 if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
465 pthread_mutex_unlock(&notes->lock); 467 pthread_mutex_unlock(&notes->lock);
466 ui__warning("Not enough memory for annotating '%s' symbol!\n", 468 ui__warning("Not enough memory for annotating '%s' symbol!\n",
467 target->name); 469 target.sym->name);
468 return true; 470 return true;
469 } 471 }
470 472
471 pthread_mutex_unlock(&notes->lock); 473 pthread_mutex_unlock(&notes->lock);
472 symbol__tui_annotate(target, ms->map, evsel, hbt); 474 symbol__tui_annotate(target.sym, target.map, evsel, hbt);
473 sym_title(sym, ms->map, title, sizeof(title)); 475 sym_title(ms->sym, ms->map, title, sizeof(title));
474 ui_browser__show_title(&browser->b, title); 476 ui_browser__show_title(&browser->b, title);
475 return true; 477 return true;
476} 478}
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 7ef36c360471..a440e03cd8c2 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1255,7 +1255,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1255 if (thread) 1255 if (thread)
1256 printed += scnprintf(bf + printed, size - printed, 1256 printed += scnprintf(bf + printed, size - printed,
1257 ", Thread: %s(%d)", 1257 ", Thread: %s(%d)",
1258 (thread->comm_set ? thread->comm : ""), 1258 (thread->comm_set ? thread__comm_str(thread) : ""),
1259 thread->tid); 1259 thread->tid);
1260 if (dso) 1260 if (dso)
1261 printed += scnprintf(bf + printed, size - printed, 1261 printed += scnprintf(bf + printed, size - printed,
@@ -1578,7 +1578,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1578 if (thread != NULL && 1578 if (thread != NULL &&
1579 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 1579 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
1580 (browser->hists->thread_filter ? "out of" : "into"), 1580 (browser->hists->thread_filter ? "out of" : "into"),
1581 (thread->comm_set ? thread->comm : ""), 1581 (thread->comm_set ? thread__comm_str(thread) : ""),
1582 thread->tid) > 0) 1582 thread->tid) > 0)
1583 zoom_thread = nr_options++; 1583 zoom_thread = nr_options++;
1584 1584
@@ -1598,7 +1598,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1598 struct symbol *sym; 1598 struct symbol *sym;
1599 1599
1600 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]", 1600 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
1601 browser->he_selection->thread->comm) > 0) 1601 thread__comm_str(browser->he_selection->thread)) > 0)
1602 scripts_comm = nr_options++; 1602 scripts_comm = nr_options++;
1603 1603
1604 sym = browser->he_selection->ms.sym; 1604 sym = browser->he_selection->ms.sym;
@@ -1701,7 +1701,7 @@ zoom_out_thread:
1701 sort_thread.elide = false; 1701 sort_thread.elide = false;
1702 } else { 1702 } else {
1703 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1703 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1704 thread->comm_set ? thread->comm : "", 1704 thread->comm_set ? thread__comm_str(thread) : "",
1705 thread->tid); 1705 thread->tid);
1706 browser->hists->thread_filter = thread; 1706 browser->hists->thread_filter = thread;
1707 sort_thread.elide = true; 1707 sort_thread.elide = true;
@@ -1717,7 +1717,7 @@ do_scripts:
1717 memset(script_opt, 0, 64); 1717 memset(script_opt, 0, 64);
1718 1718
1719 if (choice == scripts_comm) 1719 if (choice == scripts_comm)
1720 sprintf(script_opt, " -c %s ", browser->he_selection->thread->comm); 1720 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
1721 1721
1722 if (choice == scripts_symbol) 1722 if (choice == scripts_symbol)
1723 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name); 1723 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
@@ -1847,15 +1847,15 @@ browse_hists:
1847 switch (key) { 1847 switch (key) {
1848 case K_TAB: 1848 case K_TAB:
1849 if (pos->node.next == &evlist->entries) 1849 if (pos->node.next == &evlist->entries)
1850 pos = list_entry(evlist->entries.next, struct perf_evsel, node); 1850 pos = perf_evlist__first(evlist);
1851 else 1851 else
1852 pos = list_entry(pos->node.next, struct perf_evsel, node); 1852 pos = perf_evsel__next(pos);
1853 goto browse_hists; 1853 goto browse_hists;
1854 case K_UNTAB: 1854 case K_UNTAB:
1855 if (pos->node.prev == &evlist->entries) 1855 if (pos->node.prev == &evlist->entries)
1856 pos = list_entry(evlist->entries.prev, struct perf_evsel, node); 1856 pos = perf_evlist__last(evlist);
1857 else 1857 else
1858 pos = list_entry(pos->node.prev, struct perf_evsel, node); 1858 pos = perf_evsel__prev(pos);
1859 goto browse_hists; 1859 goto browse_hists;
1860 case K_ESC: 1860 case K_ESC:
1861 if (!ui_browser__dialog_yesno(&menu->b, 1861 if (!ui_browser__dialog_yesno(&menu->b,
@@ -1889,7 +1889,7 @@ out:
1889 return key; 1889 return key;
1890} 1890}
1891 1891
1892static bool filter_group_entries(struct ui_browser *self __maybe_unused, 1892static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
1893 void *entry) 1893 void *entry)
1894{ 1894{
1895 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 1895 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
@@ -1943,8 +1943,7 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1943 1943
1944single_entry: 1944single_entry:
1945 if (nr_entries == 1) { 1945 if (nr_entries == 1) {
1946 struct perf_evsel *first = list_entry(evlist->entries.next, 1946 struct perf_evsel *first = perf_evlist__first(evlist);
1947 struct perf_evsel, node);
1948 const char *ev_name = perf_evsel__name(first); 1947 const char *ev_name = perf_evsel__name(first);
1949 1948
1950 return perf_evsel__hists_browse(first, nr_entries, help, 1949 return perf_evsel__hists_browse(first, nr_entries, help,
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index 95c7cfb8f2c6..b11639f33682 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -18,30 +18,30 @@ struct map_browser {
18 u8 addrlen; 18 u8 addrlen;
19}; 19};
20 20
21static void map_browser__write(struct ui_browser *self, void *nd, int row) 21static void map_browser__write(struct ui_browser *browser, void *nd, int row)
22{ 22{
23 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 23 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
24 struct map_browser *mb = container_of(self, struct map_browser, b); 24 struct map_browser *mb = container_of(browser, struct map_browser, b);
25 bool current_entry = ui_browser__is_current_entry(self, row); 25 bool current_entry = ui_browser__is_current_entry(browser, row);
26 int width; 26 int width;
27 27
28 ui_browser__set_percent_color(self, 0, current_entry); 28 ui_browser__set_percent_color(browser, 0, current_entry);
29 slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ", 29 slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
30 mb->addrlen, sym->start, mb->addrlen, sym->end, 30 mb->addrlen, sym->start, mb->addrlen, sym->end,
31 sym->binding == STB_GLOBAL ? 'g' : 31 sym->binding == STB_GLOBAL ? 'g' :
32 sym->binding == STB_LOCAL ? 'l' : 'w'); 32 sym->binding == STB_LOCAL ? 'l' : 'w');
33 width = self->width - ((mb->addrlen * 2) + 4); 33 width = browser->width - ((mb->addrlen * 2) + 4);
34 if (width > 0) 34 if (width > 0)
35 slsmg_write_nstring(sym->name, width); 35 slsmg_write_nstring(sym->name, width);
36} 36}
37 37
38/* FIXME uber-kludgy, see comment on cmd_report... */ 38/* FIXME uber-kludgy, see comment on cmd_report... */
39static u32 *symbol__browser_index(struct symbol *self) 39static u32 *symbol__browser_index(struct symbol *browser)
40{ 40{
41 return ((void *)self) - sizeof(struct rb_node) - sizeof(u32); 41 return ((void *)browser) - sizeof(struct rb_node) - sizeof(u32);
42} 42}
43 43
44static int map_browser__search(struct map_browser *self) 44static int map_browser__search(struct map_browser *browser)
45{ 45{
46 char target[512]; 46 char target[512];
47 struct symbol *sym; 47 struct symbol *sym;
@@ -53,37 +53,37 @@ static int map_browser__search(struct map_browser *self)
53 53
54 if (target[0] == '0' && tolower(target[1]) == 'x') { 54 if (target[0] == '0' && tolower(target[1]) == 'x') {
55 u64 addr = strtoull(target, NULL, 16); 55 u64 addr = strtoull(target, NULL, 16);
56 sym = map__find_symbol(self->map, addr, NULL); 56 sym = map__find_symbol(browser->map, addr, NULL);
57 } else 57 } else
58 sym = map__find_symbol_by_name(self->map, target, NULL); 58 sym = map__find_symbol_by_name(browser->map, target, NULL);
59 59
60 if (sym != NULL) { 60 if (sym != NULL) {
61 u32 *idx = symbol__browser_index(sym); 61 u32 *idx = symbol__browser_index(sym);
62 62
63 self->b.top = &sym->rb_node; 63 browser->b.top = &sym->rb_node;
64 self->b.index = self->b.top_idx = *idx; 64 browser->b.index = browser->b.top_idx = *idx;
65 } else 65 } else
66 ui_helpline__fpush("%s not found!", target); 66 ui_helpline__fpush("%s not found!", target);
67 67
68 return 0; 68 return 0;
69} 69}
70 70
71static int map_browser__run(struct map_browser *self) 71static int map_browser__run(struct map_browser *browser)
72{ 72{
73 int key; 73 int key;
74 74
75 if (ui_browser__show(&self->b, self->map->dso->long_name, 75 if (ui_browser__show(&browser->b, browser->map->dso->long_name,
76 "Press <- or ESC to exit, %s / to search", 76 "Press <- or ESC to exit, %s / to search",
77 verbose ? "" : "restart with -v to use") < 0) 77 verbose ? "" : "restart with -v to use") < 0)
78 return -1; 78 return -1;
79 79
80 while (1) { 80 while (1) {
81 key = ui_browser__run(&self->b, 0); 81 key = ui_browser__run(&browser->b, 0);
82 82
83 switch (key) { 83 switch (key) {
84 case '/': 84 case '/':
85 if (verbose) 85 if (verbose)
86 map_browser__search(self); 86 map_browser__search(browser);
87 default: 87 default:
88 break; 88 break;
89 case K_LEFT: 89 case K_LEFT:
@@ -94,20 +94,20 @@ static int map_browser__run(struct map_browser *self)
94 } 94 }
95 } 95 }
96out: 96out:
97 ui_browser__hide(&self->b); 97 ui_browser__hide(&browser->b);
98 return key; 98 return key;
99} 99}
100 100
101int map__browse(struct map *self) 101int map__browse(struct map *map)
102{ 102{
103 struct map_browser mb = { 103 struct map_browser mb = {
104 .b = { 104 .b = {
105 .entries = &self->dso->symbols[self->type], 105 .entries = &map->dso->symbols[map->type],
106 .refresh = ui_browser__rb_tree_refresh, 106 .refresh = ui_browser__rb_tree_refresh,
107 .seek = ui_browser__rb_tree_seek, 107 .seek = ui_browser__rb_tree_seek,
108 .write = map_browser__write, 108 .write = map_browser__write,
109 }, 109 },
110 .map = self, 110 .map = map,
111 }; 111 };
112 struct rb_node *nd; 112 struct rb_node *nd;
113 char tmp[BITS_PER_LONG / 4]; 113 char tmp[BITS_PER_LONG / 4];
diff --git a/tools/perf/ui/browsers/map.h b/tools/perf/ui/browsers/map.h
index df8581a43e17..2d58e4b3eb6f 100644
--- a/tools/perf/ui/browsers/map.h
+++ b/tools/perf/ui/browsers/map.h
@@ -2,5 +2,5 @@
2#define _PERF_UI_MAP_BROWSER_H_ 1 2#define _PERF_UI_MAP_BROWSER_H_ 1
3struct map; 3struct map;
4 4
5int map__browse(struct map *self); 5int map__browse(struct map *map);
6#endif /* _PERF_UI_MAP_BROWSER_H_ */ 6#endif /* _PERF_UI_MAP_BROWSER_H_ */
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
index 12f009e61e94..d63c68ea02a8 100644
--- a/tools/perf/ui/browsers/scripts.c
+++ b/tools/perf/ui/browsers/scripts.c
@@ -84,22 +84,22 @@ static void script_browser__write(struct ui_browser *browser,
84 slsmg_write_nstring(sline->line, browser->width); 84 slsmg_write_nstring(sline->line, browser->width);
85} 85}
86 86
87static int script_browser__run(struct perf_script_browser *self) 87static int script_browser__run(struct perf_script_browser *browser)
88{ 88{
89 int key; 89 int key;
90 90
91 if (ui_browser__show(&self->b, self->script_name, 91 if (ui_browser__show(&browser->b, browser->script_name,
92 "Press <- or ESC to exit") < 0) 92 "Press <- or ESC to exit") < 0)
93 return -1; 93 return -1;
94 94
95 while (1) { 95 while (1) {
96 key = ui_browser__run(&self->b, 0); 96 key = ui_browser__run(&browser->b, 0);
97 97
98 /* We can add some special key handling here if needed */ 98 /* We can add some special key handling here if needed */
99 break; 99 break;
100 } 100 }
101 101
102 ui_browser__hide(&self->b); 102 ui_browser__hide(&browser->b);
103 return key; 103 return key;
104} 104}
105 105
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c
index f538794615db..9c7ff8d31b27 100644
--- a/tools/perf/ui/gtk/annotate.c
+++ b/tools/perf/ui/gtk/annotate.c
@@ -154,9 +154,9 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
154 return 0; 154 return 0;
155} 155}
156 156
157int symbol__gtk_annotate(struct symbol *sym, struct map *map, 157static int symbol__gtk_annotate(struct symbol *sym, struct map *map,
158 struct perf_evsel *evsel, 158 struct perf_evsel *evsel,
159 struct hist_browser_timer *hbt) 159 struct hist_browser_timer *hbt)
160{ 160{
161 GtkWidget *window; 161 GtkWidget *window;
162 GtkWidget *notebook; 162 GtkWidget *notebook;
@@ -226,6 +226,13 @@ int symbol__gtk_annotate(struct symbol *sym, struct map *map,
226 return 0; 226 return 0;
227} 227}
228 228
229int hist_entry__gtk_annotate(struct hist_entry *he,
230 struct perf_evsel *evsel,
231 struct hist_browser_timer *hbt)
232{
233 return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt);
234}
235
229void perf_gtk__show_annotations(void) 236void perf_gtk__show_annotations(void)
230{ 237{
231 GtkWidget *window; 238 GtkWidget *window;
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index c95012cdb438..c24d91221290 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -43,7 +43,7 @@ const char *perf_gtk__get_percent_color(double percent)
43 return NULL; 43 return NULL;
44} 44}
45 45
46#ifdef HAVE_GTK_INFO_BAR 46#ifdef HAVE_GTK_INFO_BAR_SUPPORT
47GtkWidget *perf_gtk__setup_info_bar(void) 47GtkWidget *perf_gtk__setup_info_bar(void)
48{ 48{
49 GtkWidget *info_bar; 49 GtkWidget *info_bar;
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 3d96785ef155..0a9173ff9a61 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -12,7 +12,7 @@ struct perf_gtk_context {
12 GtkWidget *main_window; 12 GtkWidget *main_window;
13 GtkWidget *notebook; 13 GtkWidget *notebook;
14 14
15#ifdef HAVE_GTK_INFO_BAR 15#ifdef HAVE_GTK_INFO_BAR_SUPPORT
16 GtkWidget *info_bar; 16 GtkWidget *info_bar;
17 GtkWidget *message_label; 17 GtkWidget *message_label;
18#endif 18#endif
@@ -20,6 +20,9 @@ struct perf_gtk_context {
20 guint statbar_ctx_id; 20 guint statbar_ctx_id;
21}; 21};
22 22
23int perf_gtk__init(void);
24void perf_gtk__exit(bool wait_for_ok);
25
23extern struct perf_gtk_context *pgctx; 26extern struct perf_gtk_context *pgctx;
24 27
25static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx) 28static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx)
@@ -31,7 +34,7 @@ struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
31int perf_gtk__deactivate_context(struct perf_gtk_context **ctx); 34int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
32 35
33void perf_gtk__init_helpline(void); 36void perf_gtk__init_helpline(void);
34void perf_gtk__init_progress(void); 37void gtk_ui_progress__init(void);
35void perf_gtk__init_hpp(void); 38void perf_gtk__init_hpp(void);
36 39
37void perf_gtk__signal(int sig); 40void perf_gtk__signal(int sig);
@@ -39,7 +42,7 @@ void perf_gtk__resize_window(GtkWidget *window);
39const char *perf_gtk__get_percent_color(double percent); 42const char *perf_gtk__get_percent_color(double percent);
40GtkWidget *perf_gtk__setup_statusbar(void); 43GtkWidget *perf_gtk__setup_statusbar(void);
41 44
42#ifdef HAVE_GTK_INFO_BAR 45#ifdef HAVE_GTK_INFO_BAR_SUPPORT
43GtkWidget *perf_gtk__setup_info_bar(void); 46GtkWidget *perf_gtk__setup_info_bar(void);
44#else 47#else
45static inline GtkWidget *perf_gtk__setup_info_bar(void) 48static inline GtkWidget *perf_gtk__setup_info_bar(void)
@@ -48,4 +51,17 @@ static inline GtkWidget *perf_gtk__setup_info_bar(void)
48} 51}
49#endif 52#endif
50 53
54struct perf_evsel;
55struct perf_evlist;
56struct hist_entry;
57struct hist_browser_timer;
58
59int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
60 struct hist_browser_timer *hbt,
61 float min_pcnt);
62int hist_entry__gtk_annotate(struct hist_entry *he,
63 struct perf_evsel *evsel,
64 struct hist_browser_timer *hbt);
65void perf_gtk__show_annotations(void);
66
51#endif /* _PERF_GTK_H_ */ 67#endif /* _PERF_GTK_H_ */
diff --git a/tools/perf/ui/gtk/progress.c b/tools/perf/ui/gtk/progress.c
index 482bcf3df9b7..b656655fbc39 100644
--- a/tools/perf/ui/gtk/progress.c
+++ b/tools/perf/ui/gtk/progress.c
@@ -7,14 +7,14 @@
7static GtkWidget *dialog; 7static GtkWidget *dialog;
8static GtkWidget *progress; 8static GtkWidget *progress;
9 9
10static void gtk_progress_update(u64 curr, u64 total, const char *title) 10static void gtk_ui_progress__update(struct ui_progress *p)
11{ 11{
12 double fraction = total ? 1.0 * curr / total : 0.0; 12 double fraction = p->total ? 1.0 * p->curr / p->total : 0.0;
13 char buf[1024]; 13 char buf[1024];
14 14
15 if (dialog == NULL) { 15 if (dialog == NULL) {
16 GtkWidget *vbox = gtk_vbox_new(TRUE, 5); 16 GtkWidget *vbox = gtk_vbox_new(TRUE, 5);
17 GtkWidget *label = gtk_label_new(title); 17 GtkWidget *label = gtk_label_new(p->title);
18 18
19 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL); 19 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
20 progress = gtk_progress_bar_new(); 20 progress = gtk_progress_bar_new();
@@ -32,7 +32,7 @@ static void gtk_progress_update(u64 curr, u64 total, const char *title)
32 } 32 }
33 33
34 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction); 34 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction);
35 snprintf(buf, sizeof(buf), "%"PRIu64" / %"PRIu64, curr, total); 35 snprintf(buf, sizeof(buf), "%"PRIu64" / %"PRIu64, p->curr, p->total);
36 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), buf); 36 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), buf);
37 37
38 /* we didn't call gtk_main yet, so do it manually */ 38 /* we didn't call gtk_main yet, so do it manually */
@@ -40,7 +40,7 @@ static void gtk_progress_update(u64 curr, u64 total, const char *title)
40 gtk_main_iteration(); 40 gtk_main_iteration();
41} 41}
42 42
43static void gtk_progress_finish(void) 43static void gtk_ui_progress__finish(void)
44{ 44{
45 /* this will also destroy all of its children */ 45 /* this will also destroy all of its children */
46 gtk_widget_destroy(dialog); 46 gtk_widget_destroy(dialog);
@@ -48,12 +48,12 @@ static void gtk_progress_finish(void)
48 dialog = NULL; 48 dialog = NULL;
49} 49}
50 50
51static struct ui_progress gtk_progress_fns = { 51static struct ui_progress_ops gtk_ui_progress__ops = {
52 .update = gtk_progress_update, 52 .update = gtk_ui_progress__update,
53 .finish = gtk_progress_finish, 53 .finish = gtk_ui_progress__finish,
54}; 54};
55 55
56void perf_gtk__init_progress(void) 56void gtk_ui_progress__init(void)
57{ 57{
58 progress_fns = &gtk_progress_fns; 58 ui_progress__ops = &gtk_ui_progress__ops;
59} 59}
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
index 6c2dd2e423f3..1d57676f8212 100644
--- a/tools/perf/ui/gtk/setup.c
+++ b/tools/perf/ui/gtk/setup.c
@@ -8,7 +8,7 @@ int perf_gtk__init(void)
8{ 8{
9 perf_error__register(&perf_gtk_eops); 9 perf_error__register(&perf_gtk_eops);
10 perf_gtk__init_helpline(); 10 perf_gtk__init_helpline();
11 perf_gtk__init_progress(); 11 gtk_ui_progress__init();
12 perf_gtk__init_hpp(); 12 perf_gtk__init_hpp();
13 13
14 return gtk_init_check(NULL, NULL) ? 0 : -1; 14 return gtk_init_check(NULL, NULL) ? 0 : -1;
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
index c06942a41c78..696c1fbe4248 100644
--- a/tools/perf/ui/gtk/util.c
+++ b/tools/perf/ui/gtk/util.c
@@ -53,7 +53,7 @@ static int perf_gtk__error(const char *format, va_list args)
53 return 0; 53 return 0;
54} 54}
55 55
56#ifdef HAVE_GTK_INFO_BAR 56#ifdef HAVE_GTK_INFO_BAR_SUPPORT
57static int perf_gtk__warning_info_bar(const char *format, va_list args) 57static int perf_gtk__warning_info_bar(const char *format, va_list args)
58{ 58{
59 char *msg; 59 char *msg;
@@ -105,7 +105,7 @@ static int perf_gtk__warning_statusbar(const char *format, va_list args)
105 105
106struct perf_error_ops perf_gtk_eops = { 106struct perf_error_ops perf_gtk_eops = {
107 .error = perf_gtk__error, 107 .error = perf_gtk__error,
108#ifdef HAVE_GTK_INFO_BAR 108#ifdef HAVE_GTK_INFO_BAR_SUPPORT
109 .warning = perf_gtk__warning_info_bar, 109 .warning = perf_gtk__warning_info_bar,
110#else 110#else
111 .warning = perf_gtk__warning_statusbar, 111 .warning = perf_gtk__warning_statusbar,
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 0a193281eba8..78f4c92e9b73 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -117,7 +117,7 @@ static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
117 struct perf_hpp *hpp, struct hist_entry *he) \ 117 struct perf_hpp *hpp, struct hist_entry *he) \
118{ \ 118{ \
119 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ 119 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
120 (hpp_snprint_fn)percent_color_snprintf, true); \ 120 percent_color_snprintf, true); \
121} 121}
122 122
123#define __HPP_ENTRY_PERCENT_FN(_type, _field) \ 123#define __HPP_ENTRY_PERCENT_FN(_type, _field) \
diff --git a/tools/perf/ui/progress.c b/tools/perf/ui/progress.c
index 3ec695607a4d..a0f24c7115c5 100644
--- a/tools/perf/ui/progress.c
+++ b/tools/perf/ui/progress.c
@@ -1,26 +1,38 @@
1#include "../cache.h" 1#include "../cache.h"
2#include "progress.h" 2#include "progress.h"
3 3
4static void nop_progress_update(u64 curr __maybe_unused, 4static void null_progress__update(struct ui_progress *p __maybe_unused)
5 u64 total __maybe_unused,
6 const char *title __maybe_unused)
7{ 5{
8} 6}
9 7
10static struct ui_progress default_progress_fns = 8static struct ui_progress_ops null_progress__ops =
11{ 9{
12 .update = nop_progress_update, 10 .update = null_progress__update,
13}; 11};
14 12
15struct ui_progress *progress_fns = &default_progress_fns; 13struct ui_progress_ops *ui_progress__ops = &null_progress__ops;
16 14
17void ui_progress__update(u64 curr, u64 total, const char *title) 15void ui_progress__update(struct ui_progress *p, u64 adv)
18{ 16{
19 return progress_fns->update(curr, total, title); 17 p->curr += adv;
18
19 if (p->curr >= p->next) {
20 p->next += p->step;
21 ui_progress__ops->update(p);
22 }
23}
24
25void ui_progress__init(struct ui_progress *p, u64 total, const char *title)
26{
27 p->curr = 0;
28 p->next = p->step = total / 16;
29 p->total = total;
30 p->title = title;
31
20} 32}
21 33
22void ui_progress__finish(void) 34void ui_progress__finish(void)
23{ 35{
24 if (progress_fns->finish) 36 if (ui_progress__ops->finish)
25 progress_fns->finish(); 37 ui_progress__ops->finish();
26} 38}
diff --git a/tools/perf/ui/progress.h b/tools/perf/ui/progress.h
index 257cc224f9cf..29ec8efffefb 100644
--- a/tools/perf/ui/progress.h
+++ b/tools/perf/ui/progress.h
@@ -3,16 +3,21 @@
3 3
4#include <../types.h> 4#include <../types.h>
5 5
6void ui_progress__finish(void);
7
6struct ui_progress { 8struct ui_progress {
7 void (*update)(u64, u64, const char *); 9 const char *title;
8 void (*finish)(void); 10 u64 curr, next, step, total;
9}; 11};
12
13void ui_progress__init(struct ui_progress *p, u64 total, const char *title);
14void ui_progress__update(struct ui_progress *p, u64 adv);
10 15
11extern struct ui_progress *progress_fns; 16struct ui_progress_ops {
12 17 void (*update)(struct ui_progress *p);
13void ui_progress__init(void); 18 void (*finish)(void);
19};
14 20
15void ui_progress__update(u64 curr, u64 total, const char *title); 21extern struct ui_progress_ops *ui_progress__ops;
16void ui_progress__finish(void);
17 22
18#endif 23#endif
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index 47d9a571f261..5df5140a9f29 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -1,10 +1,64 @@
1#include <pthread.h> 1#include <pthread.h>
2#include <dlfcn.h>
2 3
3#include "../util/cache.h" 4#include "../util/cache.h"
4#include "../util/debug.h" 5#include "../util/debug.h"
5#include "../util/hist.h" 6#include "../util/hist.h"
6 7
7pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; 8pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
9void *perf_gtk_handle;
10
11#ifdef HAVE_GTK2_SUPPORT
12static int setup_gtk_browser(void)
13{
14 int (*perf_ui_init)(void);
15
16 if (perf_gtk_handle)
17 return 0;
18
19 perf_gtk_handle = dlopen(PERF_GTK_DSO, RTLD_LAZY);
20 if (perf_gtk_handle == NULL) {
21 char buf[PATH_MAX];
22 scnprintf(buf, sizeof(buf), "%s/%s", LIBDIR, PERF_GTK_DSO);
23 perf_gtk_handle = dlopen(buf, RTLD_LAZY);
24 }
25 if (perf_gtk_handle == NULL)
26 return -1;
27
28 perf_ui_init = dlsym(perf_gtk_handle, "perf_gtk__init");
29 if (perf_ui_init == NULL)
30 goto out_close;
31
32 if (perf_ui_init() == 0)
33 return 0;
34
35out_close:
36 dlclose(perf_gtk_handle);
37 return -1;
38}
39
40static void exit_gtk_browser(bool wait_for_ok)
41{
42 void (*perf_ui_exit)(bool);
43
44 if (perf_gtk_handle == NULL)
45 return;
46
47 perf_ui_exit = dlsym(perf_gtk_handle, "perf_gtk__exit");
48 if (perf_ui_exit == NULL)
49 goto out_close;
50
51 perf_ui_exit(wait_for_ok);
52
53out_close:
54 dlclose(perf_gtk_handle);
55
56 perf_gtk_handle = NULL;
57}
58#else
59static inline int setup_gtk_browser(void) { return -1; }
60static inline void exit_gtk_browser(bool wait_for_ok __maybe_unused) {}
61#endif
8 62
9void setup_browser(bool fallback_to_pager) 63void setup_browser(bool fallback_to_pager)
10{ 64{
@@ -17,8 +71,11 @@ void setup_browser(bool fallback_to_pager)
17 71
18 switch (use_browser) { 72 switch (use_browser) {
19 case 2: 73 case 2:
20 if (perf_gtk__init() == 0) 74 if (setup_gtk_browser() == 0)
21 break; 75 break;
76 printf("GTK browser requested but could not find %s\n",
77 PERF_GTK_DSO);
78 sleep(1);
22 /* fall through */ 79 /* fall through */
23 case 1: 80 case 1:
24 use_browser = 1; 81 use_browser = 1;
@@ -39,7 +96,7 @@ void exit_browser(bool wait_for_ok)
39{ 96{
40 switch (use_browser) { 97 switch (use_browser) {
41 case 2: 98 case 2:
42 perf_gtk__exit(wait_for_ok); 99 exit_gtk_browser(wait_for_ok);
43 break; 100 break;
44 101
45 case 1: 102 case 1:
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 194e2f42ff5d..c244cb524ef2 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -213,20 +213,19 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
213 return ret; 213 return ret;
214} 214}
215 215
216static size_t __callchain__fprintf_flat(FILE *fp, 216static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node,
217 struct callchain_node *self,
218 u64 total_samples) 217 u64 total_samples)
219{ 218{
220 struct callchain_list *chain; 219 struct callchain_list *chain;
221 size_t ret = 0; 220 size_t ret = 0;
222 221
223 if (!self) 222 if (!node)
224 return 0; 223 return 0;
225 224
226 ret += __callchain__fprintf_flat(fp, self->parent, total_samples); 225 ret += __callchain__fprintf_flat(fp, node->parent, total_samples);
227 226
228 227
229 list_for_each_entry(chain, &self->val, list) { 228 list_for_each_entry(chain, &node->val, list) {
230 if (chain->ip >= PERF_CONTEXT_MAX) 229 if (chain->ip >= PERF_CONTEXT_MAX)
231 continue; 230 continue;
232 if (chain->ms.sym) 231 if (chain->ms.sym)
@@ -239,15 +238,14 @@ static size_t __callchain__fprintf_flat(FILE *fp,
239 return ret; 238 return ret;
240} 239}
241 240
242static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self, 241static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
243 u64 total_samples) 242 u64 total_samples)
244{ 243{
245 size_t ret = 0; 244 size_t ret = 0;
246 u32 entries_printed = 0; 245 u32 entries_printed = 0;
247 struct rb_node *rb_node;
248 struct callchain_node *chain; 246 struct callchain_node *chain;
247 struct rb_node *rb_node = rb_first(tree);
249 248
250 rb_node = rb_first(self);
251 while (rb_node) { 249 while (rb_node) {
252 double percent; 250 double percent;
253 251
@@ -315,8 +313,7 @@ static inline void advance_hpp(struct perf_hpp *hpp, int inc)
315} 313}
316 314
317static int hist_entry__period_snprintf(struct perf_hpp *hpp, 315static int hist_entry__period_snprintf(struct perf_hpp *hpp,
318 struct hist_entry *he, 316 struct hist_entry *he)
319 bool color)
320{ 317{
321 const char *sep = symbol_conf.field_sep; 318 const char *sep = symbol_conf.field_sep;
322 struct perf_hpp_fmt *fmt; 319 struct perf_hpp_fmt *fmt;
@@ -338,7 +335,7 @@ static int hist_entry__period_snprintf(struct perf_hpp *hpp,
338 } else 335 } else
339 first = false; 336 first = false;
340 337
341 if (color && fmt->color) 338 if (perf_hpp__use_color() && fmt->color)
342 ret = fmt->color(fmt, hpp, he); 339 ret = fmt->color(fmt, hpp, he);
343 else 340 else
344 ret = fmt->entry(fmt, hpp, he); 341 ret = fmt->entry(fmt, hpp, he);
@@ -358,12 +355,11 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
358 .buf = bf, 355 .buf = bf,
359 .size = size, 356 .size = size,
360 }; 357 };
361 bool color = !symbol_conf.field_sep;
362 358
363 if (size == 0 || size > bfsz) 359 if (size == 0 || size > bfsz)
364 size = hpp.size = bfsz; 360 size = hpp.size = bfsz;
365 361
366 ret = hist_entry__period_snprintf(&hpp, he, color); 362 ret = hist_entry__period_snprintf(&hpp, he);
367 hist_entry__sort_snprintf(he, bf + ret, size - ret, hists); 363 hist_entry__sort_snprintf(he, bf + ret, size - ret, hists);
368 364
369 ret = fprintf(fp, "%s\n", bf); 365 ret = fprintf(fp, "%s\n", bf);
@@ -482,6 +478,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
482 478
483print_entries: 479print_entries:
484 linesz = hists__sort_list_width(hists) + 3 + 1; 480 linesz = hists__sort_list_width(hists) + 3 + 1;
481 linesz += perf_hpp__color_overhead();
485 line = malloc(linesz); 482 line = malloc(linesz);
486 if (line == NULL) { 483 if (line == NULL) {
487 ret = -1; 484 ret = -1;
diff --git a/tools/perf/ui/tui/progress.c b/tools/perf/ui/tui/progress.c
index 6c2184d53cbf..c61d14b101e0 100644
--- a/tools/perf/ui/tui/progress.c
+++ b/tools/perf/ui/tui/progress.c
@@ -2,9 +2,10 @@
2#include "../progress.h" 2#include "../progress.h"
3#include "../libslang.h" 3#include "../libslang.h"
4#include "../ui.h" 4#include "../ui.h"
5#include "tui.h"
5#include "../browser.h" 6#include "../browser.h"
6 7
7static void tui_progress__update(u64 curr, u64 total, const char *title) 8static void tui_progress__update(struct ui_progress *p)
8{ 9{
9 int bar, y; 10 int bar, y;
10 /* 11 /*
@@ -14,29 +15,30 @@ static void tui_progress__update(u64 curr, u64 total, const char *title)
14 if (use_browser <= 0) 15 if (use_browser <= 0)
15 return; 16 return;
16 17
17 if (total == 0) 18 if (p->total == 0)
18 return; 19 return;
19 20
20 ui__refresh_dimensions(true); 21 ui__refresh_dimensions(false);
21 pthread_mutex_lock(&ui__lock); 22 pthread_mutex_lock(&ui__lock);
22 y = SLtt_Screen_Rows / 2 - 2; 23 y = SLtt_Screen_Rows / 2 - 2;
23 SLsmg_set_color(0); 24 SLsmg_set_color(0);
24 SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols); 25 SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);
25 SLsmg_gotorc(y++, 1); 26 SLsmg_gotorc(y++, 1);
26 SLsmg_write_string((char *)title); 27 SLsmg_write_string((char *)p->title);
28 SLsmg_fill_region(y, 1, 1, SLtt_Screen_Cols - 2, ' ');
27 SLsmg_set_color(HE_COLORSET_SELECTED); 29 SLsmg_set_color(HE_COLORSET_SELECTED);
28 bar = ((SLtt_Screen_Cols - 2) * curr) / total; 30 bar = ((SLtt_Screen_Cols - 2) * p->curr) / p->total;
29 SLsmg_fill_region(y, 1, 1, bar, ' '); 31 SLsmg_fill_region(y, 1, 1, bar, ' ');
30 SLsmg_refresh(); 32 SLsmg_refresh();
31 pthread_mutex_unlock(&ui__lock); 33 pthread_mutex_unlock(&ui__lock);
32} 34}
33 35
34static struct ui_progress tui_progress_fns = 36static struct ui_progress_ops tui_progress__ops =
35{ 37{
36 .update = tui_progress__update, 38 .update = tui_progress__update,
37}; 39};
38 40
39void ui_progress__init(void) 41void tui_progress__init(void)
40{ 42{
41 progress_fns = &tui_progress_fns; 43 ui_progress__ops = &tui_progress__ops;
42} 44}
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index b9401482d110..2f612562978c 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -9,6 +9,7 @@
9#include "../util.h" 9#include "../util.h"
10#include "../libslang.h" 10#include "../libslang.h"
11#include "../keysyms.h" 11#include "../keysyms.h"
12#include "tui.h"
12 13
13static volatile int ui__need_resize; 14static volatile int ui__need_resize;
14 15
@@ -119,7 +120,7 @@ int ui__init(void)
119 120
120 ui_helpline__init(); 121 ui_helpline__init();
121 ui_browser__init(); 122 ui_browser__init();
122 ui_progress__init(); 123 tui_progress__init();
123 124
124 signal(SIGSEGV, ui__signal); 125 signal(SIGSEGV, ui__signal);
125 signal(SIGFPE, ui__signal); 126 signal(SIGFPE, ui__signal);
diff --git a/tools/perf/ui/tui/tui.h b/tools/perf/ui/tui/tui.h
new file mode 100644
index 000000000000..18961c7b6ec5
--- /dev/null
+++ b/tools/perf/ui/tui/tui.h
@@ -0,0 +1,6 @@
1#ifndef _PERF_TUI_H_
2#define _PERF_TUI_H_ 1
3
4void tui_progress__init(void);
5
6#endif /* _PERF_TUI_H_ */
diff --git a/tools/perf/ui/ui.h b/tools/perf/ui/ui.h
index 70cb0d4eb8aa..ab88383f8be8 100644
--- a/tools/perf/ui/ui.h
+++ b/tools/perf/ui/ui.h
@@ -6,13 +6,14 @@
6#include <linux/compiler.h> 6#include <linux/compiler.h>
7 7
8extern pthread_mutex_t ui__lock; 8extern pthread_mutex_t ui__lock;
9extern void *perf_gtk_handle;
9 10
10extern int use_browser; 11extern int use_browser;
11 12
12void setup_browser(bool fallback_to_pager); 13void setup_browser(bool fallback_to_pager);
13void exit_browser(bool wait_for_ok); 14void exit_browser(bool wait_for_ok);
14 15
15#ifdef SLANG_SUPPORT 16#ifdef HAVE_SLANG_SUPPORT
16int ui__init(void); 17int ui__init(void);
17void ui__exit(bool wait_for_ok); 18void ui__exit(bool wait_for_ok);
18#else 19#else
@@ -23,17 +24,6 @@ static inline int ui__init(void)
23static inline void ui__exit(bool wait_for_ok __maybe_unused) {} 24static inline void ui__exit(bool wait_for_ok __maybe_unused) {}
24#endif 25#endif
25 26
26#ifdef GTK2_SUPPORT
27int perf_gtk__init(void);
28void perf_gtk__exit(bool wait_for_ok);
29#else
30static inline int perf_gtk__init(void)
31{
32 return -1;
33}
34static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {}
35#endif
36
37void ui__refresh_dimensions(bool force); 27void ui__refresh_dimensions(bool force);
38 28
39#endif /* _PERF_UI_H_ */ 29#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 15a77b7c0e36..39f17507578d 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -19,6 +19,9 @@ if test -d ../../.git -o -f ../../.git
19then 19then
20 TAG=$(git describe --abbrev=0 --match "v[0-9].[0-9]*" 2>/dev/null ) 20 TAG=$(git describe --abbrev=0 --match "v[0-9].[0-9]*" 2>/dev/null )
21 CID=$(git log -1 --abbrev=4 --pretty=format:"%h" 2>/dev/null) && CID="-g$CID" 21 CID=$(git log -1 --abbrev=4 --pretty=format:"%h" 2>/dev/null) && CID="-g$CID"
22elif test -f ../../PERF-VERSION-FILE
23then
24 TAG=$(cut -d' ' -f3 ../../PERF-VERSION-FILE | sed -e 's/\"//g')
22fi 25fi
23if test -z "$TAG" 26if test -z "$TAG"
24then 27then
@@ -40,7 +43,7 @@ else
40 VC=unset 43 VC=unset
41fi 44fi
42test "$VN" = "$VC" || { 45test "$VN" = "$VC" || {
43 echo >&2 "PERF_VERSION = $VN" 46 echo >&2 " PERF_VERSION = $VN"
44 echo "#define PERF_VERSION \"$VN\"" >$GVF 47 echo "#define PERF_VERSION \"$VN\"" >$GVF
45} 48}
46 49
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 7eae5488ecea..cf6242c92ee2 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -825,20 +825,16 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
825 dl->ops.target.offset = dl->ops.target.addr - 825 dl->ops.target.offset = dl->ops.target.addr -
826 map__rip_2objdump(map, sym->start); 826 map__rip_2objdump(map, sym->start);
827 827
828 /* 828 /* kcore has no symbols, so add the call target name */
829 * kcore has no symbols, so add the call target name if it is on the
830 * same map.
831 */
832 if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) { 829 if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) {
833 struct symbol *s; 830 struct addr_map_symbol target = {
834 u64 ip = dl->ops.target.addr; 831 .map = map,
835 832 .addr = dl->ops.target.addr,
836 if (ip >= map->start && ip <= map->end) { 833 };
837 ip = map->map_ip(map, ip); 834
838 s = map__find_symbol(map, ip, NULL); 835 if (!map_groups__find_ams(&target, NULL) &&
839 if (s && s->start == ip) 836 target.sym->start == target.al_addr)
840 dl->ops.target.name = strdup(s->name); 837 dl->ops.target.name = strdup(target.sym->name);
841 }
842 } 838 }
843 839
844 disasm__add(&notes->src->source, dl); 840 disasm__add(&notes->src->source, dl);
@@ -879,6 +875,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
879 FILE *file; 875 FILE *file;
880 int err = 0; 876 int err = 0;
881 char symfs_filename[PATH_MAX]; 877 char symfs_filename[PATH_MAX];
878 struct kcore_extract kce;
879 bool delete_extract = false;
882 880
883 if (filename) { 881 if (filename) {
884 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", 882 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
@@ -940,6 +938,23 @@ fallback:
940 pr_debug("annotating [%p] %30s : [%p] %30s\n", 938 pr_debug("annotating [%p] %30s : [%p] %30s\n",
941 dso, dso->long_name, sym, sym->name); 939 dso, dso->long_name, sym, sym->name);
942 940
941 if (dso__is_kcore(dso)) {
942 kce.kcore_filename = symfs_filename;
943 kce.addr = map__rip_2objdump(map, sym->start);
944 kce.offs = sym->start;
945 kce.len = sym->end + 1 - sym->start;
946 if (!kcore_extract__create(&kce)) {
947 delete_extract = true;
948 strlcpy(symfs_filename, kce.extract_filename,
949 sizeof(symfs_filename));
950 if (free_filename) {
951 free(filename);
952 free_filename = false;
953 }
954 filename = symfs_filename;
955 }
956 }
957
943 snprintf(command, sizeof(command), 958 snprintf(command, sizeof(command),
944 "%s %s%s --start-address=0x%016" PRIx64 959 "%s %s%s --start-address=0x%016" PRIx64
945 " --stop-address=0x%016" PRIx64 960 " --stop-address=0x%016" PRIx64
@@ -972,6 +987,8 @@ fallback:
972 987
973 pclose(file); 988 pclose(file);
974out_free_filename: 989out_free_filename:
990 if (delete_extract)
991 kcore_extract__delete(&kce);
975 if (free_filename) 992 if (free_filename)
976 free(filename); 993 free(filename);
977 return err; 994 return err;
@@ -1070,7 +1087,7 @@ static void symbol__free_source_line(struct symbol *sym, int len)
1070 (sizeof(src_line->p) * (src_line->nr_pcnt - 1)); 1087 (sizeof(src_line->p) * (src_line->nr_pcnt - 1));
1071 1088
1072 for (i = 0; i < len; i++) { 1089 for (i = 0; i < len; i++) {
1073 free(src_line->path); 1090 free_srcline(src_line->path);
1074 src_line = (void *)src_line + sizeof_src_line; 1091 src_line = (void *)src_line + sizeof_src_line;
1075 } 1092 }
1076 1093
@@ -1081,13 +1098,11 @@ static void symbol__free_source_line(struct symbol *sym, int len)
1081/* Get the filename:line for the colored entries */ 1098/* Get the filename:line for the colored entries */
1082static int symbol__get_source_line(struct symbol *sym, struct map *map, 1099static int symbol__get_source_line(struct symbol *sym, struct map *map,
1083 struct perf_evsel *evsel, 1100 struct perf_evsel *evsel,
1084 struct rb_root *root, int len, 1101 struct rb_root *root, int len)
1085 const char *filename)
1086{ 1102{
1087 u64 start; 1103 u64 start;
1088 int i, k; 1104 int i, k;
1089 int evidx = evsel->idx; 1105 int evidx = evsel->idx;
1090 char cmd[PATH_MAX * 2];
1091 struct source_line *src_line; 1106 struct source_line *src_line;
1092 struct annotation *notes = symbol__annotation(sym); 1107 struct annotation *notes = symbol__annotation(sym);
1093 struct sym_hist *h = annotation__histogram(notes, evidx); 1108 struct sym_hist *h = annotation__histogram(notes, evidx);
@@ -1115,10 +1130,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
1115 start = map__rip_2objdump(map, sym->start); 1130 start = map__rip_2objdump(map, sym->start);
1116 1131
1117 for (i = 0; i < len; i++) { 1132 for (i = 0; i < len; i++) {
1118 char *path = NULL;
1119 size_t line_len;
1120 u64 offset; 1133 u64 offset;
1121 FILE *fp;
1122 double percent_max = 0.0; 1134 double percent_max = 0.0;
1123 1135
1124 src_line->nr_pcnt = nr_pcnt; 1136 src_line->nr_pcnt = nr_pcnt;
@@ -1135,23 +1147,9 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
1135 goto next; 1147 goto next;
1136 1148
1137 offset = start + i; 1149 offset = start + i;
1138 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); 1150 src_line->path = get_srcline(map->dso, offset);
1139 fp = popen(cmd, "r");
1140 if (!fp)
1141 goto next;
1142
1143 if (getline(&path, &line_len, fp) < 0 || !line_len)
1144 goto next_close;
1145
1146 src_line->path = malloc(sizeof(char) * line_len + 1);
1147 if (!src_line->path)
1148 goto next_close;
1149
1150 strcpy(src_line->path, path);
1151 insert_source_line(&tmp_root, src_line); 1151 insert_source_line(&tmp_root, src_line);
1152 1152
1153 next_close:
1154 pclose(fp);
1155 next: 1153 next:
1156 src_line = (void *)src_line + sizeof_src_line; 1154 src_line = (void *)src_line + sizeof_src_line;
1157 } 1155 }
@@ -1192,7 +1190,7 @@ static void print_summary(struct rb_root *root, const char *filename)
1192 1190
1193 path = src_line->path; 1191 path = src_line->path;
1194 color = get_percent_color(percent_max); 1192 color = get_percent_color(percent_max);
1195 color_fprintf(stdout, color, " %s", path); 1193 color_fprintf(stdout, color, " %s\n", path);
1196 1194
1197 node = rb_next(node); 1195 node = rb_next(node);
1198 } 1196 }
@@ -1356,7 +1354,6 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
1356 bool full_paths, int min_pcnt, int max_lines) 1354 bool full_paths, int min_pcnt, int max_lines)
1357{ 1355{
1358 struct dso *dso = map->dso; 1356 struct dso *dso = map->dso;
1359 const char *filename = dso->long_name;
1360 struct rb_root source_line = RB_ROOT; 1357 struct rb_root source_line = RB_ROOT;
1361 u64 len; 1358 u64 len;
1362 1359
@@ -1366,9 +1363,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
1366 len = symbol__size(sym); 1363 len = symbol__size(sym);
1367 1364
1368 if (print_lines) { 1365 if (print_lines) {
1369 symbol__get_source_line(sym, map, evsel, &source_line, 1366 symbol__get_source_line(sym, map, evsel, &source_line, len);
1370 len, filename); 1367 print_summary(&source_line, dso->long_name);
1371 print_summary(&source_line, filename);
1372 } 1368 }
1373 1369
1374 symbol__annotate_printf(sym, map, evsel, full_paths, 1370 symbol__annotate_printf(sym, map, evsel, full_paths,
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index af755156d278..834b7b57b788 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -150,7 +150,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
150 struct perf_evsel *evsel, bool print_lines, 150 struct perf_evsel *evsel, bool print_lines,
151 bool full_paths, int min_pcnt, int max_lines); 151 bool full_paths, int min_pcnt, int max_lines);
152 152
153#ifdef SLANG_SUPPORT 153#ifdef HAVE_SLANG_SUPPORT
154int symbol__tui_annotate(struct symbol *sym, struct map *map, 154int symbol__tui_annotate(struct symbol *sym, struct map *map,
155 struct perf_evsel *evsel, 155 struct perf_evsel *evsel,
156 struct hist_browser_timer *hbt); 156 struct hist_browser_timer *hbt);
@@ -165,30 +165,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
165} 165}
166#endif 166#endif
167 167
168#ifdef GTK2_SUPPORT
169int symbol__gtk_annotate(struct symbol *sym, struct map *map,
170 struct perf_evsel *evsel,
171 struct hist_browser_timer *hbt);
172
173static inline int hist_entry__gtk_annotate(struct hist_entry *he,
174 struct perf_evsel *evsel,
175 struct hist_browser_timer *hbt)
176{
177 return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt);
178}
179
180void perf_gtk__show_annotations(void);
181#else
182static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused,
183 struct perf_evsel *evsel __maybe_unused,
184 struct hist_browser_timer *hbt __maybe_unused)
185{
186 return 0;
187}
188
189static inline void perf_gtk__show_annotations(void) {}
190#endif
191
192extern const char *disassembler_style; 168extern const char *disassembler_style;
193 169
194#endif /* __PERF_ANNOTATE_H */ 170#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 7ded71d19d75..a92770c98cc7 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -89,14 +89,14 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
89 return raw - build_id; 89 return raw - build_id;
90} 90}
91 91
92char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 92char *dso__build_id_filename(struct dso *dso, char *bf, size_t size)
93{ 93{
94 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 94 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
95 95
96 if (!self->has_build_id) 96 if (!dso->has_build_id)
97 return NULL; 97 return NULL;
98 98
99 build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex); 99 build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex);
100 if (bf == NULL) { 100 if (bf == NULL) {
101 if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir, 101 if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir,
102 build_id_hex, build_id_hex + 2) < 0) 102 build_id_hex, build_id_hex + 2) < 0)
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index a811f5c62e18..929f28a7c14d 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -10,10 +10,9 @@ extern struct perf_tool build_id__mark_dso_hit_ops;
10struct dso; 10struct dso;
11 11
12int build_id__sprintf(const u8 *build_id, int len, char *bf); 12int build_id__sprintf(const u8 *build_id, int len, char *bf);
13char *dso__build_id_filename(struct dso *self, char *bf, size_t size); 13char *dso__build_id_filename(struct dso *dso, char *bf, size_t size);
14 14
15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, 15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
16 struct perf_sample *sample, struct perf_evsel *evsel, 16 struct perf_sample *sample, struct perf_evsel *evsel,
17 struct machine *machine); 17 struct machine *machine);
18
19#endif 18#endif
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 26e367239873..7b176dd02e1a 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -70,8 +70,7 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2
70extern char *perf_pathdup(const char *fmt, ...) 70extern char *perf_pathdup(const char *fmt, ...)
71 __attribute__((format (printf, 1, 2))); 71 __attribute__((format (printf, 1, 2)));
72 72
73#ifndef HAVE_STRLCPY 73/* Matches the libc/libbsd function attribute so we declare this unconditionally: */
74extern size_t strlcpy(char *dest, const char *src, size_t size); 74extern size_t strlcpy(char *dest, const char *src, size_t size);
75#endif
76 75
77#endif /* __PERF_CACHE_H */ 76#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 482f68081cd8..e3970e3eaacf 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -21,12 +21,6 @@
21 21
22__thread struct callchain_cursor callchain_cursor; 22__thread struct callchain_cursor callchain_cursor;
23 23
24#define chain_for_each_child(child, parent) \
25 list_for_each_entry(child, &parent->children, siblings)
26
27#define chain_for_each_child_safe(child, next, parent) \
28 list_for_each_entry_safe(child, next, &parent->children, siblings)
29
30static void 24static void
31rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 25rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
32 enum chain_mode mode) 26 enum chain_mode mode)
@@ -71,10 +65,16 @@ static void
71__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node, 65__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
72 u64 min_hit) 66 u64 min_hit)
73{ 67{
68 struct rb_node *n;
74 struct callchain_node *child; 69 struct callchain_node *child;
75 70
76 chain_for_each_child(child, node) 71 n = rb_first(&node->rb_root_in);
72 while (n) {
73 child = rb_entry(n, struct callchain_node, rb_node_in);
74 n = rb_next(n);
75
77 __sort_chain_flat(rb_root, child, min_hit); 76 __sort_chain_flat(rb_root, child, min_hit);
77 }
78 78
79 if (node->hit && node->hit >= min_hit) 79 if (node->hit && node->hit >= min_hit)
80 rb_insert_callchain(rb_root, node, CHAIN_FLAT); 80 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
@@ -94,11 +94,16 @@ sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
94static void __sort_chain_graph_abs(struct callchain_node *node, 94static void __sort_chain_graph_abs(struct callchain_node *node,
95 u64 min_hit) 95 u64 min_hit)
96{ 96{
97 struct rb_node *n;
97 struct callchain_node *child; 98 struct callchain_node *child;
98 99
99 node->rb_root = RB_ROOT; 100 node->rb_root = RB_ROOT;
101 n = rb_first(&node->rb_root_in);
102
103 while (n) {
104 child = rb_entry(n, struct callchain_node, rb_node_in);
105 n = rb_next(n);
100 106
101 chain_for_each_child(child, node) {
102 __sort_chain_graph_abs(child, min_hit); 107 __sort_chain_graph_abs(child, min_hit);
103 if (callchain_cumul_hits(child) >= min_hit) 108 if (callchain_cumul_hits(child) >= min_hit)
104 rb_insert_callchain(&node->rb_root, child, 109 rb_insert_callchain(&node->rb_root, child,
@@ -117,13 +122,18 @@ sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
117static void __sort_chain_graph_rel(struct callchain_node *node, 122static void __sort_chain_graph_rel(struct callchain_node *node,
118 double min_percent) 123 double min_percent)
119{ 124{
125 struct rb_node *n;
120 struct callchain_node *child; 126 struct callchain_node *child;
121 u64 min_hit; 127 u64 min_hit;
122 128
123 node->rb_root = RB_ROOT; 129 node->rb_root = RB_ROOT;
124 min_hit = ceil(node->children_hit * min_percent); 130 min_hit = ceil(node->children_hit * min_percent);
125 131
126 chain_for_each_child(child, node) { 132 n = rb_first(&node->rb_root_in);
133 while (n) {
134 child = rb_entry(n, struct callchain_node, rb_node_in);
135 n = rb_next(n);
136
127 __sort_chain_graph_rel(child, min_percent); 137 __sort_chain_graph_rel(child, min_percent);
128 if (callchain_cumul_hits(child) >= min_hit) 138 if (callchain_cumul_hits(child) >= min_hit)
129 rb_insert_callchain(&node->rb_root, child, 139 rb_insert_callchain(&node->rb_root, child,
@@ -173,19 +183,26 @@ create_child(struct callchain_node *parent, bool inherit_children)
173 return NULL; 183 return NULL;
174 } 184 }
175 new->parent = parent; 185 new->parent = parent;
176 INIT_LIST_HEAD(&new->children);
177 INIT_LIST_HEAD(&new->val); 186 INIT_LIST_HEAD(&new->val);
178 187
179 if (inherit_children) { 188 if (inherit_children) {
180 struct callchain_node *next; 189 struct rb_node *n;
190 struct callchain_node *child;
191
192 new->rb_root_in = parent->rb_root_in;
193 parent->rb_root_in = RB_ROOT;
181 194
182 list_splice(&parent->children, &new->children); 195 n = rb_first(&new->rb_root_in);
183 INIT_LIST_HEAD(&parent->children); 196 while (n) {
197 child = rb_entry(n, struct callchain_node, rb_node_in);
198 child->parent = new;
199 n = rb_next(n);
200 }
184 201
185 chain_for_each_child(next, new) 202 /* make it the first child */
186 next->parent = new; 203 rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
204 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
187 } 205 }
188 list_add_tail(&new->siblings, &parent->children);
189 206
190 return new; 207 return new;
191} 208}
@@ -223,7 +240,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
223 } 240 }
224} 241}
225 242
226static void 243static struct callchain_node *
227add_child(struct callchain_node *parent, 244add_child(struct callchain_node *parent,
228 struct callchain_cursor *cursor, 245 struct callchain_cursor *cursor,
229 u64 period) 246 u64 period)
@@ -235,6 +252,19 @@ add_child(struct callchain_node *parent,
235 252
236 new->children_hit = 0; 253 new->children_hit = 0;
237 new->hit = period; 254 new->hit = period;
255 return new;
256}
257
258static s64 match_chain(struct callchain_cursor_node *node,
259 struct callchain_list *cnode)
260{
261 struct symbol *sym = node->sym;
262
263 if (cnode->ms.sym && sym &&
264 callchain_param.key == CCKEY_FUNCTION)
265 return cnode->ms.sym->start - sym->start;
266 else
267 return cnode->ip - node->ip;
238} 268}
239 269
240/* 270/*
@@ -272,9 +302,33 @@ split_add_child(struct callchain_node *parent,
272 302
273 /* create a new child for the new branch if any */ 303 /* create a new child for the new branch if any */
274 if (idx_total < cursor->nr) { 304 if (idx_total < cursor->nr) {
305 struct callchain_node *first;
306 struct callchain_list *cnode;
307 struct callchain_cursor_node *node;
308 struct rb_node *p, **pp;
309
275 parent->hit = 0; 310 parent->hit = 0;
276 add_child(parent, cursor, period);
277 parent->children_hit += period; 311 parent->children_hit += period;
312
313 node = callchain_cursor_current(cursor);
314 new = add_child(parent, cursor, period);
315
316 /*
317 * This is second child since we moved parent's children
318 * to new (first) child above.
319 */
320 p = parent->rb_root_in.rb_node;
321 first = rb_entry(p, struct callchain_node, rb_node_in);
322 cnode = list_first_entry(&first->val, struct callchain_list,
323 list);
324
325 if (match_chain(node, cnode) < 0)
326 pp = &p->rb_left;
327 else
328 pp = &p->rb_right;
329
330 rb_link_node(&new->rb_node_in, p, pp);
331 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
278 } else { 332 } else {
279 parent->hit = period; 333 parent->hit = period;
280 } 334 }
@@ -291,16 +345,40 @@ append_chain_children(struct callchain_node *root,
291 u64 period) 345 u64 period)
292{ 346{
293 struct callchain_node *rnode; 347 struct callchain_node *rnode;
348 struct callchain_cursor_node *node;
349 struct rb_node **p = &root->rb_root_in.rb_node;
350 struct rb_node *parent = NULL;
351
352 node = callchain_cursor_current(cursor);
353 if (!node)
354 return;
294 355
295 /* lookup in childrens */ 356 /* lookup in childrens */
296 chain_for_each_child(rnode, root) { 357 while (*p) {
297 unsigned int ret = append_chain(rnode, cursor, period); 358 s64 ret;
359 struct callchain_list *cnode;
298 360
299 if (!ret) 361 parent = *p;
362 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
363 cnode = list_first_entry(&rnode->val, struct callchain_list,
364 list);
365
366 /* just check first entry */
367 ret = match_chain(node, cnode);
368 if (ret == 0) {
369 append_chain(rnode, cursor, period);
300 goto inc_children_hit; 370 goto inc_children_hit;
371 }
372
373 if (ret < 0)
374 p = &parent->rb_left;
375 else
376 p = &parent->rb_right;
301 } 377 }
302 /* nothing in children, add to the current node */ 378 /* nothing in children, add to the current node */
303 add_child(root, cursor, period); 379 rnode = add_child(root, cursor, period);
380 rb_link_node(&rnode->rb_node_in, parent, p);
381 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
304 382
305inc_children_hit: 383inc_children_hit:
306 root->children_hit += period; 384 root->children_hit += period;
@@ -325,28 +403,20 @@ append_chain(struct callchain_node *root,
325 */ 403 */
326 list_for_each_entry(cnode, &root->val, list) { 404 list_for_each_entry(cnode, &root->val, list) {
327 struct callchain_cursor_node *node; 405 struct callchain_cursor_node *node;
328 struct symbol *sym;
329 406
330 node = callchain_cursor_current(cursor); 407 node = callchain_cursor_current(cursor);
331 if (!node) 408 if (!node)
332 break; 409 break;
333 410
334 sym = node->sym; 411 if (match_chain(node, cnode) != 0)
335
336 if (cnode->ms.sym && sym &&
337 callchain_param.key == CCKEY_FUNCTION) {
338 if (cnode->ms.sym->start != sym->start)
339 break;
340 } else if (cnode->ip != node->ip)
341 break; 412 break;
342 413
343 if (!found) 414 found = true;
344 found = true;
345 415
346 callchain_cursor_advance(cursor); 416 callchain_cursor_advance(cursor);
347 } 417 }
348 418
349 /* matches not, relay on the parent */ 419 /* matches not, relay no the parent */
350 if (!found) { 420 if (!found) {
351 cursor->curr = curr_snap; 421 cursor->curr = curr_snap;
352 cursor->pos = start; 422 cursor->pos = start;
@@ -395,8 +465,9 @@ merge_chain_branch(struct callchain_cursor *cursor,
395 struct callchain_node *dst, struct callchain_node *src) 465 struct callchain_node *dst, struct callchain_node *src)
396{ 466{
397 struct callchain_cursor_node **old_last = cursor->last; 467 struct callchain_cursor_node **old_last = cursor->last;
398 struct callchain_node *child, *next_child; 468 struct callchain_node *child;
399 struct callchain_list *list, *next_list; 469 struct callchain_list *list, *next_list;
470 struct rb_node *n;
400 int old_pos = cursor->nr; 471 int old_pos = cursor->nr;
401 int err = 0; 472 int err = 0;
402 473
@@ -412,12 +483,16 @@ merge_chain_branch(struct callchain_cursor *cursor,
412 append_chain_children(dst, cursor, src->hit); 483 append_chain_children(dst, cursor, src->hit);
413 } 484 }
414 485
415 chain_for_each_child_safe(child, next_child, src) { 486 n = rb_first(&src->rb_root_in);
487 while (n) {
488 child = container_of(n, struct callchain_node, rb_node_in);
489 n = rb_next(n);
490 rb_erase(&child->rb_node_in, &src->rb_root_in);
491
416 err = merge_chain_branch(cursor, dst, child); 492 err = merge_chain_branch(cursor, dst, child);
417 if (err) 493 if (err)
418 break; 494 break;
419 495
420 list_del(&child->siblings);
421 free(child); 496 free(child);
422 } 497 }
423 498
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 2b585bc308cf..4f7f989876ec 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -21,11 +21,11 @@ enum chain_order {
21 21
22struct callchain_node { 22struct callchain_node {
23 struct callchain_node *parent; 23 struct callchain_node *parent;
24 struct list_head siblings;
25 struct list_head children;
26 struct list_head val; 24 struct list_head val;
27 struct rb_node rb_node; /* to sort nodes in an rbtree */ 25 struct rb_node rb_node_in; /* to insert nodes in an rbtree */
28 struct rb_root rb_root; /* sorted tree of children */ 26 struct rb_node rb_node; /* to sort nodes in an output tree */
27 struct rb_root rb_root_in; /* input tree of children */
28 struct rb_root rb_root; /* sorted output tree of children */
29 unsigned int val_nr; 29 unsigned int val_nr;
30 u64 hit; 30 u64 hit;
31 u64 children_hit; 31 u64 children_hit;
@@ -86,13 +86,12 @@ extern __thread struct callchain_cursor callchain_cursor;
86 86
87static inline void callchain_init(struct callchain_root *root) 87static inline void callchain_init(struct callchain_root *root)
88{ 88{
89 INIT_LIST_HEAD(&root->node.siblings);
90 INIT_LIST_HEAD(&root->node.children);
91 INIT_LIST_HEAD(&root->node.val); 89 INIT_LIST_HEAD(&root->node.val);
92 90
93 root->node.parent = NULL; 91 root->node.parent = NULL;
94 root->node.hit = 0; 92 root->node.hit = 0;
95 root->node.children_hit = 0; 93 root->node.children_hit = 0;
94 root->node.rb_root_in = RB_ROOT;
96 root->max_depth = 0; 95 root->max_depth = 0;
97} 96}
98 97
@@ -147,6 +146,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
147 146
148struct option; 147struct option;
149 148
149int record_parse_callchain(const char *arg, struct perf_record_opts *opts);
150int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); 150int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
151int record_callchain_opt(const struct option *opt, const char *arg, int unset);
152
151extern const char record_callchain_help[]; 153extern const char record_callchain_help[];
152#endif /* __PERF_CALLCHAIN_H */ 154#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 11e46da17bbb..66e44a5019d5 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -318,8 +318,15 @@ int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
318 return r; 318 return r;
319} 319}
320 320
321int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent) 321int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...)
322{ 322{
323 const char *color = get_percent_color(percent); 323 va_list args;
324 double percent;
325 const char *color;
326
327 va_start(args, fmt);
328 percent = va_arg(args, double);
329 va_end(args);
330 color = get_percent_color(percent);
324 return color_snprintf(bf, size, color, fmt, percent); 331 return color_snprintf(bf, size, color, fmt, percent);
325} 332}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index dea082b79602..fced3840e99c 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -39,7 +39,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
39int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...); 39int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...);
40int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 40int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
42int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent); 42int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...);
43int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 43int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
44const char *get_percent_color(double percent); 44const char *get_percent_color(double percent);
45 45
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
new file mode 100644
index 000000000000..ee0df0e24cdb
--- /dev/null
+++ b/tools/perf/util/comm.c
@@ -0,0 +1,121 @@
1#include "comm.h"
2#include "util.h"
3#include <stdlib.h>
4#include <stdio.h>
5
6struct comm_str {
7 char *str;
8 struct rb_node rb_node;
9 int ref;
10};
11
12/* Should perhaps be moved to struct machine */
13static struct rb_root comm_str_root;
14
15static void comm_str__get(struct comm_str *cs)
16{
17 cs->ref++;
18}
19
20static void comm_str__put(struct comm_str *cs)
21{
22 if (!--cs->ref) {
23 rb_erase(&cs->rb_node, &comm_str_root);
24 free(cs->str);
25 free(cs);
26 }
27}
28
29static struct comm_str *comm_str__alloc(const char *str)
30{
31 struct comm_str *cs;
32
33 cs = zalloc(sizeof(*cs));
34 if (!cs)
35 return NULL;
36
37 cs->str = strdup(str);
38 if (!cs->str) {
39 free(cs);
40 return NULL;
41 }
42
43 return cs;
44}
45
46static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
47{
48 struct rb_node **p = &root->rb_node;
49 struct rb_node *parent = NULL;
50 struct comm_str *iter, *new;
51 int cmp;
52
53 while (*p != NULL) {
54 parent = *p;
55 iter = rb_entry(parent, struct comm_str, rb_node);
56
57 cmp = strcmp(str, iter->str);
58 if (!cmp)
59 return iter;
60
61 if (cmp < 0)
62 p = &(*p)->rb_left;
63 else
64 p = &(*p)->rb_right;
65 }
66
67 new = comm_str__alloc(str);
68 if (!new)
69 return NULL;
70
71 rb_link_node(&new->rb_node, parent, p);
72 rb_insert_color(&new->rb_node, root);
73
74 return new;
75}
76
77struct comm *comm__new(const char *str, u64 timestamp)
78{
79 struct comm *comm = zalloc(sizeof(*comm));
80
81 if (!comm)
82 return NULL;
83
84 comm->start = timestamp;
85
86 comm->comm_str = comm_str__findnew(str, &comm_str_root);
87 if (!comm->comm_str) {
88 free(comm);
89 return NULL;
90 }
91
92 comm_str__get(comm->comm_str);
93
94 return comm;
95}
96
97void comm__override(struct comm *comm, const char *str, u64 timestamp)
98{
99 struct comm_str *old = comm->comm_str;
100
101 comm->comm_str = comm_str__findnew(str, &comm_str_root);
102 if (!comm->comm_str) {
103 comm->comm_str = old;
104 return;
105 }
106
107 comm->start = timestamp;
108 comm_str__get(comm->comm_str);
109 comm_str__put(old);
110}
111
112void comm__free(struct comm *comm)
113{
114 comm_str__put(comm->comm_str);
115 free(comm);
116}
117
118const char *comm__str(const struct comm *comm)
119{
120 return comm->comm_str->str;
121}
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h
new file mode 100644
index 000000000000..7a86e5656710
--- /dev/null
+++ b/tools/perf/util/comm.h
@@ -0,0 +1,21 @@
1#ifndef __PERF_COMM_H
2#define __PERF_COMM_H
3
4#include "../perf.h"
5#include <linux/rbtree.h>
6#include <linux/list.h>
7
8struct comm_str;
9
10struct comm {
11 struct comm_str *comm_str;
12 u64 start;
13 struct list_head list;
14};
15
16void comm__free(struct comm *comm);
17struct comm *comm__new(const char *str, u64 timestamp);
18const char *comm__str(const struct comm *comm);
19void comm__override(struct comm *comm, const char *str, u64 timestamp);
20
21#endif /* __PERF_COMM_H */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index beb8cf9f9976..a9b48c42e81e 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -1,5 +1,5 @@
1#include "util.h" 1#include "util.h"
2#include "sysfs.h" 2#include "fs.h"
3#include "../perf.h" 3#include "../perf.h"
4#include "cpumap.h" 4#include "cpumap.h"
5#include <assert.h> 5#include <assert.h>
@@ -216,7 +216,7 @@ int cpu_map__get_socket(struct cpu_map *map, int idx)
216 216
217 cpu = map->map[idx]; 217 cpu = map->map[idx];
218 218
219 mnt = sysfs_find_mountpoint(); 219 mnt = sysfs__mountpoint();
220 if (!mnt) 220 if (!mnt)
221 return -1; 221 return -1;
222 222
@@ -279,7 +279,7 @@ int cpu_map__get_core(struct cpu_map *map, int idx)
279 279
280 cpu = map->map[idx]; 280 cpu = map->map[idx];
281 281
282 mnt = sysfs_find_mountpoint(); 282 mnt = sysfs__mountpoint();
283 if (!mnt) 283 if (!mnt)
284 return -1; 284 return -1;
285 285
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
new file mode 100644
index 000000000000..7d09faf85cf1
--- /dev/null
+++ b/tools/perf/util/data.c
@@ -0,0 +1,120 @@
1#include <linux/compiler.h>
2#include <linux/kernel.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <unistd.h>
6#include <string.h>
7
8#include "data.h"
9#include "util.h"
10
11static bool check_pipe(struct perf_data_file *file)
12{
13 struct stat st;
14 bool is_pipe = false;
15 int fd = perf_data_file__is_read(file) ?
16 STDIN_FILENO : STDOUT_FILENO;
17
18 if (!file->path) {
19 if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
20 is_pipe = true;
21 } else {
22 if (!strcmp(file->path, "-"))
23 is_pipe = true;
24 }
25
26 if (is_pipe)
27 file->fd = fd;
28
29 return file->is_pipe = is_pipe;
30}
31
32static int check_backup(struct perf_data_file *file)
33{
34 struct stat st;
35
36 if (!stat(file->path, &st) && st.st_size) {
37 /* TODO check errors properly */
38 char oldname[PATH_MAX];
39 snprintf(oldname, sizeof(oldname), "%s.old",
40 file->path);
41 unlink(oldname);
42 rename(file->path, oldname);
43 }
44
45 return 0;
46}
47
48static int open_file_read(struct perf_data_file *file)
49{
50 struct stat st;
51 int fd;
52
53 fd = open(file->path, O_RDONLY);
54 if (fd < 0) {
55 int err = errno;
56
57 pr_err("failed to open %s: %s", file->path, strerror(err));
58 if (err == ENOENT && !strcmp(file->path, "perf.data"))
59 pr_err(" (try 'perf record' first)");
60 pr_err("\n");
61 return -err;
62 }
63
64 if (fstat(fd, &st) < 0)
65 goto out_close;
66
67 if (!file->force && st.st_uid && (st.st_uid != geteuid())) {
68 pr_err("file %s not owned by current user or root\n",
69 file->path);
70 goto out_close;
71 }
72
73 if (!st.st_size) {
74 pr_info("zero-sized file (%s), nothing to do!\n",
75 file->path);
76 goto out_close;
77 }
78
79 file->size = st.st_size;
80 return fd;
81
82 out_close:
83 close(fd);
84 return -1;
85}
86
87static int open_file_write(struct perf_data_file *file)
88{
89 if (check_backup(file))
90 return -1;
91
92 return open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
93}
94
95static int open_file(struct perf_data_file *file)
96{
97 int fd;
98
99 fd = perf_data_file__is_read(file) ?
100 open_file_read(file) : open_file_write(file);
101
102 file->fd = fd;
103 return fd < 0 ? -1 : 0;
104}
105
106int perf_data_file__open(struct perf_data_file *file)
107{
108 if (check_pipe(file))
109 return 0;
110
111 if (!file->path)
112 file->path = "perf.data";
113
114 return open_file(file);
115}
116
117void perf_data_file__close(struct perf_data_file *file)
118{
119 close(file->fd);
120}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
new file mode 100644
index 000000000000..8c2df80152a5
--- /dev/null
+++ b/tools/perf/util/data.h
@@ -0,0 +1,48 @@
1#ifndef __PERF_DATA_H
2#define __PERF_DATA_H
3
4#include <stdbool.h>
5
6enum perf_data_mode {
7 PERF_DATA_MODE_WRITE,
8 PERF_DATA_MODE_READ,
9};
10
11struct perf_data_file {
12 const char *path;
13 int fd;
14 bool is_pipe;
15 bool force;
16 unsigned long size;
17 enum perf_data_mode mode;
18};
19
20static inline bool perf_data_file__is_read(struct perf_data_file *file)
21{
22 return file->mode == PERF_DATA_MODE_READ;
23}
24
25static inline bool perf_data_file__is_write(struct perf_data_file *file)
26{
27 return file->mode == PERF_DATA_MODE_WRITE;
28}
29
30static inline int perf_data_file__is_pipe(struct perf_data_file *file)
31{
32 return file->is_pipe;
33}
34
35static inline int perf_data_file__fd(struct perf_data_file *file)
36{
37 return file->fd;
38}
39
40static inline unsigned long perf_data_file__size(struct perf_data_file *file)
41{
42 return file->size;
43}
44
45int perf_data_file__open(struct perf_data_file *file);
46void perf_data_file__close(struct perf_data_file *file);
47
48#endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index e3c1ff8512c8..af4c687cc49b 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -7,19 +7,20 @@
7char dso__symtab_origin(const struct dso *dso) 7char dso__symtab_origin(const struct dso *dso)
8{ 8{
9 static const char origin[] = { 9 static const char origin[] = {
10 [DSO_BINARY_TYPE__KALLSYMS] = 'k', 10 [DSO_BINARY_TYPE__KALLSYMS] = 'k',
11 [DSO_BINARY_TYPE__VMLINUX] = 'v', 11 [DSO_BINARY_TYPE__VMLINUX] = 'v',
12 [DSO_BINARY_TYPE__JAVA_JIT] = 'j', 12 [DSO_BINARY_TYPE__JAVA_JIT] = 'j',
13 [DSO_BINARY_TYPE__DEBUGLINK] = 'l', 13 [DSO_BINARY_TYPE__DEBUGLINK] = 'l',
14 [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', 14 [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
15 [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f', 15 [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
16 [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u', 16 [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
17 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b', 17 [DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO] = 'o',
18 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', 18 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
19 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', 19 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
20 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', 20 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
21 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', 21 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
22 [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V', 22 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
23 [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
23 }; 24 };
24 25
25 if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND) 26 if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
@@ -64,6 +65,28 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
64 symbol_conf.symfs, dso->long_name); 65 symbol_conf.symfs, dso->long_name);
65 break; 66 break;
66 67
68 case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
69 {
70 char *last_slash;
71 size_t len;
72 size_t dir_size;
73
74 last_slash = dso->long_name + dso->long_name_len;
75 while (last_slash != dso->long_name && *last_slash != '/')
76 last_slash--;
77
78 len = scnprintf(file, size, "%s", symbol_conf.symfs);
79 dir_size = last_slash - dso->long_name + 2;
80 if (dir_size > (size - len)) {
81 ret = -1;
82 break;
83 }
84 len += scnprintf(file + len, dir_size, "%s", dso->long_name);
85 len += scnprintf(file + len , size - len, ".debug%s",
86 last_slash);
87 break;
88 }
89
67 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 90 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
68 if (!dso->has_build_id) { 91 if (!dso->has_build_id) {
69 ret = -1; 92 ret = -1;
@@ -427,6 +450,7 @@ struct dso *dso__new(const char *name)
427 dso->rel = 0; 450 dso->rel = 0;
428 dso->sorted_by_name = 0; 451 dso->sorted_by_name = 0;
429 dso->has_build_id = 0; 452 dso->has_build_id = 0;
453 dso->has_srcline = 1;
430 dso->kernel = DSO_TYPE_USER; 454 dso->kernel = DSO_TYPE_USER;
431 dso->needs_swap = DSO_SWAP__UNSET; 455 dso->needs_swap = DSO_SWAP__UNSET;
432 INIT_LIST_HEAD(&dso->node); 456 INIT_LIST_HEAD(&dso->node);
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index b793053335d6..9ac666abbe7e 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -6,6 +6,7 @@
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include "types.h"
8#include "map.h" 8#include "map.h"
9#include "build-id.h"
9 10
10enum dso_binary_type { 11enum dso_binary_type {
11 DSO_BINARY_TYPE__KALLSYMS = 0, 12 DSO_BINARY_TYPE__KALLSYMS = 0,
@@ -23,6 +24,7 @@ enum dso_binary_type {
23 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 24 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
24 DSO_BINARY_TYPE__KCORE, 25 DSO_BINARY_TYPE__KCORE,
25 DSO_BINARY_TYPE__GUEST_KCORE, 26 DSO_BINARY_TYPE__GUEST_KCORE,
27 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
26 DSO_BINARY_TYPE__NOT_FOUND, 28 DSO_BINARY_TYPE__NOT_FOUND,
27}; 29};
28 30
@@ -81,6 +83,7 @@ struct dso {
81 enum dso_binary_type data_type; 83 enum dso_binary_type data_type;
82 u8 adjust_symbols:1; 84 u8 adjust_symbols:1;
83 u8 has_build_id:1; 85 u8 has_build_id:1;
86 u8 has_srcline:1;
84 u8 hit:1; 87 u8 hit:1;
85 u8 annotate_warned:1; 88 u8 annotate_warned:1;
86 u8 sname_alloc:1; 89 u8 sname_alloc:1;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 9b393e7dca6f..bb788c109fe6 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -170,7 +170,8 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
170 union perf_event *event, 170 union perf_event *event,
171 pid_t pid, pid_t tgid, 171 pid_t pid, pid_t tgid,
172 perf_event__handler_t process, 172 perf_event__handler_t process,
173 struct machine *machine) 173 struct machine *machine,
174 bool mmap_data)
174{ 175{
175 char filename[PATH_MAX]; 176 char filename[PATH_MAX];
176 FILE *fp; 177 FILE *fp;
@@ -187,18 +188,13 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
187 return -1; 188 return -1;
188 } 189 }
189 190
190 event->header.type = PERF_RECORD_MMAP2; 191 event->header.type = PERF_RECORD_MMAP;
191 /*
192 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
193 */
194 event->header.misc = PERF_RECORD_MISC_USER;
195 192
196 while (1) { 193 while (1) {
197 char bf[BUFSIZ]; 194 char bf[BUFSIZ];
198 char prot[5]; 195 char prot[5];
199 char execname[PATH_MAX]; 196 char execname[PATH_MAX];
200 char anonstr[] = "//anon"; 197 char anonstr[] = "//anon";
201 unsigned int ino;
202 size_t size; 198 size_t size;
203 ssize_t n; 199 ssize_t n;
204 200
@@ -209,33 +205,40 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
209 strcpy(execname, ""); 205 strcpy(execname, "");
210 206
211 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 207 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
212 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n", 208 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n",
213 &event->mmap2.start, &event->mmap2.len, prot, 209 &event->mmap.start, &event->mmap.len, prot,
214 &event->mmap2.pgoff, &event->mmap2.maj, 210 &event->mmap.pgoff,
215 &event->mmap2.min, 211 execname);
216 &ino, execname); 212 /*
217 213 * Anon maps don't have the execname.
218 event->mmap2.ino = (u64)ino; 214 */
219 215 if (n < 4)
220 if (n != 8)
221 continue; 216 continue;
217 /*
218 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
219 */
220 event->header.misc = PERF_RECORD_MISC_USER;
222 221
223 if (prot[2] != 'x') 222 if (prot[2] != 'x') {
224 continue; 223 if (!mmap_data || prot[0] != 'r')
224 continue;
225
226 event->header.misc |= PERF_RECORD_MISC_MMAP_DATA;
227 }
225 228
226 if (!strcmp(execname, "")) 229 if (!strcmp(execname, ""))
227 strcpy(execname, anonstr); 230 strcpy(execname, anonstr);
228 231
229 size = strlen(execname) + 1; 232 size = strlen(execname) + 1;
230 memcpy(event->mmap2.filename, execname, size); 233 memcpy(event->mmap.filename, execname, size);
231 size = PERF_ALIGN(size, sizeof(u64)); 234 size = PERF_ALIGN(size, sizeof(u64));
232 event->mmap2.len -= event->mmap.start; 235 event->mmap.len -= event->mmap.start;
233 event->mmap2.header.size = (sizeof(event->mmap2) - 236 event->mmap.header.size = (sizeof(event->mmap) -
234 (sizeof(event->mmap2.filename) - size)); 237 (sizeof(event->mmap.filename) - size));
235 memset(event->mmap2.filename + size, 0, machine->id_hdr_size); 238 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
236 event->mmap2.header.size += machine->id_hdr_size; 239 event->mmap.header.size += machine->id_hdr_size;
237 event->mmap2.pid = tgid; 240 event->mmap.pid = tgid;
238 event->mmap2.tid = pid; 241 event->mmap.tid = pid;
239 242
240 if (process(tool, event, &synth_sample, machine) != 0) { 243 if (process(tool, event, &synth_sample, machine) != 0) {
241 rc = -1; 244 rc = -1;
@@ -308,20 +311,21 @@ static int __event__synthesize_thread(union perf_event *comm_event,
308 pid_t pid, int full, 311 pid_t pid, int full,
309 perf_event__handler_t process, 312 perf_event__handler_t process,
310 struct perf_tool *tool, 313 struct perf_tool *tool,
311 struct machine *machine) 314 struct machine *machine, bool mmap_data)
312{ 315{
313 pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full, 316 pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full,
314 process, machine); 317 process, machine);
315 if (tgid == -1) 318 if (tgid == -1)
316 return -1; 319 return -1;
317 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 320 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
318 process, machine); 321 process, machine, mmap_data);
319} 322}
320 323
321int perf_event__synthesize_thread_map(struct perf_tool *tool, 324int perf_event__synthesize_thread_map(struct perf_tool *tool,
322 struct thread_map *threads, 325 struct thread_map *threads,
323 perf_event__handler_t process, 326 perf_event__handler_t process,
324 struct machine *machine) 327 struct machine *machine,
328 bool mmap_data)
325{ 329{
326 union perf_event *comm_event, *mmap_event; 330 union perf_event *comm_event, *mmap_event;
327 int err = -1, thread, j; 331 int err = -1, thread, j;
@@ -338,7 +342,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
338 for (thread = 0; thread < threads->nr; ++thread) { 342 for (thread = 0; thread < threads->nr; ++thread) {
339 if (__event__synthesize_thread(comm_event, mmap_event, 343 if (__event__synthesize_thread(comm_event, mmap_event,
340 threads->map[thread], 0, 344 threads->map[thread], 0,
341 process, tool, machine)) { 345 process, tool, machine,
346 mmap_data)) {
342 err = -1; 347 err = -1;
343 break; 348 break;
344 } 349 }
@@ -360,10 +365,10 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
360 365
361 /* if not, generate events for it */ 366 /* if not, generate events for it */
362 if (need_leader && 367 if (need_leader &&
363 __event__synthesize_thread(comm_event, 368 __event__synthesize_thread(comm_event, mmap_event,
364 mmap_event, 369 comm_event->comm.pid, 0,
365 comm_event->comm.pid, 0, 370 process, tool, machine,
366 process, tool, machine)) { 371 mmap_data)) {
367 err = -1; 372 err = -1;
368 break; 373 break;
369 } 374 }
@@ -378,7 +383,7 @@ out:
378 383
379int perf_event__synthesize_threads(struct perf_tool *tool, 384int perf_event__synthesize_threads(struct perf_tool *tool,
380 perf_event__handler_t process, 385 perf_event__handler_t process,
381 struct machine *machine) 386 struct machine *machine, bool mmap_data)
382{ 387{
383 DIR *proc; 388 DIR *proc;
384 struct dirent dirent, *next; 389 struct dirent dirent, *next;
@@ -408,7 +413,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
408 * one thread couldn't be synthesized. 413 * one thread couldn't be synthesized.
409 */ 414 */
410 __event__synthesize_thread(comm_event, mmap_event, pid, 1, 415 __event__synthesize_thread(comm_event, mmap_event, pid, 1,
411 process, tool, machine); 416 process, tool, machine, mmap_data);
412 } 417 }
413 418
414 err = 0; 419 err = 0;
@@ -516,52 +521,55 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
516 521
517int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 522int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
518 union perf_event *event, 523 union perf_event *event,
519 struct perf_sample *sample __maybe_unused, 524 struct perf_sample *sample,
520 struct machine *machine) 525 struct machine *machine)
521{ 526{
522 return machine__process_comm_event(machine, event); 527 return machine__process_comm_event(machine, event, sample);
523} 528}
524 529
525int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 530int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
526 union perf_event *event, 531 union perf_event *event,
527 struct perf_sample *sample __maybe_unused, 532 struct perf_sample *sample,
528 struct machine *machine) 533 struct machine *machine)
529{ 534{
530 return machine__process_lost_event(machine, event); 535 return machine__process_lost_event(machine, event, sample);
531} 536}
532 537
533size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 538size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
534{ 539{
535 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", 540 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n",
536 event->mmap.pid, event->mmap.tid, event->mmap.start, 541 event->mmap.pid, event->mmap.tid, event->mmap.start,
537 event->mmap.len, event->mmap.pgoff, event->mmap.filename); 542 event->mmap.len, event->mmap.pgoff,
543 (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x',
544 event->mmap.filename);
538} 545}
539 546
540size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) 547size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
541{ 548{
542 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 549 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
543 " %02x:%02x %"PRIu64" %"PRIu64"]: %s\n", 550 " %02x:%02x %"PRIu64" %"PRIu64"]: %c %s\n",
544 event->mmap2.pid, event->mmap2.tid, event->mmap2.start, 551 event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
545 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, 552 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
546 event->mmap2.min, event->mmap2.ino, 553 event->mmap2.min, event->mmap2.ino,
547 event->mmap2.ino_generation, 554 event->mmap2.ino_generation,
555 (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x',
548 event->mmap2.filename); 556 event->mmap2.filename);
549} 557}
550 558
551int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, 559int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
552 union perf_event *event, 560 union perf_event *event,
553 struct perf_sample *sample __maybe_unused, 561 struct perf_sample *sample,
554 struct machine *machine) 562 struct machine *machine)
555{ 563{
556 return machine__process_mmap_event(machine, event); 564 return machine__process_mmap_event(machine, event, sample);
557} 565}
558 566
559int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, 567int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused,
560 union perf_event *event, 568 union perf_event *event,
561 struct perf_sample *sample __maybe_unused, 569 struct perf_sample *sample,
562 struct machine *machine) 570 struct machine *machine)
563{ 571{
564 return machine__process_mmap2_event(machine, event); 572 return machine__process_mmap2_event(machine, event, sample);
565} 573}
566 574
567size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 575size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
@@ -573,18 +581,18 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
573 581
574int perf_event__process_fork(struct perf_tool *tool __maybe_unused, 582int perf_event__process_fork(struct perf_tool *tool __maybe_unused,
575 union perf_event *event, 583 union perf_event *event,
576 struct perf_sample *sample __maybe_unused, 584 struct perf_sample *sample,
577 struct machine *machine) 585 struct machine *machine)
578{ 586{
579 return machine__process_fork_event(machine, event); 587 return machine__process_fork_event(machine, event, sample);
580} 588}
581 589
582int perf_event__process_exit(struct perf_tool *tool __maybe_unused, 590int perf_event__process_exit(struct perf_tool *tool __maybe_unused,
583 union perf_event *event, 591 union perf_event *event,
584 struct perf_sample *sample __maybe_unused, 592 struct perf_sample *sample,
585 struct machine *machine) 593 struct machine *machine)
586{ 594{
587 return machine__process_exit_event(machine, event); 595 return machine__process_exit_event(machine, event, sample);
588} 596}
589 597
590size_t perf_event__fprintf(union perf_event *event, FILE *fp) 598size_t perf_event__fprintf(union perf_event *event, FILE *fp)
@@ -615,21 +623,21 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
615 623
616int perf_event__process(struct perf_tool *tool __maybe_unused, 624int perf_event__process(struct perf_tool *tool __maybe_unused,
617 union perf_event *event, 625 union perf_event *event,
618 struct perf_sample *sample __maybe_unused, 626 struct perf_sample *sample,
619 struct machine *machine) 627 struct machine *machine)
620{ 628{
621 return machine__process_event(machine, event); 629 return machine__process_event(machine, event, sample);
622} 630}
623 631
624void thread__find_addr_map(struct thread *self, 632void thread__find_addr_map(struct thread *thread,
625 struct machine *machine, u8 cpumode, 633 struct machine *machine, u8 cpumode,
626 enum map_type type, u64 addr, 634 enum map_type type, u64 addr,
627 struct addr_location *al) 635 struct addr_location *al)
628{ 636{
629 struct map_groups *mg = &self->mg; 637 struct map_groups *mg = &thread->mg;
630 bool load_map = false; 638 bool load_map = false;
631 639
632 al->thread = self; 640 al->thread = thread;
633 al->addr = addr; 641 al->addr = addr;
634 al->cpumode = cpumode; 642 al->cpumode = cpumode;
635 al->filtered = false; 643 al->filtered = false;
@@ -725,10 +733,10 @@ int perf_event__preprocess_sample(const union perf_event *event,
725 return -1; 733 return -1;
726 734
727 if (symbol_conf.comm_list && 735 if (symbol_conf.comm_list &&
728 !strlist__has_entry(symbol_conf.comm_list, thread->comm)) 736 !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread)))
729 goto out_filtered; 737 goto out_filtered;
730 738
731 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid); 739 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
732 /* 740 /*
733 * Have we already created the kernel maps for this machine? 741 * Have we already created the kernel maps for this machine?
734 * 742 *
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index c67ecc457d29..30fec9901e44 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -61,6 +61,12 @@ struct read_event {
61 u64 id; 61 u64 id;
62}; 62};
63 63
64struct throttle_event {
65 struct perf_event_header header;
66 u64 time;
67 u64 id;
68 u64 stream_id;
69};
64 70
65#define PERF_SAMPLE_MASK \ 71#define PERF_SAMPLE_MASK \
66 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ 72 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
@@ -69,6 +75,9 @@ struct read_event {
69 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \ 75 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \
70 PERF_SAMPLE_IDENTIFIER) 76 PERF_SAMPLE_IDENTIFIER)
71 77
78/* perf sample has 16 bits size limit */
79#define PERF_SAMPLE_MAX_SIZE (1 << 16)
80
72struct sample_event { 81struct sample_event {
73 struct perf_event_header header; 82 struct perf_event_header header;
74 u64 array[]; 83 u64 array[];
@@ -111,6 +120,7 @@ struct perf_sample {
111 u64 stream_id; 120 u64 stream_id;
112 u64 period; 121 u64 period;
113 u64 weight; 122 u64 weight;
123 u64 transaction;
114 u32 cpu; 124 u32 cpu;
115 u32 raw_size; 125 u32 raw_size;
116 u64 data_src; 126 u64 data_src;
@@ -177,6 +187,7 @@ union perf_event {
177 struct fork_event fork; 187 struct fork_event fork;
178 struct lost_event lost; 188 struct lost_event lost;
179 struct read_event read; 189 struct read_event read;
190 struct throttle_event throttle;
180 struct sample_event sample; 191 struct sample_event sample;
181 struct attr_event attr; 192 struct attr_event attr;
182 struct event_type_event event_type; 193 struct event_type_event event_type;
@@ -197,10 +208,10 @@ typedef int (*perf_event__handler_t)(struct perf_tool *tool,
197int perf_event__synthesize_thread_map(struct perf_tool *tool, 208int perf_event__synthesize_thread_map(struct perf_tool *tool,
198 struct thread_map *threads, 209 struct thread_map *threads,
199 perf_event__handler_t process, 210 perf_event__handler_t process,
200 struct machine *machine); 211 struct machine *machine, bool mmap_data);
201int perf_event__synthesize_threads(struct perf_tool *tool, 212int perf_event__synthesize_threads(struct perf_tool *tool,
202 perf_event__handler_t process, 213 perf_event__handler_t process,
203 struct machine *machine); 214 struct machine *machine, bool mmap_data);
204int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 215int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
205 perf_event__handler_t process, 216 perf_event__handler_t process,
206 struct machine *machine, 217 struct machine *machine,
@@ -240,7 +251,8 @@ int perf_event__process(struct perf_tool *tool,
240 struct machine *machine); 251 struct machine *machine);
241 252
242struct addr_location; 253struct addr_location;
243int perf_event__preprocess_sample(const union perf_event *self, 254
255int perf_event__preprocess_sample(const union perf_event *event,
244 struct machine *machine, 256 struct machine *machine,
245 struct addr_location *al, 257 struct addr_location *al,
246 struct perf_sample *sample); 258 struct perf_sample *sample);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index f9f77bee0b1b..bbc746aa5716 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -18,6 +18,7 @@
18#include <unistd.h> 18#include <unistd.h>
19 19
20#include "parse-events.h" 20#include "parse-events.h"
21#include "parse-options.h"
21 22
22#include <sys/mman.h> 23#include <sys/mman.h>
23 24
@@ -49,6 +50,18 @@ struct perf_evlist *perf_evlist__new(void)
49 return evlist; 50 return evlist;
50} 51}
51 52
53struct perf_evlist *perf_evlist__new_default(void)
54{
55 struct perf_evlist *evlist = perf_evlist__new();
56
57 if (evlist && perf_evlist__add_default(evlist)) {
58 perf_evlist__delete(evlist);
59 evlist = NULL;
60 }
61
62 return evlist;
63}
64
52/** 65/**
53 * perf_evlist__set_id_pos - set the positions of event ids. 66 * perf_evlist__set_id_pos - set the positions of event ids.
54 * @evlist: selected event list 67 * @evlist: selected event list
@@ -104,6 +117,8 @@ void perf_evlist__delete(struct perf_evlist *evlist)
104void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) 117void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
105{ 118{
106 list_add_tail(&entry->node, &evlist->entries); 119 list_add_tail(&entry->node, &evlist->entries);
120 entry->idx = evlist->nr_entries;
121
107 if (!evlist->nr_entries++) 122 if (!evlist->nr_entries++)
108 perf_evlist__set_id_pos(evlist); 123 perf_evlist__set_id_pos(evlist);
109} 124}
@@ -152,7 +167,7 @@ int perf_evlist__add_default(struct perf_evlist *evlist)
152 167
153 event_attr_init(&attr); 168 event_attr_init(&attr);
154 169
155 evsel = perf_evsel__new(&attr, 0); 170 evsel = perf_evsel__new(&attr);
156 if (evsel == NULL) 171 if (evsel == NULL)
157 goto error; 172 goto error;
158 173
@@ -177,7 +192,7 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist,
177 size_t i; 192 size_t i;
178 193
179 for (i = 0; i < nr_attrs; i++) { 194 for (i = 0; i < nr_attrs; i++) {
180 evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i); 195 evsel = perf_evsel__new_idx(attrs + i, evlist->nr_entries + i);
181 if (evsel == NULL) 196 if (evsel == NULL)
182 goto out_delete_partial_list; 197 goto out_delete_partial_list;
183 list_add_tail(&evsel->node, &head); 198 list_add_tail(&evsel->node, &head);
@@ -236,13 +251,12 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
236int perf_evlist__add_newtp(struct perf_evlist *evlist, 251int perf_evlist__add_newtp(struct perf_evlist *evlist,
237 const char *sys, const char *name, void *handler) 252 const char *sys, const char *name, void *handler)
238{ 253{
239 struct perf_evsel *evsel; 254 struct perf_evsel *evsel = perf_evsel__newtp(sys, name);
240 255
241 evsel = perf_evsel__newtp(sys, name, evlist->nr_entries);
242 if (evsel == NULL) 256 if (evsel == NULL)
243 return -1; 257 return -1;
244 258
245 evsel->handler.func = handler; 259 evsel->handler = handler;
246 perf_evlist__add(evlist, evsel); 260 perf_evlist__add(evlist, evsel);
247 return 0; 261 return 0;
248} 262}
@@ -527,7 +541,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
527 if ((old & md->mask) + size != ((old + size) & md->mask)) { 541 if ((old & md->mask) + size != ((old + size) & md->mask)) {
528 unsigned int offset = old; 542 unsigned int offset = old;
529 unsigned int len = min(sizeof(*event), size), cpy; 543 unsigned int len = min(sizeof(*event), size), cpy;
530 void *dst = &md->event_copy; 544 void *dst = md->event_copy;
531 545
532 do { 546 do {
533 cpy = min(md->mask + 1 - (offset & md->mask), len); 547 cpy = min(md->mask + 1 - (offset & md->mask), len);
@@ -537,7 +551,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
537 len -= cpy; 551 len -= cpy;
538 } while (len); 552 } while (len);
539 553
540 event = &md->event_copy; 554 event = (union perf_event *) md->event_copy;
541 } 555 }
542 556
543 old += size; 557 old += size;
@@ -545,12 +559,19 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
545 559
546 md->prev = old; 560 md->prev = old;
547 561
548 if (!evlist->overwrite)
549 perf_mmap__write_tail(md, old);
550
551 return event; 562 return event;
552} 563}
553 564
565void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
566{
567 if (!evlist->overwrite) {
568 struct perf_mmap *md = &evlist->mmap[idx];
569 unsigned int old = md->prev;
570
571 perf_mmap__write_tail(md, old);
572 }
573}
574
554static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) 575static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
555{ 576{
556 if (evlist->mmap[idx].base != NULL) { 577 if (evlist->mmap[idx].base != NULL) {
@@ -587,6 +608,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
587 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, 608 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
588 MAP_SHARED, fd, 0); 609 MAP_SHARED, fd, 0);
589 if (evlist->mmap[idx].base == MAP_FAILED) { 610 if (evlist->mmap[idx].base == MAP_FAILED) {
611 pr_debug2("failed to mmap perf event ring buffer, error %d\n",
612 errno);
590 evlist->mmap[idx].base = NULL; 613 evlist->mmap[idx].base = NULL;
591 return -1; 614 return -1;
592 } 615 }
@@ -595,9 +618,36 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
595 return 0; 618 return 0;
596} 619}
597 620
598static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask) 621static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
622 int prot, int mask, int cpu, int thread,
623 int *output)
599{ 624{
600 struct perf_evsel *evsel; 625 struct perf_evsel *evsel;
626
627 list_for_each_entry(evsel, &evlist->entries, node) {
628 int fd = FD(evsel, cpu, thread);
629
630 if (*output == -1) {
631 *output = fd;
632 if (__perf_evlist__mmap(evlist, idx, prot, mask,
633 *output) < 0)
634 return -1;
635 } else {
636 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
637 return -1;
638 }
639
640 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
641 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
642 return -1;
643 }
644
645 return 0;
646}
647
648static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
649 int mask)
650{
601 int cpu, thread; 651 int cpu, thread;
602 int nr_cpus = cpu_map__nr(evlist->cpus); 652 int nr_cpus = cpu_map__nr(evlist->cpus);
603 int nr_threads = thread_map__nr(evlist->threads); 653 int nr_threads = thread_map__nr(evlist->threads);
@@ -607,23 +657,9 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
607 int output = -1; 657 int output = -1;
608 658
609 for (thread = 0; thread < nr_threads; thread++) { 659 for (thread = 0; thread < nr_threads; thread++) {
610 list_for_each_entry(evsel, &evlist->entries, node) { 660 if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask,
611 int fd = FD(evsel, cpu, thread); 661 cpu, thread, &output))
612 662 goto out_unmap;
613 if (output == -1) {
614 output = fd;
615 if (__perf_evlist__mmap(evlist, cpu,
616 prot, mask, output) < 0)
617 goto out_unmap;
618 } else {
619 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
620 goto out_unmap;
621 }
622
623 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
624 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
625 goto out_unmap;
626 }
627 } 663 }
628 } 664 }
629 665
@@ -635,9 +671,9 @@ out_unmap:
635 return -1; 671 return -1;
636} 672}
637 673
638static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask) 674static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
675 int mask)
639{ 676{
640 struct perf_evsel *evsel;
641 int thread; 677 int thread;
642 int nr_threads = thread_map__nr(evlist->threads); 678 int nr_threads = thread_map__nr(evlist->threads);
643 679
@@ -645,23 +681,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
645 for (thread = 0; thread < nr_threads; thread++) { 681 for (thread = 0; thread < nr_threads; thread++) {
646 int output = -1; 682 int output = -1;
647 683
648 list_for_each_entry(evsel, &evlist->entries, node) { 684 if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0,
649 int fd = FD(evsel, 0, thread); 685 thread, &output))
650 686 goto out_unmap;
651 if (output == -1) {
652 output = fd;
653 if (__perf_evlist__mmap(evlist, thread,
654 prot, mask, output) < 0)
655 goto out_unmap;
656 } else {
657 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
658 goto out_unmap;
659 }
660
661 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
662 perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0)
663 goto out_unmap;
664 }
665 } 687 }
666 688
667 return 0; 689 return 0;
@@ -672,20 +694,90 @@ out_unmap:
672 return -1; 694 return -1;
673} 695}
674 696
675/** perf_evlist__mmap - Create per cpu maps to receive events 697static size_t perf_evlist__mmap_size(unsigned long pages)
676 * 698{
677 * @evlist - list of events 699 /* 512 kiB: default amount of unprivileged mlocked memory */
678 * @pages - map length in pages 700 if (pages == UINT_MAX)
679 * @overwrite - overwrite older events? 701 pages = (512 * 1024) / page_size;
680 * 702 else if (!is_power_of_2(pages))
681 * If overwrite is false the user needs to signal event consuption using: 703 return 0;
682 * 704
683 * struct perf_mmap *m = &evlist->mmap[cpu]; 705 return (pages + 1) * page_size;
684 * unsigned int head = perf_mmap__read_head(m); 706}
707
708static long parse_pages_arg(const char *str, unsigned long min,
709 unsigned long max)
710{
711 unsigned long pages, val;
712 static struct parse_tag tags[] = {
713 { .tag = 'B', .mult = 1 },
714 { .tag = 'K', .mult = 1 << 10 },
715 { .tag = 'M', .mult = 1 << 20 },
716 { .tag = 'G', .mult = 1 << 30 },
717 { .tag = 0 },
718 };
719
720 if (str == NULL)
721 return -EINVAL;
722
723 val = parse_tag_value(str, tags);
724 if (val != (unsigned long) -1) {
725 /* we got file size value */
726 pages = PERF_ALIGN(val, page_size) / page_size;
727 } else {
728 /* we got pages count value */
729 char *eptr;
730 pages = strtoul(str, &eptr, 10);
731 if (*eptr != '\0')
732 return -EINVAL;
733 }
734
735 if ((pages == 0) && (min == 0)) {
736 /* leave number of pages at 0 */
737 } else if (pages < (1UL << 31) && !is_power_of_2(pages)) {
738 /* round pages up to next power of 2 */
739 pages = next_pow2(pages);
740 pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n",
741 pages * page_size, pages);
742 }
743
744 if (pages > max)
745 return -EINVAL;
746
747 return pages;
748}
749
750int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
751 int unset __maybe_unused)
752{
753 unsigned int *mmap_pages = opt->value;
754 unsigned long max = UINT_MAX;
755 long pages;
756
757 if (max < SIZE_MAX / page_size)
758 max = SIZE_MAX / page_size;
759
760 pages = parse_pages_arg(str, 1, max);
761 if (pages < 0) {
762 pr_err("Invalid argument for --mmap_pages/-m\n");
763 return -1;
764 }
765
766 *mmap_pages = pages;
767 return 0;
768}
769
770/**
771 * perf_evlist__mmap - Create mmaps to receive events.
772 * @evlist: list of events
773 * @pages: map length in pages
774 * @overwrite: overwrite older events?
685 * 775 *
686 * perf_mmap__write_tail(m, head) 776 * If @overwrite is %false the user needs to signal event consumption using
777 * perf_mmap__write_tail(). Using perf_evlist__mmap_read() does this
778 * automatically.
687 * 779 *
688 * Using perf_evlist__read_on_cpu does this automatically. 780 * Return: %0 on success, negative error code otherwise.
689 */ 781 */
690int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 782int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
691 bool overwrite) 783 bool overwrite)
@@ -695,14 +787,6 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
695 const struct thread_map *threads = evlist->threads; 787 const struct thread_map *threads = evlist->threads;
696 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; 788 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask;
697 789
698 /* 512 kiB: default amount of unprivileged mlocked memory */
699 if (pages == UINT_MAX)
700 pages = (512 * 1024) / page_size;
701 else if (!is_power_of_2(pages))
702 return -EINVAL;
703
704 mask = pages * page_size - 1;
705
706 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) 790 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
707 return -ENOMEM; 791 return -ENOMEM;
708 792
@@ -710,7 +794,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
710 return -ENOMEM; 794 return -ENOMEM;
711 795
712 evlist->overwrite = overwrite; 796 evlist->overwrite = overwrite;
713 evlist->mmap_len = (pages + 1) * page_size; 797 evlist->mmap_len = perf_evlist__mmap_size(pages);
798 pr_debug("mmap size %zuB\n", evlist->mmap_len);
799 mask = evlist->mmap_len - page_size - 1;
714 800
715 list_for_each_entry(evsel, &evlist->entries, node) { 801 list_for_each_entry(evsel, &evlist->entries, node) {
716 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 802 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -725,8 +811,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
725 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 811 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
726} 812}
727 813
728int perf_evlist__create_maps(struct perf_evlist *evlist, 814int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
729 struct perf_target *target)
730{ 815{
731 evlist->threads = thread_map__new_str(target->pid, target->tid, 816 evlist->threads = thread_map__new_str(target->pid, target->tid,
732 target->uid); 817 target->uid);
@@ -734,9 +819,11 @@ int perf_evlist__create_maps(struct perf_evlist *evlist,
734 if (evlist->threads == NULL) 819 if (evlist->threads == NULL)
735 return -1; 820 return -1;
736 821
737 if (perf_target__has_task(target)) 822 if (target->force_per_cpu)
823 evlist->cpus = cpu_map__new(target->cpu_list);
824 else if (target__has_task(target))
738 evlist->cpus = cpu_map__dummy_new(); 825 evlist->cpus = cpu_map__dummy_new();
739 else if (!perf_target__has_cpu(target) && !target->uses_mmap) 826 else if (!target__has_cpu(target) && !target->uses_mmap)
740 evlist->cpus = cpu_map__dummy_new(); 827 evlist->cpus = cpu_map__dummy_new();
741 else 828 else
742 evlist->cpus = cpu_map__new(target->cpu_list); 829 evlist->cpus = cpu_map__new(target->cpu_list);
@@ -945,8 +1032,7 @@ out_err:
945 return err; 1032 return err;
946} 1033}
947 1034
948int perf_evlist__prepare_workload(struct perf_evlist *evlist, 1035int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target,
949 struct perf_target *target,
950 const char *argv[], bool pipe_output, 1036 const char *argv[], bool pipe_output,
951 bool want_signal) 1037 bool want_signal)
952{ 1038{
@@ -998,7 +1084,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
998 exit(-1); 1084 exit(-1);
999 } 1085 }
1000 1086
1001 if (perf_target__none(target)) 1087 if (target__none(target))
1002 evlist->threads->map[0] = evlist->workload.pid; 1088 evlist->threads->map[0] = evlist->workload.pid;
1003 1089
1004 close(child_ready_pipe[1]); 1090 close(child_ready_pipe[1]);
@@ -1064,5 +1150,68 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
1064 perf_evsel__name(evsel)); 1150 perf_evsel__name(evsel));
1065 } 1151 }
1066 1152
1067 return printed + fprintf(fp, "\n");; 1153 return printed + fprintf(fp, "\n");
1154}
1155
1156int perf_evlist__strerror_tp(struct perf_evlist *evlist __maybe_unused,
1157 int err, char *buf, size_t size)
1158{
1159 char sbuf[128];
1160
1161 switch (err) {
1162 case ENOENT:
1163 scnprintf(buf, size, "%s",
1164 "Error:\tUnable to find debugfs\n"
1165 "Hint:\tWas your kernel was compiled with debugfs support?\n"
1166 "Hint:\tIs the debugfs filesystem mounted?\n"
1167 "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'");
1168 break;
1169 case EACCES:
1170 scnprintf(buf, size,
1171 "Error:\tNo permissions to read %s/tracing/events/raw_syscalls\n"
1172 "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
1173 debugfs_mountpoint, debugfs_mountpoint);
1174 break;
1175 default:
1176 scnprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf)));
1177 break;
1178 }
1179
1180 return 0;
1181}
1182
1183int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1184 int err, char *buf, size_t size)
1185{
1186 int printed, value;
1187 char sbuf[128], *emsg = strerror_r(err, sbuf, sizeof(sbuf));
1188
1189 switch (err) {
1190 case EACCES:
1191 case EPERM:
1192 printed = scnprintf(buf, size,
1193 "Error:\t%s.\n"
1194 "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg);
1195
1196 if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value))
1197 break;
1198
1199 printed += scnprintf(buf + printed, size - printed, "\nHint:\t");
1200
1201 if (value >= 2) {
1202 printed += scnprintf(buf + printed, size - printed,
1203 "For your workloads it needs to be <= 1\nHint:\t");
1204 }
1205 printed += scnprintf(buf + printed, size - printed,
1206 "For system wide tracing it needs to be set to -1");
1207
1208 printed += scnprintf(buf + printed, size - printed,
1209 ".\nHint:\tThe current value is %d.", value);
1210 break;
1211 default:
1212 scnprintf(buf, size, "%s", emsg);
1213 break;
1214 }
1215
1216 return 0;
1068} 1217}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 880d7139d2fb..649d6ea98a84 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -21,7 +21,7 @@ struct perf_mmap {
21 void *base; 21 void *base;
22 int mask; 22 int mask;
23 unsigned int prev; 23 unsigned int prev;
24 union perf_event event_copy; 24 char event_copy[PERF_SAMPLE_MAX_SIZE];
25}; 25};
26 26
27struct perf_evlist { 27struct perf_evlist {
@@ -31,7 +31,7 @@ struct perf_evlist {
31 int nr_groups; 31 int nr_groups;
32 int nr_fds; 32 int nr_fds;
33 int nr_mmaps; 33 int nr_mmaps;
34 int mmap_len; 34 size_t mmap_len;
35 int id_pos; 35 int id_pos;
36 int is_pos; 36 int is_pos;
37 u64 combined_sample_type; 37 u64 combined_sample_type;
@@ -53,6 +53,7 @@ struct perf_evsel_str_handler {
53}; 53};
54 54
55struct perf_evlist *perf_evlist__new(void); 55struct perf_evlist *perf_evlist__new(void);
56struct perf_evlist *perf_evlist__new_default(void);
56void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, 57void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
57 struct thread_map *threads); 58 struct thread_map *threads);
58void perf_evlist__exit(struct perf_evlist *evlist); 59void perf_evlist__exit(struct perf_evlist *evlist);
@@ -87,7 +88,9 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
87 88
88struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); 89struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id);
89 90
90union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 91union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx);
92
93void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx);
91 94
92int perf_evlist__open(struct perf_evlist *evlist); 95int perf_evlist__open(struct perf_evlist *evlist);
93void perf_evlist__close(struct perf_evlist *evlist); 96void perf_evlist__close(struct perf_evlist *evlist);
@@ -96,13 +99,18 @@ void perf_evlist__set_id_pos(struct perf_evlist *evlist);
96bool perf_can_sample_identifier(void); 99bool perf_can_sample_identifier(void);
97void perf_evlist__config(struct perf_evlist *evlist, 100void perf_evlist__config(struct perf_evlist *evlist,
98 struct perf_record_opts *opts); 101 struct perf_record_opts *opts);
102int perf_record_opts__config(struct perf_record_opts *opts);
99 103
100int perf_evlist__prepare_workload(struct perf_evlist *evlist, 104int perf_evlist__prepare_workload(struct perf_evlist *evlist,
101 struct perf_target *target, 105 struct target *target,
102 const char *argv[], bool pipe_output, 106 const char *argv[], bool pipe_output,
103 bool want_signal); 107 bool want_signal);
104int perf_evlist__start_workload(struct perf_evlist *evlist); 108int perf_evlist__start_workload(struct perf_evlist *evlist);
105 109
110int perf_evlist__parse_mmap_pages(const struct option *opt,
111 const char *str,
112 int unset);
113
106int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 114int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
107 bool overwrite); 115 bool overwrite);
108void perf_evlist__munmap(struct perf_evlist *evlist); 116void perf_evlist__munmap(struct perf_evlist *evlist);
@@ -126,8 +134,7 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
126 evlist->threads = threads; 134 evlist->threads = threads;
127} 135}
128 136
129int perf_evlist__create_maps(struct perf_evlist *evlist, 137int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target);
130 struct perf_target *target);
131void perf_evlist__delete_maps(struct perf_evlist *evlist); 138void perf_evlist__delete_maps(struct perf_evlist *evlist);
132int perf_evlist__apply_filters(struct perf_evlist *evlist); 139int perf_evlist__apply_filters(struct perf_evlist *evlist);
133 140
@@ -163,10 +170,13 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
163 170
164size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); 171size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
165 172
173int perf_evlist__strerror_tp(struct perf_evlist *evlist, int err, char *buf, size_t size);
174int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size);
175
166static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm) 176static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
167{ 177{
168 struct perf_event_mmap_page *pc = mm->base; 178 struct perf_event_mmap_page *pc = mm->base;
169 int head = pc->data_head; 179 int head = ACCESS_ONCE(pc->data_head);
170 rmb(); 180 rmb();
171 return head; 181 return head;
172} 182}
@@ -179,7 +189,7 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md,
179 /* 189 /*
180 * ensure all reads are done before we write the tail out. 190 * ensure all reads are done before we write the tail out.
181 */ 191 */
182 /* mb(); */ 192 mb();
183 pc->data_tail = tail; 193 pc->data_tail = tail;
184} 194}
185 195
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 0ce9febf1ba0..46dd4c2a41ce 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -168,7 +168,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
168 perf_evsel__calc_id_pos(evsel); 168 perf_evsel__calc_id_pos(evsel);
169} 169}
170 170
171struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 171struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
172{ 172{
173 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 173 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
174 174
@@ -219,7 +219,7 @@ out:
219 return format; 219 return format;
220} 220}
221 221
222struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx) 222struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx)
223{ 223{
224 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 224 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
225 225
@@ -645,7 +645,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
645 } 645 }
646 } 646 }
647 647
648 if (perf_target__has_cpu(&opts->target)) 648 if (target__has_cpu(&opts->target) || opts->target.force_per_cpu)
649 perf_evsel__set_sample_bit(evsel, CPU); 649 perf_evsel__set_sample_bit(evsel, CPU);
650 650
651 if (opts->period) 651 if (opts->period)
@@ -653,7 +653,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
653 653
654 if (!perf_missing_features.sample_id_all && 654 if (!perf_missing_features.sample_id_all &&
655 (opts->sample_time || !opts->no_inherit || 655 (opts->sample_time || !opts->no_inherit ||
656 perf_target__has_cpu(&opts->target))) 656 target__has_cpu(&opts->target) || opts->target.force_per_cpu))
657 perf_evsel__set_sample_bit(evsel, TIME); 657 perf_evsel__set_sample_bit(evsel, TIME);
658 658
659 if (opts->raw_samples) { 659 if (opts->raw_samples) {
@@ -663,7 +663,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
663 } 663 }
664 664
665 if (opts->sample_address) 665 if (opts->sample_address)
666 attr->sample_type |= PERF_SAMPLE_DATA_SRC; 666 perf_evsel__set_sample_bit(evsel, DATA_SRC);
667 667
668 if (opts->no_delay) { 668 if (opts->no_delay) {
669 attr->watermark = 0; 669 attr->watermark = 0;
@@ -675,12 +675,14 @@ void perf_evsel__config(struct perf_evsel *evsel,
675 } 675 }
676 676
677 if (opts->sample_weight) 677 if (opts->sample_weight)
678 attr->sample_type |= PERF_SAMPLE_WEIGHT; 678 perf_evsel__set_sample_bit(evsel, WEIGHT);
679 679
680 attr->mmap = track; 680 attr->mmap = track;
681 attr->mmap2 = track && !perf_missing_features.mmap2;
682 attr->comm = track; 681 attr->comm = track;
683 682
683 if (opts->sample_transaction)
684 perf_evsel__set_sample_bit(evsel, TRANSACTION);
685
684 /* 686 /*
685 * XXX see the function comment above 687 * XXX see the function comment above
686 * 688 *
@@ -694,7 +696,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
694 * Setting enable_on_exec for independent events and 696 * Setting enable_on_exec for independent events and
695 * group leaders for traced executed by perf. 697 * group leaders for traced executed by perf.
696 */ 698 */
697 if (perf_target__none(&opts->target) && perf_evsel__is_group_leader(evsel)) 699 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel))
698 attr->enable_on_exec = 1; 700 attr->enable_on_exec = 1;
699} 701}
700 702
@@ -983,6 +985,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
983 ret += PRINT_ATTR2(exclude_host, exclude_guest); 985 ret += PRINT_ATTR2(exclude_host, exclude_guest);
984 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, 986 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel,
985 "excl.callchain_user", exclude_callchain_user); 987 "excl.callchain_user", exclude_callchain_user);
988 ret += PRINT_ATTR_U32(mmap2);
986 989
987 ret += PRINT_ATTR_U32(wakeup_events); 990 ret += PRINT_ATTR_U32(wakeup_events);
988 ret += PRINT_ATTR_U32(wakeup_watermark); 991 ret += PRINT_ATTR_U32(wakeup_watermark);
@@ -1048,6 +1051,8 @@ retry_open:
1048 group_fd, flags); 1051 group_fd, flags);
1049 if (FD(evsel, cpu, thread) < 0) { 1052 if (FD(evsel, cpu, thread) < 0) {
1050 err = -errno; 1053 err = -errno;
1054 pr_debug2("perf_event_open failed, error %d\n",
1055 err);
1051 goto try_fallback; 1056 goto try_fallback;
1052 } 1057 }
1053 set_rlimit = NO_CHANGE; 1058 set_rlimit = NO_CHANGE;
@@ -1214,6 +1219,7 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
1214 1219
1215 sample->pid = u.val32[0]; 1220 sample->pid = u.val32[0];
1216 sample->tid = u.val32[1]; 1221 sample->tid = u.val32[1];
1222 array--;
1217 } 1223 }
1218 1224
1219 return 0; 1225 return 0;
@@ -1453,6 +1459,9 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1453 array = (void *)array + sz; 1459 array = (void *)array + sz;
1454 OVERFLOW_CHECK_u64(array); 1460 OVERFLOW_CHECK_u64(array);
1455 data->user_stack.size = *array++; 1461 data->user_stack.size = *array++;
1462 if (WARN_ONCE(data->user_stack.size > sz,
1463 "user stack dump failure\n"))
1464 return -EFAULT;
1456 } 1465 }
1457 } 1466 }
1458 1467
@@ -1470,6 +1479,13 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1470 array++; 1479 array++;
1471 } 1480 }
1472 1481
1482 data->transaction = 0;
1483 if (type & PERF_SAMPLE_TRANSACTION) {
1484 OVERFLOW_CHECK_u64(array);
1485 data->transaction = *array;
1486 array++;
1487 }
1488
1473 return 0; 1489 return 0;
1474} 1490}
1475 1491
@@ -1562,6 +1578,9 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
1562 if (type & PERF_SAMPLE_DATA_SRC) 1578 if (type & PERF_SAMPLE_DATA_SRC)
1563 result += sizeof(u64); 1579 result += sizeof(u64);
1564 1580
1581 if (type & PERF_SAMPLE_TRANSACTION)
1582 result += sizeof(u64);
1583
1565 return result; 1584 return result;
1566} 1585}
1567 1586
@@ -1735,6 +1754,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
1735 array++; 1754 array++;
1736 } 1755 }
1737 1756
1757 if (type & PERF_SAMPLE_TRANSACTION) {
1758 *array = sample->transaction;
1759 array++;
1760 }
1761
1738 return 0; 1762 return 0;
1739} 1763}
1740 1764
@@ -1982,8 +2006,7 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
1982 return false; 2006 return false;
1983} 2007}
1984 2008
1985int perf_evsel__open_strerror(struct perf_evsel *evsel, 2009int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
1986 struct perf_target *target,
1987 int err, char *msg, size_t size) 2010 int err, char *msg, size_t size)
1988{ 2011{
1989 switch (err) { 2012 switch (err) {
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 4a7bdc713bab..1ea7c92e6e33 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -74,10 +74,7 @@ struct perf_evsel {
74 off_t id_offset; 74 off_t id_offset;
75 }; 75 };
76 struct cgroup_sel *cgrp; 76 struct cgroup_sel *cgrp;
77 struct { 77 void *handler;
78 void *func;
79 void *data;
80 } handler;
81 struct cpu_map *cpus; 78 struct cpu_map *cpus;
82 unsigned int sample_size; 79 unsigned int sample_size;
83 int id_pos; 80 int id_pos;
@@ -99,8 +96,19 @@ struct thread_map;
99struct perf_evlist; 96struct perf_evlist;
100struct perf_record_opts; 97struct perf_record_opts;
101 98
102struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); 99struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx);
103struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx); 100
101static inline struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr)
102{
103 return perf_evsel__new_idx(attr, 0);
104}
105
106struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx);
107
108static inline struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name)
109{
110 return perf_evsel__newtp_idx(sys, name, 0);
111}
104 112
105struct event_format *event_format__new(const char *sys, const char *name); 113struct event_format *event_format__new(const char *sys, const char *name);
106 114
@@ -197,6 +205,12 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1,
197 (e1->attr.config == e2->attr.config); 205 (e1->attr.config == e2->attr.config);
198} 206}
199 207
208#define perf_evsel__cmp(a, b) \
209 ((a) && \
210 (b) && \
211 (a)->attr.type == (b)->attr.type && \
212 (a)->attr.config == (b)->attr.config)
213
200int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 214int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
201 int cpu, int thread, bool scale); 215 int cpu, int thread, bool scale);
202 216
@@ -265,6 +279,11 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
265 return list_entry(evsel->node.next, struct perf_evsel, node); 279 return list_entry(evsel->node.next, struct perf_evsel, node);
266} 280}
267 281
282static inline struct perf_evsel *perf_evsel__prev(struct perf_evsel *evsel)
283{
284 return list_entry(evsel->node.prev, struct perf_evsel, node);
285}
286
268/** 287/**
269 * perf_evsel__is_group_leader - Return whether given evsel is a leader event 288 * perf_evsel__is_group_leader - Return whether given evsel is a leader event
270 * 289 *
@@ -304,8 +323,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
304 323
305bool perf_evsel__fallback(struct perf_evsel *evsel, int err, 324bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
306 char *msg, size_t msgsize); 325 char *msg, size_t msgsize);
307int perf_evsel__open_strerror(struct perf_evsel *evsel, 326int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
308 struct perf_target *target,
309 int err, char *msg, size_t size); 327 int err, char *msg, size_t size);
310 328
311static inline int perf_evsel__group_idx(struct perf_evsel *evsel) 329static inline int perf_evsel__group_idx(struct perf_evsel *evsel)
diff --git a/tools/perf/util/fs.c b/tools/perf/util/fs.c
new file mode 100644
index 000000000000..f5be1f26e724
--- /dev/null
+++ b/tools/perf/util/fs.c
@@ -0,0 +1,119 @@
1
2/* TODO merge/factor into tools/lib/lk/debugfs.c */
3
4#include "util.h"
5#include "util/fs.h"
6
7static const char * const sysfs__fs_known_mountpoints[] = {
8 "/sys",
9 0,
10};
11
12static const char * const procfs__known_mountpoints[] = {
13 "/proc",
14 0,
15};
16
17struct fs {
18 const char *name;
19 const char * const *mounts;
20 char path[PATH_MAX + 1];
21 bool found;
22 long magic;
23};
24
25enum {
26 FS__SYSFS = 0,
27 FS__PROCFS = 1,
28};
29
30static struct fs fs__entries[] = {
31 [FS__SYSFS] = {
32 .name = "sysfs",
33 .mounts = sysfs__fs_known_mountpoints,
34 .magic = SYSFS_MAGIC,
35 },
36 [FS__PROCFS] = {
37 .name = "proc",
38 .mounts = procfs__known_mountpoints,
39 .magic = PROC_SUPER_MAGIC,
40 },
41};
42
43static bool fs__read_mounts(struct fs *fs)
44{
45 bool found = false;
46 char type[100];
47 FILE *fp;
48
49 fp = fopen("/proc/mounts", "r");
50 if (fp == NULL)
51 return NULL;
52
53 while (!found &&
54 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
55 fs->path, type) == 2) {
56
57 if (strcmp(type, fs->name) == 0)
58 found = true;
59 }
60
61 fclose(fp);
62 return fs->found = found;
63}
64
65static int fs__valid_mount(const char *fs, long magic)
66{
67 struct statfs st_fs;
68
69 if (statfs(fs, &st_fs) < 0)
70 return -ENOENT;
71 else if (st_fs.f_type != magic)
72 return -ENOENT;
73
74 return 0;
75}
76
77static bool fs__check_mounts(struct fs *fs)
78{
79 const char * const *ptr;
80
81 ptr = fs->mounts;
82 while (*ptr) {
83 if (fs__valid_mount(*ptr, fs->magic) == 0) {
84 fs->found = true;
85 strcpy(fs->path, *ptr);
86 return true;
87 }
88 ptr++;
89 }
90
91 return false;
92}
93
94static const char *fs__get_mountpoint(struct fs *fs)
95{
96 if (fs__check_mounts(fs))
97 return fs->path;
98
99 return fs__read_mounts(fs) ? fs->path : NULL;
100}
101
102static const char *fs__mountpoint(int idx)
103{
104 struct fs *fs = &fs__entries[idx];
105
106 if (fs->found)
107 return (const char *)fs->path;
108
109 return fs__get_mountpoint(fs);
110}
111
112#define FS__MOUNTPOINT(name, idx) \
113const char *name##__mountpoint(void) \
114{ \
115 return fs__mountpoint(idx); \
116}
117
118FS__MOUNTPOINT(sysfs, FS__SYSFS);
119FS__MOUNTPOINT(procfs, FS__PROCFS);
diff --git a/tools/perf/util/fs.h b/tools/perf/util/fs.h
new file mode 100644
index 000000000000..5e09ce1bab0e
--- /dev/null
+++ b/tools/perf/util/fs.h
@@ -0,0 +1,7 @@
1#ifndef __PERF_FS
2#define __PERF_FS
3
4const char *sysfs__mountpoint(void);
5const char *procfs__mountpoint(void);
6
7#endif /* __PERF_FS */
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh
index 3ac38031d534..36a885d2cd22 100755
--- a/tools/perf/util/generate-cmdlist.sh
+++ b/tools/perf/util/generate-cmdlist.sh
@@ -22,7 +22,7 @@ do
22 }' "Documentation/perf-$cmd.txt" 22 }' "Documentation/perf-$cmd.txt"
23done 23done
24 24
25echo "#ifdef LIBELF_SUPPORT" 25echo "#ifdef HAVE_LIBELF_SUPPORT"
26sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt | 26sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt |
27sort | 27sort |
28while read cmd 28while read cmd
@@ -35,5 +35,5 @@ do
35 p 35 p
36 }' "Documentation/perf-$cmd.txt" 36 }' "Documentation/perf-$cmd.txt"
37done 37done
38echo "#endif /* LIBELF_SUPPORT */" 38echo "#endif /* HAVE_LIBELF_SUPPORT */"
39echo "};" 39echo "};"
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index c3e5a3b817ab..369c03648f88 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -22,6 +22,7 @@
22#include "vdso.h" 22#include "vdso.h"
23#include "strbuf.h" 23#include "strbuf.h"
24#include "build-id.h" 24#include "build-id.h"
25#include "data.h"
25 26
26static bool no_buildid_cache = false; 27static bool no_buildid_cache = false;
27 28
@@ -2189,7 +2190,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
2189{ 2190{
2190 struct header_print_data hd; 2191 struct header_print_data hd;
2191 struct perf_header *header = &session->header; 2192 struct perf_header *header = &session->header;
2192 int fd = session->fd; 2193 int fd = perf_data_file__fd(session->file);
2193 hd.fp = fp; 2194 hd.fp = fp;
2194 hd.full = full; 2195 hd.full = full;
2195 2196
@@ -2650,7 +2651,8 @@ static int perf_header__read_pipe(struct perf_session *session)
2650 struct perf_header *header = &session->header; 2651 struct perf_header *header = &session->header;
2651 struct perf_pipe_file_header f_header; 2652 struct perf_pipe_file_header f_header;
2652 2653
2653 if (perf_file_header__read_pipe(&f_header, header, session->fd, 2654 if (perf_file_header__read_pipe(&f_header, header,
2655 perf_data_file__fd(session->file),
2654 session->repipe) < 0) { 2656 session->repipe) < 0) {
2655 pr_debug("incompatible file format\n"); 2657 pr_debug("incompatible file format\n");
2656 return -EINVAL; 2658 return -EINVAL;
@@ -2751,18 +2753,19 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
2751 2753
2752int perf_session__read_header(struct perf_session *session) 2754int perf_session__read_header(struct perf_session *session)
2753{ 2755{
2756 struct perf_data_file *file = session->file;
2754 struct perf_header *header = &session->header; 2757 struct perf_header *header = &session->header;
2755 struct perf_file_header f_header; 2758 struct perf_file_header f_header;
2756 struct perf_file_attr f_attr; 2759 struct perf_file_attr f_attr;
2757 u64 f_id; 2760 u64 f_id;
2758 int nr_attrs, nr_ids, i, j; 2761 int nr_attrs, nr_ids, i, j;
2759 int fd = session->fd; 2762 int fd = perf_data_file__fd(file);
2760 2763
2761 session->evlist = perf_evlist__new(); 2764 session->evlist = perf_evlist__new();
2762 if (session->evlist == NULL) 2765 if (session->evlist == NULL)
2763 return -ENOMEM; 2766 return -ENOMEM;
2764 2767
2765 if (session->fd_pipe) 2768 if (perf_data_file__is_pipe(file))
2766 return perf_header__read_pipe(session); 2769 return perf_header__read_pipe(session);
2767 2770
2768 if (perf_file_header__read(&f_header, header, fd) < 0) 2771 if (perf_file_header__read(&f_header, header, fd) < 0)
@@ -2777,7 +2780,7 @@ int perf_session__read_header(struct perf_session *session)
2777 if (f_header.data.size == 0) { 2780 if (f_header.data.size == 0) {
2778 pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n" 2781 pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n"
2779 "Was the 'perf record' command properly terminated?\n", 2782 "Was the 'perf record' command properly terminated?\n",
2780 session->filename); 2783 file->path);
2781 } 2784 }
2782 2785
2783 nr_attrs = f_header.attrs.size / f_header.attr_size; 2786 nr_attrs = f_header.attrs.size / f_header.attr_size;
@@ -2794,7 +2797,7 @@ int perf_session__read_header(struct perf_session *session)
2794 perf_event__attr_swap(&f_attr.attr); 2797 perf_event__attr_swap(&f_attr.attr);
2795 2798
2796 tmp = lseek(fd, 0, SEEK_CUR); 2799 tmp = lseek(fd, 0, SEEK_CUR);
2797 evsel = perf_evsel__new(&f_attr.attr, i); 2800 evsel = perf_evsel__new(&f_attr.attr);
2798 2801
2799 if (evsel == NULL) 2802 if (evsel == NULL)
2800 goto out_delete_evlist; 2803 goto out_delete_evlist;
@@ -2913,7 +2916,7 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
2913 return -ENOMEM; 2916 return -ENOMEM;
2914 } 2917 }
2915 2918
2916 evsel = perf_evsel__new(&event->attr.attr, evlist->nr_entries); 2919 evsel = perf_evsel__new(&event->attr.attr);
2917 if (evsel == NULL) 2920 if (evsel == NULL)
2918 return -ENOMEM; 2921 return -ENOMEM;
2919 2922
@@ -2990,18 +2993,19 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
2990 struct perf_session *session) 2993 struct perf_session *session)
2991{ 2994{
2992 ssize_t size_read, padding, size = event->tracing_data.size; 2995 ssize_t size_read, padding, size = event->tracing_data.size;
2993 off_t offset = lseek(session->fd, 0, SEEK_CUR); 2996 int fd = perf_data_file__fd(session->file);
2997 off_t offset = lseek(fd, 0, SEEK_CUR);
2994 char buf[BUFSIZ]; 2998 char buf[BUFSIZ];
2995 2999
2996 /* setup for reading amidst mmap */ 3000 /* setup for reading amidst mmap */
2997 lseek(session->fd, offset + sizeof(struct tracing_data_event), 3001 lseek(fd, offset + sizeof(struct tracing_data_event),
2998 SEEK_SET); 3002 SEEK_SET);
2999 3003
3000 size_read = trace_report(session->fd, &session->pevent, 3004 size_read = trace_report(fd, &session->pevent,
3001 session->repipe); 3005 session->repipe);
3002 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 3006 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
3003 3007
3004 if (readn(session->fd, buf, padding) < 0) { 3008 if (readn(fd, buf, padding) < 0) {
3005 pr_err("%s: reading input file", __func__); 3009 pr_err("%s: reading input file", __func__);
3006 return -1; 3010 return -1;
3007 } 3011 }
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 9ff6cf3e9a99..822903eaa201 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -160,6 +160,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
160 hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3); 160 hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3);
161 hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); 161 hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
162 hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); 162 hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
163
164 if (h->transaction)
165 hists__new_col_len(hists, HISTC_TRANSACTION,
166 hist_entry__transaction_len());
163} 167}
164 168
165void hists__output_recalc_col_len(struct hists *hists, int max_rows) 169void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@@ -346,7 +350,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
346 struct rb_node **p; 350 struct rb_node **p;
347 struct rb_node *parent = NULL; 351 struct rb_node *parent = NULL;
348 struct hist_entry *he; 352 struct hist_entry *he;
349 int cmp; 353 int64_t cmp;
350 354
351 p = &hists->entries_in->rb_node; 355 p = &hists->entries_in->rb_node;
352 356
@@ -395,6 +399,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
395 if (!he) 399 if (!he)
396 return NULL; 400 return NULL;
397 401
402 hists->nr_entries++;
398 rb_link_node(&he->rb_node_in, parent, p); 403 rb_link_node(&he->rb_node_in, parent, p);
399 rb_insert_color(&he->rb_node_in, hists->entries_in); 404 rb_insert_color(&he->rb_node_in, hists->entries_in);
400out: 405out:
@@ -402,74 +407,16 @@ out:
402 return he; 407 return he;
403} 408}
404 409
405struct hist_entry *__hists__add_mem_entry(struct hists *self, 410struct hist_entry *__hists__add_entry(struct hists *hists,
406 struct addr_location *al,
407 struct symbol *sym_parent,
408 struct mem_info *mi,
409 u64 period,
410 u64 weight)
411{
412 struct hist_entry entry = {
413 .thread = al->thread,
414 .ms = {
415 .map = al->map,
416 .sym = al->sym,
417 },
418 .stat = {
419 .period = period,
420 .weight = weight,
421 .nr_events = 1,
422 },
423 .cpu = al->cpu,
424 .ip = al->addr,
425 .level = al->level,
426 .parent = sym_parent,
427 .filtered = symbol__parent_filter(sym_parent),
428 .hists = self,
429 .mem_info = mi,
430 .branch_info = NULL,
431 };
432 return add_hist_entry(self, &entry, al, period, weight);
433}
434
435struct hist_entry *__hists__add_branch_entry(struct hists *self,
436 struct addr_location *al,
437 struct symbol *sym_parent,
438 struct branch_info *bi,
439 u64 period,
440 u64 weight)
441{
442 struct hist_entry entry = {
443 .thread = al->thread,
444 .ms = {
445 .map = bi->to.map,
446 .sym = bi->to.sym,
447 },
448 .cpu = al->cpu,
449 .ip = bi->to.addr,
450 .level = al->level,
451 .stat = {
452 .period = period,
453 .nr_events = 1,
454 .weight = weight,
455 },
456 .parent = sym_parent,
457 .filtered = symbol__parent_filter(sym_parent),
458 .branch_info = bi,
459 .hists = self,
460 .mem_info = NULL,
461 };
462
463 return add_hist_entry(self, &entry, al, period, weight);
464}
465
466struct hist_entry *__hists__add_entry(struct hists *self,
467 struct addr_location *al, 411 struct addr_location *al,
468 struct symbol *sym_parent, u64 period, 412 struct symbol *sym_parent,
469 u64 weight) 413 struct branch_info *bi,
414 struct mem_info *mi,
415 u64 period, u64 weight, u64 transaction)
470{ 416{
471 struct hist_entry entry = { 417 struct hist_entry entry = {
472 .thread = al->thread, 418 .thread = al->thread,
419 .comm = thread__comm(al->thread),
473 .ms = { 420 .ms = {
474 .map = al->map, 421 .map = al->map,
475 .sym = al->sym, 422 .sym = al->sym,
@@ -478,18 +425,19 @@ struct hist_entry *__hists__add_entry(struct hists *self,
478 .ip = al->addr, 425 .ip = al->addr,
479 .level = al->level, 426 .level = al->level,
480 .stat = { 427 .stat = {
481 .period = period,
482 .nr_events = 1, 428 .nr_events = 1,
429 .period = period,
483 .weight = weight, 430 .weight = weight,
484 }, 431 },
485 .parent = sym_parent, 432 .parent = sym_parent,
486 .filtered = symbol__parent_filter(sym_parent), 433 .filtered = symbol__parent_filter(sym_parent),
487 .hists = self, 434 .hists = hists,
488 .branch_info = NULL, 435 .branch_info = bi,
489 .mem_info = NULL, 436 .mem_info = mi,
437 .transaction = transaction,
490 }; 438 };
491 439
492 return add_hist_entry(self, &entry, al, period, weight); 440 return add_hist_entry(hists, &entry, al, period, weight);
493} 441}
494 442
495int64_t 443int64_t
@@ -530,6 +478,7 @@ void hist_entry__free(struct hist_entry *he)
530{ 478{
531 free(he->branch_info); 479 free(he->branch_info);
532 free(he->mem_info); 480 free(he->mem_info);
481 free_srcline(he->srcline);
533 free(he); 482 free(he);
534} 483}
535 484
@@ -598,7 +547,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
598 hists__filter_entry_by_symbol(hists, he); 547 hists__filter_entry_by_symbol(hists, he);
599} 548}
600 549
601void hists__collapse_resort(struct hists *hists) 550void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
602{ 551{
603 struct rb_root *root; 552 struct rb_root *root;
604 struct rb_node *next; 553 struct rb_node *next;
@@ -625,6 +574,8 @@ void hists__collapse_resort(struct hists *hists)
625 */ 574 */
626 hists__apply_filters(hists, n); 575 hists__apply_filters(hists, n);
627 } 576 }
577 if (prog)
578 ui_progress__update(prog, 1);
628 } 579 }
629} 580}
630 581
@@ -884,7 +835,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
884 struct rb_node **p; 835 struct rb_node **p;
885 struct rb_node *parent = NULL; 836 struct rb_node *parent = NULL;
886 struct hist_entry *he; 837 struct hist_entry *he;
887 int cmp; 838 int64_t cmp;
888 839
889 if (sort__need_collapse) 840 if (sort__need_collapse)
890 root = &hists->entries_collapsed; 841 root = &hists->entries_collapsed;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 1329b6b6ffe6..b621347a1585 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -5,6 +5,8 @@
5#include <pthread.h> 5#include <pthread.h>
6#include "callchain.h" 6#include "callchain.h"
7#include "header.h" 7#include "header.h"
8#include "color.h"
9#include "ui/progress.h"
8 10
9extern struct callchain_param callchain_param; 11extern struct callchain_param callchain_param;
10 12
@@ -45,6 +47,8 @@ enum hist_column {
45 HISTC_CPU, 47 HISTC_CPU,
46 HISTC_SRCLINE, 48 HISTC_SRCLINE,
47 HISTC_MISPREDICT, 49 HISTC_MISPREDICT,
50 HISTC_IN_TX,
51 HISTC_ABORT,
48 HISTC_SYMBOL_FROM, 52 HISTC_SYMBOL_FROM,
49 HISTC_SYMBOL_TO, 53 HISTC_SYMBOL_TO,
50 HISTC_DSO_FROM, 54 HISTC_DSO_FROM,
@@ -57,6 +61,7 @@ enum hist_column {
57 HISTC_MEM_TLB, 61 HISTC_MEM_TLB,
58 HISTC_MEM_LVL, 62 HISTC_MEM_LVL,
59 HISTC_MEM_SNOOP, 63 HISTC_MEM_SNOOP,
64 HISTC_TRANSACTION,
60 HISTC_NR_COLS, /* Last entry */ 65 HISTC_NR_COLS, /* Last entry */
61}; 66};
62 67
@@ -79,54 +84,43 @@ struct hists {
79 u16 col_len[HISTC_NR_COLS]; 84 u16 col_len[HISTC_NR_COLS];
80}; 85};
81 86
82struct hist_entry *__hists__add_entry(struct hists *self, 87struct hist_entry *__hists__add_entry(struct hists *hists,
83 struct addr_location *al, 88 struct addr_location *al,
84 struct symbol *parent, u64 period, 89 struct symbol *parent,
85 u64 weight); 90 struct branch_info *bi,
91 struct mem_info *mi, u64 period,
92 u64 weight, u64 transaction);
86int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 93int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
87int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 94int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
88int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, 95int hist_entry__transaction_len(void);
96int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
89 struct hists *hists); 97 struct hists *hists);
90void hist_entry__free(struct hist_entry *); 98void hist_entry__free(struct hist_entry *);
91 99
92struct hist_entry *__hists__add_branch_entry(struct hists *self, 100void hists__output_resort(struct hists *hists);
93 struct addr_location *al, 101void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
94 struct symbol *sym_parent,
95 struct branch_info *bi,
96 u64 period,
97 u64 weight);
98
99struct hist_entry *__hists__add_mem_entry(struct hists *self,
100 struct addr_location *al,
101 struct symbol *sym_parent,
102 struct mem_info *mi,
103 u64 period,
104 u64 weight);
105
106void hists__output_resort(struct hists *self);
107void hists__collapse_resort(struct hists *self);
108 102
109void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); 103void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
110void hists__output_recalc_col_len(struct hists *hists, int max_rows); 104void hists__output_recalc_col_len(struct hists *hists, int max_rows);
111 105
112void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); 106void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
113void hists__inc_nr_events(struct hists *self, u32 type); 107void hists__inc_nr_events(struct hists *hists, u32 type);
114void events_stats__inc(struct events_stats *stats, u32 type); 108void events_stats__inc(struct events_stats *stats, u32 type);
115size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); 109size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
116 110
117size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, 111size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
118 int max_cols, float min_pcnt, FILE *fp); 112 int max_cols, float min_pcnt, FILE *fp);
119 113
120int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); 114int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr);
121int hist_entry__annotate(struct hist_entry *self, size_t privsize); 115int hist_entry__annotate(struct hist_entry *he, size_t privsize);
122 116
123void hists__filter_by_dso(struct hists *hists); 117void hists__filter_by_dso(struct hists *hists);
124void hists__filter_by_thread(struct hists *hists); 118void hists__filter_by_thread(struct hists *hists);
125void hists__filter_by_symbol(struct hists *hists); 119void hists__filter_by_symbol(struct hists *hists);
126 120
127u16 hists__col_len(struct hists *self, enum hist_column col); 121u16 hists__col_len(struct hists *hists, enum hist_column col);
128void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 122void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len);
129bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); 123bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len);
130void hists__reset_col_len(struct hists *hists); 124void hists__reset_col_len(struct hists *hists);
131void hists__calc_col_len(struct hists *hists, struct hist_entry *he); 125void hists__calc_col_len(struct hists *hists, struct hist_entry *he);
132 126
@@ -175,6 +169,18 @@ void perf_hpp__init(void);
175void perf_hpp__column_register(struct perf_hpp_fmt *format); 169void perf_hpp__column_register(struct perf_hpp_fmt *format);
176void perf_hpp__column_enable(unsigned col); 170void perf_hpp__column_enable(unsigned col);
177 171
172static inline size_t perf_hpp__use_color(void)
173{
174 return !symbol_conf.field_sep;
175}
176
177static inline size_t perf_hpp__color_overhead(void)
178{
179 return perf_hpp__use_color() ?
180 (COLOR_MAXLEN + sizeof(PERF_COLOR_RESET)) * PERF_HPP__MAX_INDEX
181 : 0;
182}
183
178struct perf_evlist; 184struct perf_evlist;
179 185
180struct hist_browser_timer { 186struct hist_browser_timer {
@@ -183,7 +189,7 @@ struct hist_browser_timer {
183 int refresh; 189 int refresh;
184}; 190};
185 191
186#ifdef SLANG_SUPPORT 192#ifdef HAVE_SLANG_SUPPORT
187#include "../ui/keysyms.h" 193#include "../ui/keysyms.h"
188int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, 194int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
189 struct hist_browser_timer *hbt); 195 struct hist_browser_timer *hbt);
@@ -204,12 +210,9 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
204 return 0; 210 return 0;
205} 211}
206 212
207static inline int hist_entry__tui_annotate(struct hist_entry *self 213static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused,
208 __maybe_unused, 214 struct perf_evsel *evsel __maybe_unused,
209 struct perf_evsel *evsel 215 struct hist_browser_timer *hbt __maybe_unused)
210 __maybe_unused,
211 struct hist_browser_timer *hbt
212 __maybe_unused)
213{ 216{
214 return 0; 217 return 0;
215} 218}
@@ -224,20 +227,5 @@ static inline int script_browse(const char *script_opt __maybe_unused)
224#define K_SWITCH_INPUT_DATA -3000 227#define K_SWITCH_INPUT_DATA -3000
225#endif 228#endif
226 229
227#ifdef GTK2_SUPPORT 230unsigned int hists__sort_list_width(struct hists *hists);
228int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
229 struct hist_browser_timer *hbt __maybe_unused,
230 float min_pcnt);
231#else
232static inline
233int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
234 const char *help __maybe_unused,
235 struct hist_browser_timer *hbt __maybe_unused,
236 float min_pcnt __maybe_unused)
237{
238 return 0;
239}
240#endif
241
242unsigned int hists__sort_list_width(struct hists *self);
243#endif /* __PERF_HIST_H */ 231#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/dwarf-regs.h b/tools/perf/util/include/dwarf-regs.h
index cf6727e99c44..8f149655f497 100644
--- a/tools/perf/util/include/dwarf-regs.h
+++ b/tools/perf/util/include/dwarf-regs.h
@@ -1,7 +1,7 @@
1#ifndef _PERF_DWARF_REGS_H_ 1#ifndef _PERF_DWARF_REGS_H_
2#define _PERF_DWARF_REGS_H_ 2#define _PERF_DWARF_REGS_H_
3 3
4#ifdef DWARF_SUPPORT 4#ifdef HAVE_DWARF_SUPPORT
5const char *get_arch_regstr(unsigned int n); 5const char *get_arch_regstr(unsigned int n);
6#endif 6#endif
7 7
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
index 96b919dae11c..b003ad7200b2 100644
--- a/tools/perf/util/include/linux/compiler.h
+++ b/tools/perf/util/include/linux/compiler.h
@@ -2,20 +2,29 @@
2#define _PERF_LINUX_COMPILER_H_ 2#define _PERF_LINUX_COMPILER_H_
3 3
4#ifndef __always_inline 4#ifndef __always_inline
5#define __always_inline inline 5# define __always_inline inline __attribute__((always_inline))
6#endif 6#endif
7
7#define __user 8#define __user
9
8#ifndef __attribute_const__ 10#ifndef __attribute_const__
9#define __attribute_const__ 11# define __attribute_const__
10#endif 12#endif
11 13
12#ifndef __maybe_unused 14#ifndef __maybe_unused
13#define __maybe_unused __attribute__((unused)) 15# define __maybe_unused __attribute__((unused))
16#endif
17
18#ifndef __packed
19# define __packed __attribute__((__packed__))
14#endif 20#endif
15#define __packed __attribute__((__packed__))
16 21
17#ifndef __force 22#ifndef __force
18#define __force 23# define __force
24#endif
25
26#ifndef __weak
27# define __weak __attribute__((weak))
19#endif 28#endif
20 29
21#endif 30#endif
diff --git a/tools/perf/util/include/linux/magic.h b/tools/perf/util/include/linux/magic.h
index 58b64ed4da12..07d63cf3e0f6 100644
--- a/tools/perf/util/include/linux/magic.h
+++ b/tools/perf/util/include/linux/magic.h
@@ -9,4 +9,8 @@
9#define SYSFS_MAGIC 0x62656572 9#define SYSFS_MAGIC 0x62656572
10#endif 10#endif
11 11
12#ifndef PROC_SUPER_MAGIC
13#define PROC_SUPER_MAGIC 0x9fa0
14#endif
15
12#endif 16#endif
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c
index 11a8d86f7fea..89715b64a315 100644
--- a/tools/perf/util/intlist.c
+++ b/tools/perf/util/intlist.c
@@ -20,6 +20,7 @@ static struct rb_node *intlist__node_new(struct rblist *rblist __maybe_unused,
20 20
21 if (node != NULL) { 21 if (node != NULL) {
22 node->i = i; 22 node->i = i;
23 node->priv = NULL;
23 rc = &node->rb_node; 24 rc = &node->rb_node;
24 } 25 }
25 26
@@ -57,22 +58,36 @@ void intlist__remove(struct intlist *ilist, struct int_node *node)
57 rblist__remove_node(&ilist->rblist, &node->rb_node); 58 rblist__remove_node(&ilist->rblist, &node->rb_node);
58} 59}
59 60
60struct int_node *intlist__find(struct intlist *ilist, int i) 61static struct int_node *__intlist__findnew(struct intlist *ilist,
62 int i, bool create)
61{ 63{
62 struct int_node *node; 64 struct int_node *node = NULL;
63 struct rb_node *rb_node; 65 struct rb_node *rb_node;
64 66
65 if (ilist == NULL) 67 if (ilist == NULL)
66 return NULL; 68 return NULL;
67 69
68 node = NULL; 70 if (create)
69 rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); 71 rb_node = rblist__findnew(&ilist->rblist, (void *)((long)i));
72 else
73 rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
74
70 if (rb_node) 75 if (rb_node)
71 node = container_of(rb_node, struct int_node, rb_node); 76 node = container_of(rb_node, struct int_node, rb_node);
72 77
73 return node; 78 return node;
74} 79}
75 80
81struct int_node *intlist__find(struct intlist *ilist, int i)
82{
83 return __intlist__findnew(ilist, i, false);
84}
85
86struct int_node *intlist__findnew(struct intlist *ilist, int i)
87{
88 return __intlist__findnew(ilist, i, true);
89}
90
76static int intlist__parse_list(struct intlist *ilist, const char *s) 91static int intlist__parse_list(struct intlist *ilist, const char *s)
77{ 92{
78 char *sep; 93 char *sep;
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h
index 62351dad848f..aa6877d36858 100644
--- a/tools/perf/util/intlist.h
+++ b/tools/perf/util/intlist.h
@@ -9,6 +9,7 @@
9struct int_node { 9struct int_node {
10 struct rb_node rb_node; 10 struct rb_node rb_node;
11 int i; 11 int i;
12 void *priv;
12}; 13};
13 14
14struct intlist { 15struct intlist {
@@ -23,6 +24,7 @@ int intlist__add(struct intlist *ilist, int i);
23 24
24struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx); 25struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx);
25struct int_node *intlist__find(struct intlist *ilist, int i); 26struct int_node *intlist__find(struct intlist *ilist, int i);
27struct int_node *intlist__findnew(struct intlist *ilist, int i);
26 28
27static inline bool intlist__has_entry(struct intlist *ilist, int i) 29static inline bool intlist__has_entry(struct intlist *ilist, int i)
28{ 30{
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 6188d2876a71..84cdb072ac83 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -40,12 +40,29 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
40 return -ENOMEM; 40 return -ENOMEM;
41 41
42 snprintf(comm, sizeof(comm), "[guest/%d]", pid); 42 snprintf(comm, sizeof(comm), "[guest/%d]", pid);
43 thread__set_comm(thread, comm); 43 thread__set_comm(thread, comm, 0);
44 } 44 }
45 45
46 return 0; 46 return 0;
47} 47}
48 48
49struct machine *machine__new_host(void)
50{
51 struct machine *machine = malloc(sizeof(*machine));
52
53 if (machine != NULL) {
54 machine__init(machine, "", HOST_KERNEL_ID);
55
56 if (machine__create_kernel_maps(machine) < 0)
57 goto out_delete;
58 }
59
60 return machine;
61out_delete:
62 free(machine);
63 return NULL;
64}
65
49static void dsos__delete(struct list_head *dsos) 66static void dsos__delete(struct list_head *dsos)
50{ 67{
51 struct dso *pos, *n; 68 struct dso *pos, *n;
@@ -314,7 +331,8 @@ struct thread *machine__find_thread(struct machine *machine, pid_t tid)
314 return __machine__findnew_thread(machine, 0, tid, false); 331 return __machine__findnew_thread(machine, 0, tid, false);
315} 332}
316 333
317int machine__process_comm_event(struct machine *machine, union perf_event *event) 334int machine__process_comm_event(struct machine *machine, union perf_event *event,
335 struct perf_sample *sample)
318{ 336{
319 struct thread *thread = machine__findnew_thread(machine, 337 struct thread *thread = machine__findnew_thread(machine,
320 event->comm.pid, 338 event->comm.pid,
@@ -323,7 +341,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
323 if (dump_trace) 341 if (dump_trace)
324 perf_event__fprintf_comm(event, stdout); 342 perf_event__fprintf_comm(event, stdout);
325 343
326 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { 344 if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) {
327 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 345 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
328 return -1; 346 return -1;
329 } 347 }
@@ -332,7 +350,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
332} 350}
333 351
334int machine__process_lost_event(struct machine *machine __maybe_unused, 352int machine__process_lost_event(struct machine *machine __maybe_unused,
335 union perf_event *event) 353 union perf_event *event, struct perf_sample *sample __maybe_unused)
336{ 354{
337 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", 355 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
338 event->lost.id, event->lost.lost); 356 event->lost.id, event->lost.lost);
@@ -776,75 +794,44 @@ static int machine__set_modules_path(struct machine *machine)
776 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); 794 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
777} 795}
778 796
779static int machine__create_modules(struct machine *machine) 797static int machine__create_module(void *arg, const char *name, u64 start)
780{ 798{
781 char *line = NULL; 799 struct machine *machine = arg;
782 size_t n;
783 FILE *file;
784 struct map *map; 800 struct map *map;
801
802 map = machine__new_module(machine, start, name);
803 if (map == NULL)
804 return -1;
805
806 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
807
808 return 0;
809}
810
811static int machine__create_modules(struct machine *machine)
812{
785 const char *modules; 813 const char *modules;
786 char path[PATH_MAX]; 814 char path[PATH_MAX];
787 815
788 if (machine__is_default_guest(machine)) 816 if (machine__is_default_guest(machine)) {
789 modules = symbol_conf.default_guest_modules; 817 modules = symbol_conf.default_guest_modules;
790 else { 818 } else {
791 sprintf(path, "%s/proc/modules", machine->root_dir); 819 snprintf(path, PATH_MAX, "%s/proc/modules", machine->root_dir);
792 modules = path; 820 modules = path;
793 } 821 }
794 822
795 if (symbol__restricted_filename(modules, "/proc/modules")) 823 if (symbol__restricted_filename(modules, "/proc/modules"))
796 return -1; 824 return -1;
797 825
798 file = fopen(modules, "r"); 826 if (modules__parse(modules, machine, machine__create_module))
799 if (file == NULL)
800 return -1; 827 return -1;
801 828
802 while (!feof(file)) { 829 if (!machine__set_modules_path(machine))
803 char name[PATH_MAX]; 830 return 0;
804 u64 start;
805 char *sep;
806 int line_len;
807
808 line_len = getline(&line, &n, file);
809 if (line_len < 0)
810 break;
811
812 if (!line)
813 goto out_failure;
814
815 line[--line_len] = '\0'; /* \n */
816
817 sep = strrchr(line, 'x');
818 if (sep == NULL)
819 continue;
820
821 hex2u64(sep + 1, &start);
822
823 sep = strchr(line, ' ');
824 if (sep == NULL)
825 continue;
826
827 *sep = '\0';
828
829 snprintf(name, sizeof(name), "[%s]", line);
830 map = machine__new_module(machine, start, name);
831 if (map == NULL)
832 goto out_delete_line;
833 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
834 }
835 831
836 free(line); 832 pr_debug("Problems setting modules path maps, continuing anyway...\n");
837 fclose(file);
838 833
839 if (machine__set_modules_path(machine) < 0) {
840 pr_debug("Problems setting modules path maps, continuing anyway...\n");
841 }
842 return 0; 834 return 0;
843
844out_delete_line:
845 free(line);
846out_failure:
847 return -1;
848} 835}
849 836
850int machine__create_kernel_maps(struct machine *machine) 837int machine__create_kernel_maps(struct machine *machine)
@@ -998,7 +985,8 @@ out_problem:
998} 985}
999 986
1000int machine__process_mmap2_event(struct machine *machine, 987int machine__process_mmap2_event(struct machine *machine,
1001 union perf_event *event) 988 union perf_event *event,
989 struct perf_sample *sample __maybe_unused)
1002{ 990{
1003 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 991 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1004 struct thread *thread; 992 struct thread *thread;
@@ -1045,7 +1033,8 @@ out_problem:
1045 return 0; 1033 return 0;
1046} 1034}
1047 1035
1048int machine__process_mmap_event(struct machine *machine, union perf_event *event) 1036int machine__process_mmap_event(struct machine *machine, union perf_event *event,
1037 struct perf_sample *sample __maybe_unused)
1049{ 1038{
1050 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1039 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1051 struct thread *thread; 1040 struct thread *thread;
@@ -1102,7 +1091,8 @@ static void machine__remove_thread(struct machine *machine, struct thread *th)
1102 list_add_tail(&th->node, &machine->dead_threads); 1091 list_add_tail(&th->node, &machine->dead_threads);
1103} 1092}
1104 1093
1105int machine__process_fork_event(struct machine *machine, union perf_event *event) 1094int machine__process_fork_event(struct machine *machine, union perf_event *event,
1095 struct perf_sample *sample)
1106{ 1096{
1107 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1097 struct thread *thread = machine__find_thread(machine, event->fork.tid);
1108 struct thread *parent = machine__findnew_thread(machine, 1098 struct thread *parent = machine__findnew_thread(machine,
@@ -1119,7 +1109,7 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1119 perf_event__fprintf_task(event, stdout); 1109 perf_event__fprintf_task(event, stdout);
1120 1110
1121 if (thread == NULL || parent == NULL || 1111 if (thread == NULL || parent == NULL ||
1122 thread__fork(thread, parent) < 0) { 1112 thread__fork(thread, parent, sample->time) < 0) {
1123 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); 1113 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
1124 return -1; 1114 return -1;
1125 } 1115 }
@@ -1127,8 +1117,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1127 return 0; 1117 return 0;
1128} 1118}
1129 1119
1130int machine__process_exit_event(struct machine *machine __maybe_unused, 1120int machine__process_exit_event(struct machine *machine, union perf_event *event,
1131 union perf_event *event) 1121 struct perf_sample *sample __maybe_unused)
1132{ 1122{
1133 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1123 struct thread *thread = machine__find_thread(machine, event->fork.tid);
1134 1124
@@ -1141,23 +1131,24 @@ int machine__process_exit_event(struct machine *machine __maybe_unused,
1141 return 0; 1131 return 0;
1142} 1132}
1143 1133
1144int machine__process_event(struct machine *machine, union perf_event *event) 1134int machine__process_event(struct machine *machine, union perf_event *event,
1135 struct perf_sample *sample)
1145{ 1136{
1146 int ret; 1137 int ret;
1147 1138
1148 switch (event->header.type) { 1139 switch (event->header.type) {
1149 case PERF_RECORD_COMM: 1140 case PERF_RECORD_COMM:
1150 ret = machine__process_comm_event(machine, event); break; 1141 ret = machine__process_comm_event(machine, event, sample); break;
1151 case PERF_RECORD_MMAP: 1142 case PERF_RECORD_MMAP:
1152 ret = machine__process_mmap_event(machine, event); break; 1143 ret = machine__process_mmap_event(machine, event, sample); break;
1153 case PERF_RECORD_MMAP2: 1144 case PERF_RECORD_MMAP2:
1154 ret = machine__process_mmap2_event(machine, event); break; 1145 ret = machine__process_mmap2_event(machine, event, sample); break;
1155 case PERF_RECORD_FORK: 1146 case PERF_RECORD_FORK:
1156 ret = machine__process_fork_event(machine, event); break; 1147 ret = machine__process_fork_event(machine, event, sample); break;
1157 case PERF_RECORD_EXIT: 1148 case PERF_RECORD_EXIT:
1158 ret = machine__process_exit_event(machine, event); break; 1149 ret = machine__process_exit_event(machine, event, sample); break;
1159 case PERF_RECORD_LOST: 1150 case PERF_RECORD_LOST:
1160 ret = machine__process_lost_event(machine, event); break; 1151 ret = machine__process_lost_event(machine, event, sample); break;
1161 default: 1152 default:
1162 ret = -1; 1153 ret = -1;
1163 break; 1154 break;
@@ -1267,10 +1258,12 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1267 struct thread *thread, 1258 struct thread *thread,
1268 struct ip_callchain *chain, 1259 struct ip_callchain *chain,
1269 struct symbol **parent, 1260 struct symbol **parent,
1270 struct addr_location *root_al) 1261 struct addr_location *root_al,
1262 int max_stack)
1271{ 1263{
1272 u8 cpumode = PERF_RECORD_MISC_USER; 1264 u8 cpumode = PERF_RECORD_MISC_USER;
1273 unsigned int i; 1265 int chain_nr = min(max_stack, (int)chain->nr);
1266 int i;
1274 int err; 1267 int err;
1275 1268
1276 callchain_cursor_reset(&callchain_cursor); 1269 callchain_cursor_reset(&callchain_cursor);
@@ -1280,7 +1273,7 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1280 return 0; 1273 return 0;
1281 } 1274 }
1282 1275
1283 for (i = 0; i < chain->nr; i++) { 1276 for (i = 0; i < chain_nr; i++) {
1284 u64 ip; 1277 u64 ip;
1285 struct addr_location al; 1278 struct addr_location al;
1286 1279
@@ -1352,12 +1345,14 @@ int machine__resolve_callchain(struct machine *machine,
1352 struct thread *thread, 1345 struct thread *thread,
1353 struct perf_sample *sample, 1346 struct perf_sample *sample,
1354 struct symbol **parent, 1347 struct symbol **parent,
1355 struct addr_location *root_al) 1348 struct addr_location *root_al,
1349 int max_stack)
1356{ 1350{
1357 int ret; 1351 int ret;
1358 1352
1359 ret = machine__resolve_callchain_sample(machine, thread, 1353 ret = machine__resolve_callchain_sample(machine, thread,
1360 sample->callchain, parent, root_al); 1354 sample->callchain, parent,
1355 root_al, max_stack);
1361 if (ret) 1356 if (ret)
1362 return ret; 1357 return ret;
1363 1358
@@ -1373,6 +1368,41 @@ int machine__resolve_callchain(struct machine *machine,
1373 1368
1374 return unwind__get_entries(unwind_entry, &callchain_cursor, machine, 1369 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
1375 thread, evsel->attr.sample_regs_user, 1370 thread, evsel->attr.sample_regs_user,
1376 sample); 1371 sample, max_stack);
1377 1372
1378} 1373}
1374
1375int machine__for_each_thread(struct machine *machine,
1376 int (*fn)(struct thread *thread, void *p),
1377 void *priv)
1378{
1379 struct rb_node *nd;
1380 struct thread *thread;
1381 int rc = 0;
1382
1383 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
1384 thread = rb_entry(nd, struct thread, rb_node);
1385 rc = fn(thread, priv);
1386 if (rc != 0)
1387 return rc;
1388 }
1389
1390 list_for_each_entry(thread, &machine->dead_threads, node) {
1391 rc = fn(thread, priv);
1392 if (rc != 0)
1393 return rc;
1394 }
1395 return rc;
1396}
1397
1398int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
1399 struct target *target, struct thread_map *threads,
1400 perf_event__handler_t process, bool data_mmap)
1401{
1402 if (target__has_task(target))
1403 return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap);
1404 else if (target__has_cpu(target))
1405 return perf_event__synthesize_threads(tool, process, machine, data_mmap);
1406 /* command specified */
1407 return 0;
1408}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 58a6be1fc739..477133015440 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -4,6 +4,7 @@
4#include <sys/types.h> 4#include <sys/types.h>
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include "map.h" 6#include "map.h"
7#include "event.h"
7 8
8struct addr_location; 9struct addr_location;
9struct branch_stack; 10struct branch_stack;
@@ -40,13 +41,20 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
40 41
41struct thread *machine__find_thread(struct machine *machine, pid_t tid); 42struct thread *machine__find_thread(struct machine *machine, pid_t tid);
42 43
43int machine__process_comm_event(struct machine *machine, union perf_event *event); 44int machine__process_comm_event(struct machine *machine, union perf_event *event,
44int machine__process_exit_event(struct machine *machine, union perf_event *event); 45 struct perf_sample *sample);
45int machine__process_fork_event(struct machine *machine, union perf_event *event); 46int machine__process_exit_event(struct machine *machine, union perf_event *event,
46int machine__process_lost_event(struct machine *machine, union perf_event *event); 47 struct perf_sample *sample);
47int machine__process_mmap_event(struct machine *machine, union perf_event *event); 48int machine__process_fork_event(struct machine *machine, union perf_event *event,
48int machine__process_mmap2_event(struct machine *machine, union perf_event *event); 49 struct perf_sample *sample);
49int machine__process_event(struct machine *machine, union perf_event *event); 50int machine__process_lost_event(struct machine *machine, union perf_event *event,
51 struct perf_sample *sample);
52int machine__process_mmap_event(struct machine *machine, union perf_event *event,
53 struct perf_sample *sample);
54int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
55 struct perf_sample *sample);
56int machine__process_event(struct machine *machine, union perf_event *event,
57 struct perf_sample *sample);
50 58
51typedef void (*machine__process_t)(struct machine *machine, void *data); 59typedef void (*machine__process_t)(struct machine *machine, void *data);
52 60
@@ -74,6 +82,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
74void machines__set_symbol_filter(struct machines *machines, 82void machines__set_symbol_filter(struct machines *machines,
75 symbol_filter_t symbol_filter); 83 symbol_filter_t symbol_filter);
76 84
85struct machine *machine__new_host(void);
77int machine__init(struct machine *machine, const char *root_dir, pid_t pid); 86int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
78void machine__exit(struct machine *machine); 87void machine__exit(struct machine *machine);
79void machine__delete_dead_threads(struct machine *machine); 88void machine__delete_dead_threads(struct machine *machine);
@@ -91,7 +100,8 @@ int machine__resolve_callchain(struct machine *machine,
91 struct thread *thread, 100 struct thread *thread,
92 struct perf_sample *sample, 101 struct perf_sample *sample,
93 struct symbol **parent, 102 struct symbol **parent,
94 struct addr_location *root_al); 103 struct addr_location *root_al,
104 int max_stack);
95 105
96/* 106/*
97 * Default guest kernel is defined by parameter --guestkallsyms 107 * Default guest kernel is defined by parameter --guestkallsyms
@@ -165,4 +175,19 @@ void machines__destroy_kernel_maps(struct machines *machines);
165 175
166size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); 176size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
167 177
178int machine__for_each_thread(struct machine *machine,
179 int (*fn)(struct thread *thread, void *p),
180 void *priv);
181
182int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
183 struct target *target, struct thread_map *threads,
184 perf_event__handler_t process, bool data_mmap);
185static inline
186int machine__synthesize_threads(struct machine *machine, struct target *target,
187 struct thread_map *threads, bool data_mmap)
188{
189 return __machine__synthesize_threads(machine, NULL, target, threads,
190 perf_event__process, data_mmap);
191}
192
168#endif /* __PERF_MACHINE_H */ 193#endif /* __PERF_MACHINE_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 4f6680d2043b..ef5bc913ca7a 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -172,7 +172,7 @@ int map__load(struct map *map, symbol_filter_t filter)
172 pr_warning(", continuing without symbols\n"); 172 pr_warning(", continuing without symbols\n");
173 return -1; 173 return -1;
174 } else if (nr == 0) { 174 } else if (nr == 0) {
175#ifdef LIBELF_SUPPORT 175#ifdef HAVE_LIBELF_SUPPORT
176 const size_t len = strlen(name); 176 const size_t len = strlen(name);
177 const size_t real_len = len - sizeof(DSO__DELETED); 177 const size_t real_len = len - sizeof(DSO__DELETED);
178 178
@@ -252,10 +252,16 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
252 return fprintf(fp, "%s", dsoname); 252 return fprintf(fp, "%s", dsoname);
253} 253}
254 254
255/* 255/**
256 * map__rip_2objdump - convert symbol start address to objdump address.
257 * @map: memory map
258 * @rip: symbol start address
259 *
256 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 260 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
257 * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is 261 * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is
258 * relative to section start. 262 * relative to section start.
263 *
264 * Return: Address suitable for passing to "objdump --start-address="
259 */ 265 */
260u64 map__rip_2objdump(struct map *map, u64 rip) 266u64 map__rip_2objdump(struct map *map, u64 rip)
261{ 267{
@@ -268,6 +274,29 @@ u64 map__rip_2objdump(struct map *map, u64 rip)
268 return map->unmap_ip(map, rip); 274 return map->unmap_ip(map, rip);
269} 275}
270 276
277/**
278 * map__objdump_2mem - convert objdump address to a memory address.
279 * @map: memory map
280 * @ip: objdump address
281 *
282 * Closely related to map__rip_2objdump(), this function takes an address from
283 * objdump and converts it to a memory address. Note this assumes that @map
284 * contains the address. To be sure the result is valid, check it forwards
285 * e.g. map__rip_2objdump(map->map_ip(map, map__objdump_2mem(map, ip))) == ip
286 *
287 * Return: Memory address.
288 */
289u64 map__objdump_2mem(struct map *map, u64 ip)
290{
291 if (!map->dso->adjust_symbols)
292 return map->unmap_ip(map, ip);
293
294 if (map->dso->rel)
295 return map->unmap_ip(map, ip + map->pgoff);
296
297 return ip;
298}
299
271void map_groups__init(struct map_groups *mg) 300void map_groups__init(struct map_groups *mg)
272{ 301{
273 int i; 302 int i;
@@ -371,6 +400,23 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
371 return NULL; 400 return NULL;
372} 401}
373 402
403int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
404{
405 if (ams->addr < ams->map->start || ams->addr > ams->map->end) {
406 if (ams->map->groups == NULL)
407 return -1;
408 ams->map = map_groups__find(ams->map->groups, ams->map->type,
409 ams->addr);
410 if (ams->map == NULL)
411 return -1;
412 }
413
414 ams->al_addr = ams->map->map_ip(ams->map, ams->addr);
415 ams->sym = map__find_symbol(ams->map, ams->al_addr, filter);
416
417 return ams->sym ? 0 : -1;
418}
419
374size_t __map_groups__fprintf_maps(struct map_groups *mg, 420size_t __map_groups__fprintf_maps(struct map_groups *mg,
375 enum map_type type, int verbose, FILE *fp) 421 enum map_type type, int verbose, FILE *fp)
376{ 422{
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 4886ca280536..e4e259c3ba16 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -84,6 +84,9 @@ static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip)
84/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ 84/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
85u64 map__rip_2objdump(struct map *map, u64 rip); 85u64 map__rip_2objdump(struct map *map, u64 rip);
86 86
87/* objdump address -> memory address */
88u64 map__objdump_2mem(struct map *map, u64 ip);
89
87struct symbol; 90struct symbol;
88 91
89typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 92typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
@@ -167,6 +170,10 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
167 struct map **mapp, 170 struct map **mapp,
168 symbol_filter_t filter); 171 symbol_filter_t filter);
169 172
173struct addr_map_symbol;
174
175int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter);
176
170static inline 177static inline
171struct symbol *map_groups__find_function_by_name(struct map_groups *mg, 178struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
172 const char *name, struct map **mapp, 179 const char *name, struct map **mapp,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 98125319b158..6de6f89c2a61 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -277,7 +277,7 @@ static int __add_event(struct list_head *list, int *idx,
277 277
278 event_attr_init(attr); 278 event_attr_init(attr);
279 279
280 evsel = perf_evsel__new(attr, (*idx)++); 280 evsel = perf_evsel__new_idx(attr, (*idx)++);
281 if (!evsel) 281 if (!evsel)
282 return -ENOMEM; 282 return -ENOMEM;
283 283
@@ -378,7 +378,7 @@ static int add_tracepoint(struct list_head *list, int *idx,
378{ 378{
379 struct perf_evsel *evsel; 379 struct perf_evsel *evsel;
380 380
381 evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); 381 evsel = perf_evsel__newtp_idx(sys_name, evt_name, (*idx)++);
382 if (!evsel) 382 if (!evsel)
383 return -ENOMEM; 383 return -ENOMEM;
384 384
@@ -998,8 +998,10 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
998 char evt_path[MAXPATHLEN]; 998 char evt_path[MAXPATHLEN];
999 char dir_path[MAXPATHLEN]; 999 char dir_path[MAXPATHLEN];
1000 1000
1001 if (debugfs_valid_mountpoint(tracing_events_path)) 1001 if (debugfs_valid_mountpoint(tracing_events_path)) {
1002 printf(" [ Tracepoints not available: %s ]\n", strerror(errno));
1002 return; 1003 return;
1004 }
1003 1005
1004 sys_dir = opendir(tracing_events_path); 1006 sys_dir = opendir(tracing_events_path);
1005 if (!sys_dir) 1007 if (!sys_dir)
@@ -1095,7 +1097,7 @@ static bool is_event_supported(u8 type, unsigned config)
1095 .threads = { 0 }, 1097 .threads = { 0 },
1096 }; 1098 };
1097 1099
1098 evsel = perf_evsel__new(&attr, 0); 1100 evsel = perf_evsel__new(&attr);
1099 if (evsel) { 1101 if (evsel) {
1100 ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0; 1102 ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
1101 perf_evsel__delete(evsel); 1103 perf_evsel__delete(evsel);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 91346b753960..343299575b30 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -126,6 +126,37 @@ modifier_bp [rwx]{1,3}
126 126
127} 127}
128 128
129<config>{
130config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
131config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
132config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
133name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
134period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
135branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
136, { return ','; }
137"/" { BEGIN(INITIAL); return '/'; }
138{name_minus} { return str(yyscanner, PE_NAME); }
139}
140
141<mem>{
142{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
143: { return ':'; }
144{num_dec} { return value(yyscanner, 10); }
145{num_hex} { return value(yyscanner, 16); }
146 /*
147 * We need to separate 'mem:' scanner part, in order to get specific
148 * modifier bits parsed out. Otherwise we would need to handle PE_NAME
149 * and we'd need to parse it manually. During the escape from <mem>
150 * state we need to put the escaping char back, so we dont miss it.
151 */
152. { unput(*yytext); BEGIN(INITIAL); }
153 /*
154 * We destroy the scanner after reaching EOF,
155 * but anyway just to be sure get back to INIT state.
156 */
157<<EOF>> { BEGIN(INITIAL); }
158}
159
129cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } 160cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
130stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } 161stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
131stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } 162stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
@@ -162,18 +193,6 @@ speculative-read|speculative-load |
162refs|Reference|ops|access | 193refs|Reference|ops|access |
163misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); } 194misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); }
164 195
165<config>{
166config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
167config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
168config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
169name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
170period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
171branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
172, { return ','; }
173"/" { BEGIN(INITIAL); return '/'; }
174{name_minus} { return str(yyscanner, PE_NAME); }
175}
176
177mem: { BEGIN(mem); return PE_PREFIX_MEM; } 196mem: { BEGIN(mem); return PE_PREFIX_MEM; }
178r{num_raw_hex} { return raw(yyscanner); } 197r{num_raw_hex} { return raw(yyscanner); }
179{num_dec} { return value(yyscanner, 10); } 198{num_dec} { return value(yyscanner, 10); }
@@ -189,25 +208,7 @@ r{num_raw_hex} { return raw(yyscanner); }
189"}" { return '}'; } 208"}" { return '}'; }
190= { return '='; } 209= { return '='; }
191\n { } 210\n { }
192 211. { }
193<mem>{
194{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
195: { return ':'; }
196{num_dec} { return value(yyscanner, 10); }
197{num_hex} { return value(yyscanner, 16); }
198 /*
199 * We need to separate 'mem:' scanner part, in order to get specific
200 * modifier bits parsed out. Otherwise we would need to handle PE_NAME
201 * and we'd need to parse it manually. During the escape from <mem>
202 * state we need to put the escaping char back, so we dont miss it.
203 */
204. { unput(*yytext); BEGIN(INITIAL); }
205 /*
206 * We destroy the scanner after reaching EOF,
207 * but anyway just to be sure get back to INIT state.
208 */
209<<EOF>> { BEGIN(INITIAL); }
210}
211 212
212%% 213%%
213 214
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 2bc9e70df7e2..31f404a032a9 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -339,10 +339,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
339 if (arg[1] != '-') { 339 if (arg[1] != '-') {
340 ctx->opt = arg + 1; 340 ctx->opt = arg + 1;
341 if (internal_help && *ctx->opt == 'h') 341 if (internal_help && *ctx->opt == 'h')
342 return parse_options_usage(usagestr, options); 342 return usage_with_options_internal(usagestr, options, 0);
343 switch (parse_short_opt(ctx, options)) { 343 switch (parse_short_opt(ctx, options)) {
344 case -1: 344 case -1:
345 return parse_options_usage(usagestr, options); 345 return parse_options_usage(usagestr, options, arg + 1, 1);
346 case -2: 346 case -2:
347 goto unknown; 347 goto unknown;
348 default: 348 default:
@@ -352,10 +352,11 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
352 check_typos(arg + 1, options); 352 check_typos(arg + 1, options);
353 while (ctx->opt) { 353 while (ctx->opt) {
354 if (internal_help && *ctx->opt == 'h') 354 if (internal_help && *ctx->opt == 'h')
355 return parse_options_usage(usagestr, options); 355 return usage_with_options_internal(usagestr, options, 0);
356 arg = ctx->opt;
356 switch (parse_short_opt(ctx, options)) { 357 switch (parse_short_opt(ctx, options)) {
357 case -1: 358 case -1:
358 return parse_options_usage(usagestr, options); 359 return parse_options_usage(usagestr, options, arg, 1);
359 case -2: 360 case -2:
360 /* fake a short option thing to hide the fact that we may have 361 /* fake a short option thing to hide the fact that we may have
361 * started to parse aggregated stuff 362 * started to parse aggregated stuff
@@ -383,12 +384,12 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
383 if (internal_help && !strcmp(arg + 2, "help-all")) 384 if (internal_help && !strcmp(arg + 2, "help-all"))
384 return usage_with_options_internal(usagestr, options, 1); 385 return usage_with_options_internal(usagestr, options, 1);
385 if (internal_help && !strcmp(arg + 2, "help")) 386 if (internal_help && !strcmp(arg + 2, "help"))
386 return parse_options_usage(usagestr, options); 387 return usage_with_options_internal(usagestr, options, 0);
387 if (!strcmp(arg + 2, "list-opts")) 388 if (!strcmp(arg + 2, "list-opts"))
388 return PARSE_OPT_LIST; 389 return PARSE_OPT_LIST;
389 switch (parse_long_opt(ctx, arg + 2, options)) { 390 switch (parse_long_opt(ctx, arg + 2, options)) {
390 case -1: 391 case -1:
391 return parse_options_usage(usagestr, options); 392 return parse_options_usage(usagestr, options, arg + 2, 0);
392 case -2: 393 case -2:
393 goto unknown; 394 goto unknown;
394 default: 395 default:
@@ -445,6 +446,89 @@ int parse_options(int argc, const char **argv, const struct option *options,
445#define USAGE_OPTS_WIDTH 24 446#define USAGE_OPTS_WIDTH 24
446#define USAGE_GAP 2 447#define USAGE_GAP 2
447 448
449static void print_option_help(const struct option *opts, int full)
450{
451 size_t pos;
452 int pad;
453
454 if (opts->type == OPTION_GROUP) {
455 fputc('\n', stderr);
456 if (*opts->help)
457 fprintf(stderr, "%s\n", opts->help);
458 return;
459 }
460 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
461 return;
462
463 pos = fprintf(stderr, " ");
464 if (opts->short_name)
465 pos += fprintf(stderr, "-%c", opts->short_name);
466 else
467 pos += fprintf(stderr, " ");
468
469 if (opts->long_name && opts->short_name)
470 pos += fprintf(stderr, ", ");
471 if (opts->long_name)
472 pos += fprintf(stderr, "--%s", opts->long_name);
473
474 switch (opts->type) {
475 case OPTION_ARGUMENT:
476 break;
477 case OPTION_LONG:
478 case OPTION_U64:
479 case OPTION_INTEGER:
480 case OPTION_UINTEGER:
481 if (opts->flags & PARSE_OPT_OPTARG)
482 if (opts->long_name)
483 pos += fprintf(stderr, "[=<n>]");
484 else
485 pos += fprintf(stderr, "[<n>]");
486 else
487 pos += fprintf(stderr, " <n>");
488 break;
489 case OPTION_CALLBACK:
490 if (opts->flags & PARSE_OPT_NOARG)
491 break;
492 /* FALLTHROUGH */
493 case OPTION_STRING:
494 if (opts->argh) {
495 if (opts->flags & PARSE_OPT_OPTARG)
496 if (opts->long_name)
497 pos += fprintf(stderr, "[=<%s>]", opts->argh);
498 else
499 pos += fprintf(stderr, "[<%s>]", opts->argh);
500 else
501 pos += fprintf(stderr, " <%s>", opts->argh);
502 } else {
503 if (opts->flags & PARSE_OPT_OPTARG)
504 if (opts->long_name)
505 pos += fprintf(stderr, "[=...]");
506 else
507 pos += fprintf(stderr, "[...]");
508 else
509 pos += fprintf(stderr, " ...");
510 }
511 break;
512 default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
513 case OPTION_END:
514 case OPTION_GROUP:
515 case OPTION_BIT:
516 case OPTION_BOOLEAN:
517 case OPTION_INCR:
518 case OPTION_SET_UINT:
519 case OPTION_SET_PTR:
520 break;
521 }
522
523 if (pos <= USAGE_OPTS_WIDTH)
524 pad = USAGE_OPTS_WIDTH - pos;
525 else {
526 fputc('\n', stderr);
527 pad = USAGE_OPTS_WIDTH;
528 }
529 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
530}
531
448int usage_with_options_internal(const char * const *usagestr, 532int usage_with_options_internal(const char * const *usagestr,
449 const struct option *opts, int full) 533 const struct option *opts, int full)
450{ 534{
@@ -464,87 +548,9 @@ int usage_with_options_internal(const char * const *usagestr,
464 if (opts->type != OPTION_GROUP) 548 if (opts->type != OPTION_GROUP)
465 fputc('\n', stderr); 549 fputc('\n', stderr);
466 550
467 for (; opts->type != OPTION_END; opts++) { 551 for ( ; opts->type != OPTION_END; opts++)
468 size_t pos; 552 print_option_help(opts, full);
469 int pad;
470
471 if (opts->type == OPTION_GROUP) {
472 fputc('\n', stderr);
473 if (*opts->help)
474 fprintf(stderr, "%s\n", opts->help);
475 continue;
476 }
477 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
478 continue;
479
480 pos = fprintf(stderr, " ");
481 if (opts->short_name)
482 pos += fprintf(stderr, "-%c", opts->short_name);
483 else
484 pos += fprintf(stderr, " ");
485
486 if (opts->long_name && opts->short_name)
487 pos += fprintf(stderr, ", ");
488 if (opts->long_name)
489 pos += fprintf(stderr, "--%s", opts->long_name);
490
491 switch (opts->type) {
492 case OPTION_ARGUMENT:
493 break;
494 case OPTION_LONG:
495 case OPTION_U64:
496 case OPTION_INTEGER:
497 case OPTION_UINTEGER:
498 if (opts->flags & PARSE_OPT_OPTARG)
499 if (opts->long_name)
500 pos += fprintf(stderr, "[=<n>]");
501 else
502 pos += fprintf(stderr, "[<n>]");
503 else
504 pos += fprintf(stderr, " <n>");
505 break;
506 case OPTION_CALLBACK:
507 if (opts->flags & PARSE_OPT_NOARG)
508 break;
509 /* FALLTHROUGH */
510 case OPTION_STRING:
511 if (opts->argh) {
512 if (opts->flags & PARSE_OPT_OPTARG)
513 if (opts->long_name)
514 pos += fprintf(stderr, "[=<%s>]", opts->argh);
515 else
516 pos += fprintf(stderr, "[<%s>]", opts->argh);
517 else
518 pos += fprintf(stderr, " <%s>", opts->argh);
519 } else {
520 if (opts->flags & PARSE_OPT_OPTARG)
521 if (opts->long_name)
522 pos += fprintf(stderr, "[=...]");
523 else
524 pos += fprintf(stderr, "[...]");
525 else
526 pos += fprintf(stderr, " ...");
527 }
528 break;
529 default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
530 case OPTION_END:
531 case OPTION_GROUP:
532 case OPTION_BIT:
533 case OPTION_BOOLEAN:
534 case OPTION_INCR:
535 case OPTION_SET_UINT:
536 case OPTION_SET_PTR:
537 break;
538 }
539 553
540 if (pos <= USAGE_OPTS_WIDTH)
541 pad = USAGE_OPTS_WIDTH - pos;
542 else {
543 fputc('\n', stderr);
544 pad = USAGE_OPTS_WIDTH;
545 }
546 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
547 }
548 fputc('\n', stderr); 554 fputc('\n', stderr);
549 555
550 return PARSE_OPT_HELP; 556 return PARSE_OPT_HELP;
@@ -559,9 +565,45 @@ void usage_with_options(const char * const *usagestr,
559} 565}
560 566
561int parse_options_usage(const char * const *usagestr, 567int parse_options_usage(const char * const *usagestr,
562 const struct option *opts) 568 const struct option *opts,
569 const char *optstr, bool short_opt)
563{ 570{
564 return usage_with_options_internal(usagestr, opts, 0); 571 if (!usagestr)
572 goto opt;
573
574 fprintf(stderr, "\n usage: %s\n", *usagestr++);
575 while (*usagestr && **usagestr)
576 fprintf(stderr, " or: %s\n", *usagestr++);
577 while (*usagestr) {
578 fprintf(stderr, "%s%s\n",
579 **usagestr ? " " : "",
580 *usagestr);
581 usagestr++;
582 }
583 fputc('\n', stderr);
584
585opt:
586 for ( ; opts->type != OPTION_END; opts++) {
587 if (short_opt) {
588 if (opts->short_name == *optstr)
589 break;
590 continue;
591 }
592
593 if (opts->long_name == NULL)
594 continue;
595
596 if (!prefixcmp(optstr, opts->long_name))
597 break;
598 if (!prefixcmp(optstr, "no-") &&
599 !prefixcmp(optstr + 3, opts->long_name))
600 break;
601 }
602
603 if (opts->type != OPTION_END)
604 print_option_help(opts, 0);
605
606 return PARSE_OPT_HELP;
565} 607}
566 608
567 609
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 7bb5999940ca..b0241e28eaf7 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -158,7 +158,9 @@ struct parse_opt_ctx_t {
158}; 158};
159 159
160extern int parse_options_usage(const char * const *usagestr, 160extern int parse_options_usage(const char * const *usagestr,
161 const struct option *opts); 161 const struct option *opts,
162 const char *optstr,
163 bool short_opt);
162 164
163extern void parse_options_start(struct parse_opt_ctx_t *ctx, 165extern void parse_options_start(struct parse_opt_ctx_t *ctx,
164 int argc, const char **argv, int flags); 166 int argc, const char **argv, int flags);
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index a8c49548ca48..5d13cb45b317 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -22,19 +22,23 @@ static const char *get_perf_dir(void)
22 return "."; 22 return ".";
23} 23}
24 24
25#ifndef HAVE_STRLCPY 25/*
26size_t strlcpy(char *dest, const char *src, size_t size) 26 * If libc has strlcpy() then that version will override this
27 * implementation:
28 */
29size_t __weak strlcpy(char *dest, const char *src, size_t size)
27{ 30{
28 size_t ret = strlen(src); 31 size_t ret = strlen(src);
29 32
30 if (size) { 33 if (size) {
31 size_t len = (ret >= size) ? size - 1 : ret; 34 size_t len = (ret >= size) ? size - 1 : ret;
35
32 memcpy(dest, src, len); 36 memcpy(dest, src, len);
33 dest[len] = '\0'; 37 dest[len] = '\0';
34 } 38 }
39
35 return ret; 40 return ret;
36} 41}
37#endif
38 42
39static char *get_pathname(void) 43static char *get_pathname(void)
40{ 44{
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index 5a4f2b6f3738..a3d42cd74919 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_REGS_H 1#ifndef __PERF_REGS_H
2#define __PERF_REGS_H 2#define __PERF_REGS_H
3 3
4#ifdef HAVE_PERF_REGS 4#ifdef HAVE_PERF_REGS_SUPPORT
5#include <perf_regs.h> 5#include <perf_regs.h>
6#else 6#else
7#define PERF_REGS_MASK 0 7#define PERF_REGS_MASK 0
@@ -10,5 +10,5 @@ static inline const char *perf_reg_name(int id __maybe_unused)
10{ 10{
11 return NULL; 11 return NULL;
12} 12}
13#endif /* HAVE_PERF_REGS */ 13#endif /* HAVE_PERF_REGS_SUPPORT */
14#endif /* __PERF_REGS_H */ 14#endif /* __PERF_REGS_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index bc9d8069d376..c232d8dd410b 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -4,7 +4,7 @@
4#include <unistd.h> 4#include <unistd.h>
5#include <stdio.h> 5#include <stdio.h>
6#include <dirent.h> 6#include <dirent.h>
7#include "sysfs.h" 7#include "fs.h"
8#include "util.h" 8#include "util.h"
9#include "pmu.h" 9#include "pmu.h"
10#include "parse-events.h" 10#include "parse-events.h"
@@ -77,9 +77,8 @@ static int pmu_format(const char *name, struct list_head *format)
77{ 77{
78 struct stat st; 78 struct stat st;
79 char path[PATH_MAX]; 79 char path[PATH_MAX];
80 const char *sysfs; 80 const char *sysfs = sysfs__mountpoint();
81 81
82 sysfs = sysfs_find_mountpoint();
83 if (!sysfs) 82 if (!sysfs)
84 return -1; 83 return -1;
85 84
@@ -166,9 +165,8 @@ static int pmu_aliases(const char *name, struct list_head *head)
166{ 165{
167 struct stat st; 166 struct stat st;
168 char path[PATH_MAX]; 167 char path[PATH_MAX];
169 const char *sysfs; 168 const char *sysfs = sysfs__mountpoint();
170 169
171 sysfs = sysfs_find_mountpoint();
172 if (!sysfs) 170 if (!sysfs)
173 return -1; 171 return -1;
174 172
@@ -212,11 +210,10 @@ static int pmu_type(const char *name, __u32 *type)
212{ 210{
213 struct stat st; 211 struct stat st;
214 char path[PATH_MAX]; 212 char path[PATH_MAX];
215 const char *sysfs;
216 FILE *file; 213 FILE *file;
217 int ret = 0; 214 int ret = 0;
215 const char *sysfs = sysfs__mountpoint();
218 216
219 sysfs = sysfs_find_mountpoint();
220 if (!sysfs) 217 if (!sysfs)
221 return -1; 218 return -1;
222 219
@@ -241,11 +238,10 @@ static int pmu_type(const char *name, __u32 *type)
241static void pmu_read_sysfs(void) 238static void pmu_read_sysfs(void)
242{ 239{
243 char path[PATH_MAX]; 240 char path[PATH_MAX];
244 const char *sysfs;
245 DIR *dir; 241 DIR *dir;
246 struct dirent *dent; 242 struct dirent *dent;
243 const char *sysfs = sysfs__mountpoint();
247 244
248 sysfs = sysfs_find_mountpoint();
249 if (!sysfs) 245 if (!sysfs)
250 return; 246 return;
251 247
@@ -270,11 +266,10 @@ static struct cpu_map *pmu_cpumask(const char *name)
270{ 266{
271 struct stat st; 267 struct stat st;
272 char path[PATH_MAX]; 268 char path[PATH_MAX];
273 const char *sysfs;
274 FILE *file; 269 FILE *file;
275 struct cpu_map *cpus; 270 struct cpu_map *cpus;
271 const char *sysfs = sysfs__mountpoint();
276 272
277 sysfs = sysfs_find_mountpoint();
278 if (!sysfs) 273 if (!sysfs)
279 return NULL; 274 return NULL;
280 275
@@ -637,3 +632,19 @@ void print_pmu_events(const char *event_glob, bool name_only)
637 printf("\n"); 632 printf("\n");
638 free(aliases); 633 free(aliases);
639} 634}
635
636bool pmu_have_event(const char *pname, const char *name)
637{
638 struct perf_pmu *pmu;
639 struct perf_pmu_alias *alias;
640
641 pmu = NULL;
642 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
643 if (strcmp(pname, pmu->name))
644 continue;
645 list_for_each_entry(alias, &pmu->aliases, list)
646 if (!strcmp(alias->name, name))
647 return true;
648 }
649 return false;
650}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 6b2cbe2d4cc3..1179b26f244a 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -42,6 +42,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
42struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 42struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
43 43
44void print_pmu_events(const char *event_glob, bool name_only); 44void print_pmu_events(const char *event_glob, bool name_only);
45bool pmu_have_event(const char *pname, const char *name);
45 46
46int perf_pmu__test(void); 47int perf_pmu__test(void);
47#endif /* __PMU_H */ 48#endif /* __PMU_H */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index aa04bf9c9ad7..9c6989ca2bea 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -47,7 +47,6 @@
47#include "session.h" 47#include "session.h"
48 48
49#define MAX_CMDLEN 256 49#define MAX_CMDLEN 256
50#define MAX_PROBE_ARGS 128
51#define PERFPROBE_GROUP "probe" 50#define PERFPROBE_GROUP "probe"
52 51
53bool probe_event_dry_run; /* Dry run flag */ 52bool probe_event_dry_run; /* Dry run flag */
@@ -201,7 +200,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp,
201 return 0; 200 return 0;
202} 201}
203 202
204#ifdef DWARF_SUPPORT 203#ifdef HAVE_DWARF_SUPPORT
205/* Open new debuginfo of given module */ 204/* Open new debuginfo of given module */
206static struct debuginfo *open_debuginfo(const char *module) 205static struct debuginfo *open_debuginfo(const char *module)
207{ 206{
@@ -630,7 +629,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
630 return ret; 629 return ret;
631} 630}
632 631
633#else /* !DWARF_SUPPORT */ 632#else /* !HAVE_DWARF_SUPPORT */
634 633
635static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 634static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
636 struct perf_probe_point *pp) 635 struct perf_probe_point *pp)
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c09e0a9fdf4c..ffb657ffd327 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -115,7 +115,7 @@ static const Dwfl_Callbacks offline_callbacks = {
115}; 115};
116 116
117/* Get a Dwarf from offline image */ 117/* Get a Dwarf from offline image */
118static int debuginfo__init_offline_dwarf(struct debuginfo *self, 118static int debuginfo__init_offline_dwarf(struct debuginfo *dbg,
119 const char *path) 119 const char *path)
120{ 120{
121 int fd; 121 int fd;
@@ -124,25 +124,25 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *self,
124 if (fd < 0) 124 if (fd < 0)
125 return fd; 125 return fd;
126 126
127 self->dwfl = dwfl_begin(&offline_callbacks); 127 dbg->dwfl = dwfl_begin(&offline_callbacks);
128 if (!self->dwfl) 128 if (!dbg->dwfl)
129 goto error; 129 goto error;
130 130
131 self->mod = dwfl_report_offline(self->dwfl, "", "", fd); 131 dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd);
132 if (!self->mod) 132 if (!dbg->mod)
133 goto error; 133 goto error;
134 134
135 self->dbg = dwfl_module_getdwarf(self->mod, &self->bias); 135 dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias);
136 if (!self->dbg) 136 if (!dbg->dbg)
137 goto error; 137 goto error;
138 138
139 return 0; 139 return 0;
140error: 140error:
141 if (self->dwfl) 141 if (dbg->dwfl)
142 dwfl_end(self->dwfl); 142 dwfl_end(dbg->dwfl);
143 else 143 else
144 close(fd); 144 close(fd);
145 memset(self, 0, sizeof(*self)); 145 memset(dbg, 0, sizeof(*dbg));
146 146
147 return -ENOENT; 147 return -ENOENT;
148} 148}
@@ -180,24 +180,24 @@ static const Dwfl_Callbacks kernel_callbacks = {
180}; 180};
181 181
182/* Get a Dwarf from live kernel image */ 182/* Get a Dwarf from live kernel image */
183static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, 183static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
184 Dwarf_Addr addr) 184 Dwarf_Addr addr)
185{ 185{
186 self->dwfl = dwfl_begin(&kernel_callbacks); 186 dbg->dwfl = dwfl_begin(&kernel_callbacks);
187 if (!self->dwfl) 187 if (!dbg->dwfl)
188 return -EINVAL; 188 return -EINVAL;
189 189
190 /* Load the kernel dwarves: Don't care the result here */ 190 /* Load the kernel dwarves: Don't care the result here */
191 dwfl_linux_kernel_report_kernel(self->dwfl); 191 dwfl_linux_kernel_report_kernel(dbg->dwfl);
192 dwfl_linux_kernel_report_modules(self->dwfl); 192 dwfl_linux_kernel_report_modules(dbg->dwfl);
193 193
194 self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); 194 dbg->dbg = dwfl_addrdwarf(dbg->dwfl, addr, &dbg->bias);
195 /* Here, check whether we could get a real dwarf */ 195 /* Here, check whether we could get a real dwarf */
196 if (!self->dbg) { 196 if (!dbg->dbg) {
197 pr_debug("Failed to find kernel dwarf at %lx\n", 197 pr_debug("Failed to find kernel dwarf at %lx\n",
198 (unsigned long)addr); 198 (unsigned long)addr);
199 dwfl_end(self->dwfl); 199 dwfl_end(dbg->dwfl);
200 memset(self, 0, sizeof(*self)); 200 memset(dbg, 0, sizeof(*dbg));
201 return -ENOENT; 201 return -ENOENT;
202 } 202 }
203 203
@@ -205,7 +205,7 @@ static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
205} 205}
206#else 206#else
207/* With older elfutils, this just support kernel module... */ 207/* With older elfutils, this just support kernel module... */
208static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, 208static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
209 Dwarf_Addr addr __maybe_unused) 209 Dwarf_Addr addr __maybe_unused)
210{ 210{
211 const char *path = kernel_get_module_path("kernel"); 211 const char *path = kernel_get_module_path("kernel");
@@ -216,44 +216,45 @@ static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
216 } 216 }
217 217
218 pr_debug2("Use file %s for debuginfo\n", path); 218 pr_debug2("Use file %s for debuginfo\n", path);
219 return debuginfo__init_offline_dwarf(self, path); 219 return debuginfo__init_offline_dwarf(dbg, path);
220} 220}
221#endif 221#endif
222 222
223struct debuginfo *debuginfo__new(const char *path) 223struct debuginfo *debuginfo__new(const char *path)
224{ 224{
225 struct debuginfo *self = zalloc(sizeof(struct debuginfo)); 225 struct debuginfo *dbg = zalloc(sizeof(*dbg));
226 if (!self) 226 if (!dbg)
227 return NULL; 227 return NULL;
228 228
229 if (debuginfo__init_offline_dwarf(self, path) < 0) { 229 if (debuginfo__init_offline_dwarf(dbg, path) < 0) {
230 free(self); 230 free(dbg);
231 self = NULL; 231 dbg = NULL;
232 } 232 }
233 233
234 return self; 234 return dbg;
235} 235}
236 236
237struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) 237struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
238{ 238{
239 struct debuginfo *self = zalloc(sizeof(struct debuginfo)); 239 struct debuginfo *dbg = zalloc(sizeof(*dbg));
240 if (!self) 240
241 if (!dbg)
241 return NULL; 242 return NULL;
242 243
243 if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) { 244 if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) {
244 free(self); 245 free(dbg);
245 self = NULL; 246 dbg = NULL;
246 } 247 }
247 248
248 return self; 249 return dbg;
249} 250}
250 251
251void debuginfo__delete(struct debuginfo *self) 252void debuginfo__delete(struct debuginfo *dbg)
252{ 253{
253 if (self) { 254 if (dbg) {
254 if (self->dwfl) 255 if (dbg->dwfl)
255 dwfl_end(self->dwfl); 256 dwfl_end(dbg->dwfl);
256 free(self); 257 free(dbg);
257 } 258 }
258} 259}
259 260
@@ -273,12 +274,15 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
273/* 274/*
274 * Convert a location into trace_arg. 275 * Convert a location into trace_arg.
275 * If tvar == NULL, this just checks variable can be converted. 276 * If tvar == NULL, this just checks variable can be converted.
277 * If fentry == true and vr_die is a parameter, do huristic search
278 * for the location fuzzed by function entry mcount.
276 */ 279 */
277static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 280static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
278 Dwarf_Op *fb_ops, 281 Dwarf_Op *fb_ops, Dwarf_Die *sp_die,
279 struct probe_trace_arg *tvar) 282 struct probe_trace_arg *tvar)
280{ 283{
281 Dwarf_Attribute attr; 284 Dwarf_Attribute attr;
285 Dwarf_Addr tmp = 0;
282 Dwarf_Op *op; 286 Dwarf_Op *op;
283 size_t nops; 287 size_t nops;
284 unsigned int regn; 288 unsigned int regn;
@@ -291,12 +295,29 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
291 goto static_var; 295 goto static_var;
292 296
293 /* TODO: handle more than 1 exprs */ 297 /* TODO: handle more than 1 exprs */
294 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || 298 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
295 dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || 299 return -EINVAL; /* Broken DIE ? */
296 nops == 0) { 300 if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) {
297 /* TODO: Support const_value */ 301 ret = dwarf_entrypc(sp_die, &tmp);
302 if (ret || addr != tmp ||
303 dwarf_tag(vr_die) != DW_TAG_formal_parameter ||
304 dwarf_highpc(sp_die, &tmp))
305 return -ENOENT;
306 /*
307 * This is fuzzed by fentry mcount. We try to find the
308 * parameter location at the earliest address.
309 */
310 for (addr += 1; addr <= tmp; addr++) {
311 if (dwarf_getlocation_addr(&attr, addr, &op,
312 &nops, 1) > 0)
313 goto found;
314 }
298 return -ENOENT; 315 return -ENOENT;
299 } 316 }
317found:
318 if (nops == 0)
319 /* TODO: Support const_value */
320 return -ENOENT;
300 321
301 if (op->atom == DW_OP_addr) { 322 if (op->atom == DW_OP_addr) {
302static_var: 323static_var:
@@ -563,7 +584,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
563 } 584 }
564 585
565 if (die_find_member(&type, field->name, die_mem) == NULL) { 586 if (die_find_member(&type, field->name, die_mem) == NULL) {
566 pr_warning("%s(tyep:%s) has no member %s.\n", varname, 587 pr_warning("%s(type:%s) has no member %s.\n", varname,
567 dwarf_diename(&type), field->name); 588 dwarf_diename(&type), field->name);
568 return -EINVAL; 589 return -EINVAL;
569 } 590 }
@@ -600,7 +621,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
600 dwarf_diename(vr_die)); 621 dwarf_diename(vr_die));
601 622
602 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 623 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
603 pf->tvar); 624 &pf->sp_die, pf->tvar);
604 if (ret == -ENOENT) 625 if (ret == -ENOENT)
605 pr_err("Failed to find the location of %s at this address.\n" 626 pr_err("Failed to find the location of %s at this address.\n"
606 " Perhaps, it has been optimized out.\n", pf->pvar->var); 627 " Perhaps, it has been optimized out.\n", pf->pvar->var);
@@ -1063,7 +1084,7 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
1063} 1084}
1064 1085
1065/* Find probe points from debuginfo */ 1086/* Find probe points from debuginfo */
1066static int debuginfo__find_probes(struct debuginfo *self, 1087static int debuginfo__find_probes(struct debuginfo *dbg,
1067 struct probe_finder *pf) 1088 struct probe_finder *pf)
1068{ 1089{
1069 struct perf_probe_point *pp = &pf->pev->point; 1090 struct perf_probe_point *pp = &pf->pev->point;
@@ -1074,7 +1095,7 @@ static int debuginfo__find_probes(struct debuginfo *self,
1074 1095
1075#if _ELFUTILS_PREREQ(0, 142) 1096#if _ELFUTILS_PREREQ(0, 142)
1076 /* Get the call frame information from this dwarf */ 1097 /* Get the call frame information from this dwarf */
1077 pf->cfi = dwarf_getcfi(self->dbg); 1098 pf->cfi = dwarf_getcfi(dbg->dbg);
1078#endif 1099#endif
1079 1100
1080 off = 0; 1101 off = 0;
@@ -1093,7 +1114,7 @@ static int debuginfo__find_probes(struct debuginfo *self,
1093 .data = pf, 1114 .data = pf,
1094 }; 1115 };
1095 1116
1096 dwarf_getpubnames(self->dbg, pubname_search_cb, 1117 dwarf_getpubnames(dbg->dbg, pubname_search_cb,
1097 &pubname_param, 0); 1118 &pubname_param, 0);
1098 if (pubname_param.found) { 1119 if (pubname_param.found) {
1099 ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1120 ret = probe_point_search_cb(&pf->sp_die, &probe_param);
@@ -1103,9 +1124,9 @@ static int debuginfo__find_probes(struct debuginfo *self,
1103 } 1124 }
1104 1125
1105 /* Loop on CUs (Compilation Unit) */ 1126 /* Loop on CUs (Compilation Unit) */
1106 while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 1127 while (!dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
1107 /* Get the DIE(Debugging Information Entry) of this CU */ 1128 /* Get the DIE(Debugging Information Entry) of this CU */
1108 diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die); 1129 diep = dwarf_offdie(dbg->dbg, off + cuhl, &pf->cu_die);
1109 if (!diep) 1130 if (!diep)
1110 continue; 1131 continue;
1111 1132
@@ -1136,12 +1157,80 @@ found:
1136 return ret; 1157 return ret;
1137} 1158}
1138 1159
1160struct local_vars_finder {
1161 struct probe_finder *pf;
1162 struct perf_probe_arg *args;
1163 int max_args;
1164 int nargs;
1165 int ret;
1166};
1167
1168/* Collect available variables in this scope */
1169static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
1170{
1171 struct local_vars_finder *vf = data;
1172 struct probe_finder *pf = vf->pf;
1173 int tag;
1174
1175 tag = dwarf_tag(die_mem);
1176 if (tag == DW_TAG_formal_parameter ||
1177 tag == DW_TAG_variable) {
1178 if (convert_variable_location(die_mem, vf->pf->addr,
1179 vf->pf->fb_ops, &pf->sp_die,
1180 NULL) == 0) {
1181 vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem);
1182 if (vf->args[vf->nargs].var == NULL) {
1183 vf->ret = -ENOMEM;
1184 return DIE_FIND_CB_END;
1185 }
1186 pr_debug(" %s", vf->args[vf->nargs].var);
1187 vf->nargs++;
1188 }
1189 }
1190
1191 if (dwarf_haspc(die_mem, vf->pf->addr))
1192 return DIE_FIND_CB_CONTINUE;
1193 else
1194 return DIE_FIND_CB_SIBLING;
1195}
1196
1197static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf,
1198 struct perf_probe_arg *args)
1199{
1200 Dwarf_Die die_mem;
1201 int i;
1202 int n = 0;
1203 struct local_vars_finder vf = {.pf = pf, .args = args,
1204 .max_args = MAX_PROBE_ARGS, .ret = 0};
1205
1206 for (i = 0; i < pf->pev->nargs; i++) {
1207 /* var never be NULL */
1208 if (strcmp(pf->pev->args[i].var, "$vars") == 0) {
1209 pr_debug("Expanding $vars into:");
1210 vf.nargs = n;
1211 /* Special local variables */
1212 die_find_child(sc_die, copy_variables_cb, (void *)&vf,
1213 &die_mem);
1214 pr_debug(" (%d)\n", vf.nargs - n);
1215 if (vf.ret < 0)
1216 return vf.ret;
1217 n = vf.nargs;
1218 } else {
1219 /* Copy normal argument */
1220 args[n] = pf->pev->args[i];
1221 n++;
1222 }
1223 }
1224 return n;
1225}
1226
1139/* Add a found probe point into trace event list */ 1227/* Add a found probe point into trace event list */
1140static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 1228static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1141{ 1229{
1142 struct trace_event_finder *tf = 1230 struct trace_event_finder *tf =
1143 container_of(pf, struct trace_event_finder, pf); 1231 container_of(pf, struct trace_event_finder, pf);
1144 struct probe_trace_event *tev; 1232 struct probe_trace_event *tev;
1233 struct perf_probe_arg *args;
1145 int ret, i; 1234 int ret, i;
1146 1235
1147 /* Check number of tevs */ 1236 /* Check number of tevs */
@@ -1161,31 +1250,45 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1161 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1250 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1162 tev->point.offset); 1251 tev->point.offset);
1163 1252
1164 /* Find each argument */ 1253 /* Expand special probe argument if exist */
1165 tev->nargs = pf->pev->nargs; 1254 args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
1166 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1255 if (args == NULL)
1167 if (tev->args == NULL)
1168 return -ENOMEM; 1256 return -ENOMEM;
1169 for (i = 0; i < pf->pev->nargs; i++) { 1257
1170 pf->pvar = &pf->pev->args[i]; 1258 ret = expand_probe_args(sc_die, pf, args);
1259 if (ret < 0)
1260 goto end;
1261
1262 tev->nargs = ret;
1263 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1264 if (tev->args == NULL) {
1265 ret = -ENOMEM;
1266 goto end;
1267 }
1268
1269 /* Find each argument */
1270 for (i = 0; i < tev->nargs; i++) {
1271 pf->pvar = &args[i];
1171 pf->tvar = &tev->args[i]; 1272 pf->tvar = &tev->args[i];
1172 /* Variable should be found from scope DIE */ 1273 /* Variable should be found from scope DIE */
1173 ret = find_variable(sc_die, pf); 1274 ret = find_variable(sc_die, pf);
1174 if (ret != 0) 1275 if (ret != 0)
1175 return ret; 1276 break;
1176 } 1277 }
1177 1278
1178 return 0; 1279end:
1280 free(args);
1281 return ret;
1179} 1282}
1180 1283
1181/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1284/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1182int debuginfo__find_trace_events(struct debuginfo *self, 1285int debuginfo__find_trace_events(struct debuginfo *dbg,
1183 struct perf_probe_event *pev, 1286 struct perf_probe_event *pev,
1184 struct probe_trace_event **tevs, int max_tevs) 1287 struct probe_trace_event **tevs, int max_tevs)
1185{ 1288{
1186 struct trace_event_finder tf = { 1289 struct trace_event_finder tf = {
1187 .pf = {.pev = pev, .callback = add_probe_trace_event}, 1290 .pf = {.pev = pev, .callback = add_probe_trace_event},
1188 .mod = self->mod, .max_tevs = max_tevs}; 1291 .mod = dbg->mod, .max_tevs = max_tevs};
1189 int ret; 1292 int ret;
1190 1293
1191 /* Allocate result tevs array */ 1294 /* Allocate result tevs array */
@@ -1196,7 +1299,7 @@ int debuginfo__find_trace_events(struct debuginfo *self,
1196 tf.tevs = *tevs; 1299 tf.tevs = *tevs;
1197 tf.ntevs = 0; 1300 tf.ntevs = 0;
1198 1301
1199 ret = debuginfo__find_probes(self, &tf.pf); 1302 ret = debuginfo__find_probes(dbg, &tf.pf);
1200 if (ret < 0) { 1303 if (ret < 0) {
1201 free(*tevs); 1304 free(*tevs);
1202 *tevs = NULL; 1305 *tevs = NULL;
@@ -1222,7 +1325,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1222 if (tag == DW_TAG_formal_parameter || 1325 if (tag == DW_TAG_formal_parameter ||
1223 tag == DW_TAG_variable) { 1326 tag == DW_TAG_variable) {
1224 ret = convert_variable_location(die_mem, af->pf.addr, 1327 ret = convert_variable_location(die_mem, af->pf.addr,
1225 af->pf.fb_ops, NULL); 1328 af->pf.fb_ops, &af->pf.sp_die,
1329 NULL);
1226 if (ret == 0) { 1330 if (ret == 0) {
1227 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); 1331 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
1228 pr_debug2("Add new var: %s\n", buf); 1332 pr_debug2("Add new var: %s\n", buf);
@@ -1286,14 +1390,14 @@ out:
1286} 1390}
1287 1391
1288/* Find available variables at given probe point */ 1392/* Find available variables at given probe point */
1289int debuginfo__find_available_vars_at(struct debuginfo *self, 1393int debuginfo__find_available_vars_at(struct debuginfo *dbg,
1290 struct perf_probe_event *pev, 1394 struct perf_probe_event *pev,
1291 struct variable_list **vls, 1395 struct variable_list **vls,
1292 int max_vls, bool externs) 1396 int max_vls, bool externs)
1293{ 1397{
1294 struct available_var_finder af = { 1398 struct available_var_finder af = {
1295 .pf = {.pev = pev, .callback = add_available_vars}, 1399 .pf = {.pev = pev, .callback = add_available_vars},
1296 .mod = self->mod, 1400 .mod = dbg->mod,
1297 .max_vls = max_vls, .externs = externs}; 1401 .max_vls = max_vls, .externs = externs};
1298 int ret; 1402 int ret;
1299 1403
@@ -1305,7 +1409,7 @@ int debuginfo__find_available_vars_at(struct debuginfo *self,
1305 af.vls = *vls; 1409 af.vls = *vls;
1306 af.nvls = 0; 1410 af.nvls = 0;
1307 1411
1308 ret = debuginfo__find_probes(self, &af.pf); 1412 ret = debuginfo__find_probes(dbg, &af.pf);
1309 if (ret < 0) { 1413 if (ret < 0) {
1310 /* Free vlist for error */ 1414 /* Free vlist for error */
1311 while (af.nvls--) { 1415 while (af.nvls--) {
@@ -1323,7 +1427,7 @@ int debuginfo__find_available_vars_at(struct debuginfo *self,
1323} 1427}
1324 1428
1325/* Reverse search */ 1429/* Reverse search */
1326int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, 1430int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
1327 struct perf_probe_point *ppt) 1431 struct perf_probe_point *ppt)
1328{ 1432{
1329 Dwarf_Die cudie, spdie, indie; 1433 Dwarf_Die cudie, spdie, indie;
@@ -1332,10 +1436,10 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
1332 int baseline = 0, lineno = 0, ret = 0; 1436 int baseline = 0, lineno = 0, ret = 0;
1333 1437
1334 /* Adjust address with bias */ 1438 /* Adjust address with bias */
1335 addr += self->bias; 1439 addr += dbg->bias;
1336 1440
1337 /* Find cu die */ 1441 /* Find cu die */
1338 if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) { 1442 if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr - dbg->bias, &cudie)) {
1339 pr_warning("Failed to find debug information for address %lx\n", 1443 pr_warning("Failed to find debug information for address %lx\n",
1340 addr); 1444 addr);
1341 ret = -EINVAL; 1445 ret = -EINVAL;
@@ -1357,10 +1461,10 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
1357 goto post; 1461 goto post;
1358 } 1462 }
1359 1463
1464 fname = dwarf_decl_file(&spdie);
1360 if (addr == (unsigned long)baseaddr) { 1465 if (addr == (unsigned long)baseaddr) {
1361 /* Function entry - Relative line number is 0 */ 1466 /* Function entry - Relative line number is 0 */
1362 lineno = baseline; 1467 lineno = baseline;
1363 fname = dwarf_decl_file(&spdie);
1364 goto post; 1468 goto post;
1365 } 1469 }
1366 1470
@@ -1536,7 +1640,7 @@ static int find_line_range_by_func(struct line_finder *lf)
1536 return param.retval; 1640 return param.retval;
1537} 1641}
1538 1642
1539int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr) 1643int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr)
1540{ 1644{
1541 struct line_finder lf = {.lr = lr, .found = 0}; 1645 struct line_finder lf = {.lr = lr, .found = 0};
1542 int ret = 0; 1646 int ret = 0;
@@ -1553,7 +1657,7 @@ int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr)
1553 struct dwarf_callback_param line_range_param = { 1657 struct dwarf_callback_param line_range_param = {
1554 .data = (void *)&lf, .retval = 0}; 1658 .data = (void *)&lf, .retval = 0};
1555 1659
1556 dwarf_getpubnames(self->dbg, pubname_search_cb, 1660 dwarf_getpubnames(dbg->dbg, pubname_search_cb,
1557 &pubname_param, 0); 1661 &pubname_param, 0);
1558 if (pubname_param.found) { 1662 if (pubname_param.found) {
1559 line_range_search_cb(&lf.sp_die, &line_range_param); 1663 line_range_search_cb(&lf.sp_die, &line_range_param);
@@ -1564,12 +1668,12 @@ int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr)
1564 1668
1565 /* Loop on CUs (Compilation Unit) */ 1669 /* Loop on CUs (Compilation Unit) */
1566 while (!lf.found && ret >= 0) { 1670 while (!lf.found && ret >= 0) {
1567 if (dwarf_nextcu(self->dbg, off, &noff, &cuhl, 1671 if (dwarf_nextcu(dbg->dbg, off, &noff, &cuhl,
1568 NULL, NULL, NULL) != 0) 1672 NULL, NULL, NULL) != 0)
1569 break; 1673 break;
1570 1674
1571 /* Get the DIE(Debugging Information Entry) of this CU */ 1675 /* Get the DIE(Debugging Information Entry) of this CU */
1572 diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die); 1676 diep = dwarf_offdie(dbg->dbg, off + cuhl, &lf.cu_die);
1573 if (!diep) 1677 if (!diep)
1574 continue; 1678 continue;
1575 1679
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 3b7d63018960..ffc33cdd25cc 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -7,6 +7,7 @@
7 7
8#define MAX_PROBE_BUFFER 1024 8#define MAX_PROBE_BUFFER 1024
9#define MAX_PROBES 128 9#define MAX_PROBES 128
10#define MAX_PROBE_ARGS 128
10 11
11static inline int is_c_varname(const char *name) 12static inline int is_c_varname(const char *name)
12{ 13{
@@ -14,7 +15,7 @@ static inline int is_c_varname(const char *name)
14 return isalpha(name[0]) || name[0] == '_'; 15 return isalpha(name[0]) || name[0] == '_';
15} 16}
16 17
17#ifdef DWARF_SUPPORT 18#ifdef HAVE_DWARF_SUPPORT
18 19
19#include "dwarf-aux.h" 20#include "dwarf-aux.h"
20 21
@@ -30,25 +31,25 @@ struct debuginfo {
30 31
31extern struct debuginfo *debuginfo__new(const char *path); 32extern struct debuginfo *debuginfo__new(const char *path);
32extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr); 33extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr);
33extern void debuginfo__delete(struct debuginfo *self); 34extern void debuginfo__delete(struct debuginfo *dbg);
34 35
35/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 36/* Find probe_trace_events specified by perf_probe_event from debuginfo */
36extern int debuginfo__find_trace_events(struct debuginfo *self, 37extern int debuginfo__find_trace_events(struct debuginfo *dbg,
37 struct perf_probe_event *pev, 38 struct perf_probe_event *pev,
38 struct probe_trace_event **tevs, 39 struct probe_trace_event **tevs,
39 int max_tevs); 40 int max_tevs);
40 41
41/* Find a perf_probe_point from debuginfo */ 42/* Find a perf_probe_point from debuginfo */
42extern int debuginfo__find_probe_point(struct debuginfo *self, 43extern int debuginfo__find_probe_point(struct debuginfo *dbg,
43 unsigned long addr, 44 unsigned long addr,
44 struct perf_probe_point *ppt); 45 struct perf_probe_point *ppt);
45 46
46/* Find a line range */ 47/* Find a line range */
47extern int debuginfo__find_line_range(struct debuginfo *self, 48extern int debuginfo__find_line_range(struct debuginfo *dbg,
48 struct line_range *lr); 49 struct line_range *lr);
49 50
50/* Find available variables */ 51/* Find available variables */
51extern int debuginfo__find_available_vars_at(struct debuginfo *self, 52extern int debuginfo__find_available_vars_at(struct debuginfo *dbg,
52 struct perf_probe_event *pev, 53 struct perf_probe_event *pev,
53 struct variable_list **vls, 54 struct variable_list **vls,
54 int max_points, bool externs); 55 int max_points, bool externs);
@@ -105,6 +106,6 @@ struct line_finder {
105 int found; 106 int found;
106}; 107};
107 108
108#endif /* DWARF_SUPPORT */ 109#endif /* HAVE_DWARF_SUPPORT */
109 110
110#endif /*_PROBE_FINDER_H */ 111#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/pstack.h b/tools/perf/util/pstack.h
index 4cedea59f518..c3cb6584d527 100644
--- a/tools/perf/util/pstack.h
+++ b/tools/perf/util/pstack.h
@@ -5,10 +5,10 @@
5 5
6struct pstack; 6struct pstack;
7struct pstack *pstack__new(unsigned short max_nr_entries); 7struct pstack *pstack__new(unsigned short max_nr_entries);
8void pstack__delete(struct pstack *self); 8void pstack__delete(struct pstack *pstack);
9bool pstack__empty(const struct pstack *self); 9bool pstack__empty(const struct pstack *pstack);
10void pstack__remove(struct pstack *self, void *key); 10void pstack__remove(struct pstack *pstack, void *key);
11void pstack__push(struct pstack *self, void *key); 11void pstack__push(struct pstack *pstack, void *key);
12void *pstack__pop(struct pstack *self); 12void *pstack__pop(struct pstack *pstack);
13 13
14#endif /* _PERF_PSTACK_ */ 14#endif /* _PERF_PSTACK_ */
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index f75ae1b9900c..239036fb2b2c 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -17,5 +17,5 @@ util/xyarray.c
17util/cgroup.c 17util/cgroup.c
18util/rblist.c 18util/rblist.c
19util/strlist.c 19util/strlist.c
20util/sysfs.c 20util/fs.c
21../../lib/rbtree.c 21../../lib/rbtree.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 71b5412bbbb9..4bf8ace7f511 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -33,13 +33,6 @@ int eprintf(int level, const char *fmt, ...)
33# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, 33# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
34#endif 34#endif
35 35
36struct throttle_event {
37 struct perf_event_header header;
38 u64 time;
39 u64 id;
40 u64 stream_id;
41};
42
43PyMODINIT_FUNC initperf(void); 36PyMODINIT_FUNC initperf(void);
44 37
45#define member_def(type, member, ptype, help) \ 38#define member_def(type, member, ptype, help) \
@@ -822,6 +815,8 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
822 PyObject *pyevent = pyrf_event__new(event); 815 PyObject *pyevent = pyrf_event__new(event);
823 struct pyrf_event *pevent = (struct pyrf_event *)pyevent; 816 struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
824 817
818 perf_evlist__mmap_consume(evlist, cpu);
819
825 if (pyevent == NULL) 820 if (pyevent == NULL)
826 return PyErr_NoMemory(); 821 return PyErr_NoMemory();
827 822
@@ -1036,6 +1031,7 @@ PyMODINIT_FUNC initperf(void)
1036 pyrf_cpu_map__setup_types() < 0) 1031 pyrf_cpu_map__setup_types() < 0)
1037 return; 1032 return;
1038 1033
1034 /* The page_size is placed in util object. */
1039 page_size = sysconf(_SC_PAGE_SIZE); 1035 page_size = sysconf(_SC_PAGE_SIZE);
1040 1036
1041 Py_INCREF(&pyrf_evlist__type); 1037 Py_INCREF(&pyrf_evlist__type);
diff --git a/tools/perf/util/rblist.c b/tools/perf/util/rblist.c
index a16cdd2625ad..0dfe27d99458 100644
--- a/tools/perf/util/rblist.c
+++ b/tools/perf/util/rblist.c
@@ -48,10 +48,12 @@ void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
48 rblist->node_delete(rblist, rb_node); 48 rblist->node_delete(rblist, rb_node);
49} 49}
50 50
51struct rb_node *rblist__find(struct rblist *rblist, const void *entry) 51static struct rb_node *__rblist__findnew(struct rblist *rblist,
52 const void *entry,
53 bool create)
52{ 54{
53 struct rb_node **p = &rblist->entries.rb_node; 55 struct rb_node **p = &rblist->entries.rb_node;
54 struct rb_node *parent = NULL; 56 struct rb_node *parent = NULL, *new_node = NULL;
55 57
56 while (*p != NULL) { 58 while (*p != NULL) {
57 int rc; 59 int rc;
@@ -67,7 +69,26 @@ struct rb_node *rblist__find(struct rblist *rblist, const void *entry)
67 return parent; 69 return parent;
68 } 70 }
69 71
70 return NULL; 72 if (create) {
73 new_node = rblist->node_new(rblist, entry);
74 if (new_node) {
75 rb_link_node(new_node, parent, p);
76 rb_insert_color(new_node, &rblist->entries);
77 ++rblist->nr_entries;
78 }
79 }
80
81 return new_node;
82}
83
84struct rb_node *rblist__find(struct rblist *rblist, const void *entry)
85{
86 return __rblist__findnew(rblist, entry, false);
87}
88
89struct rb_node *rblist__findnew(struct rblist *rblist, const void *entry)
90{
91 return __rblist__findnew(rblist, entry, true);
71} 92}
72 93
73void rblist__init(struct rblist *rblist) 94void rblist__init(struct rblist *rblist)
diff --git a/tools/perf/util/rblist.h b/tools/perf/util/rblist.h
index 6d0cae5ae83d..ff9913b994c2 100644
--- a/tools/perf/util/rblist.h
+++ b/tools/perf/util/rblist.h
@@ -32,6 +32,7 @@ void rblist__delete(struct rblist *rblist);
32int rblist__add_node(struct rblist *rblist, const void *new_entry); 32int rblist__add_node(struct rblist *rblist, const void *new_entry);
33void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node); 33void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node);
34struct rb_node *rblist__find(struct rblist *rblist, const void *entry); 34struct rb_node *rblist__find(struct rblist *rblist, const void *entry);
35struct rb_node *rblist__findnew(struct rblist *rblist, const void *entry);
35struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx); 36struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx);
36 37
37static inline bool rblist__empty(const struct rblist *rblist) 38static inline bool rblist__empty(const struct rblist *rblist)
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 18d73aa2f0f8..c8845b107f60 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -2,6 +2,8 @@
2#include "evsel.h" 2#include "evsel.h"
3#include "cpumap.h" 3#include "cpumap.h"
4#include "parse-events.h" 4#include "parse-events.h"
5#include "fs.h"
6#include "util.h"
5 7
6typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); 8typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
7 9
@@ -106,3 +108,72 @@ void perf_evlist__config(struct perf_evlist *evlist,
106 108
107 perf_evlist__set_id_pos(evlist); 109 perf_evlist__set_id_pos(evlist);
108} 110}
111
112static int get_max_rate(unsigned int *rate)
113{
114 char path[PATH_MAX];
115 const char *procfs = procfs__mountpoint();
116
117 if (!procfs)
118 return -1;
119
120 snprintf(path, PATH_MAX,
121 "%s/sys/kernel/perf_event_max_sample_rate", procfs);
122
123 return filename__read_int(path, (int *) rate);
124}
125
126static int perf_record_opts__config_freq(struct perf_record_opts *opts)
127{
128 bool user_freq = opts->user_freq != UINT_MAX;
129 unsigned int max_rate;
130
131 if (opts->user_interval != ULLONG_MAX)
132 opts->default_interval = opts->user_interval;
133 if (user_freq)
134 opts->freq = opts->user_freq;
135
136 /*
137 * User specified count overrides default frequency.
138 */
139 if (opts->default_interval)
140 opts->freq = 0;
141 else if (opts->freq) {
142 opts->default_interval = opts->freq;
143 } else {
144 pr_err("frequency and count are zero, aborting\n");
145 return -1;
146 }
147
148 if (get_max_rate(&max_rate))
149 return 0;
150
151 /*
152 * User specified frequency is over current maximum.
153 */
154 if (user_freq && (max_rate < opts->freq)) {
155 pr_err("Maximum frequency rate (%u) reached.\n"
156 "Please use -F freq option with lower value or consider\n"
157 "tweaking /proc/sys/kernel/perf_event_max_sample_rate.\n",
158 max_rate);
159 return -1;
160 }
161
162 /*
163 * Default frequency is over current maximum.
164 */
165 if (max_rate < opts->freq) {
166 pr_warning("Lowering default frequency rate to %u.\n"
167 "Please consider tweaking "
168 "/proc/sys/kernel/perf_event_max_sample_rate.\n",
169 max_rate);
170 opts->freq = max_rate;
171 }
172
173 return 0;
174}
175
176int perf_record_opts__config(struct perf_record_opts *opts)
177{
178 return perf_record_opts__config_freq(opts);
179}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index a85e4ae5f3ac..d5e5969f6fea 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -273,7 +273,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
273 int cpu = sample->cpu; 273 int cpu = sample->cpu;
274 void *data = sample->raw_data; 274 void *data = sample->raw_data;
275 unsigned long long nsecs = sample->time; 275 unsigned long long nsecs = sample->time;
276 char *comm = thread->comm; 276 const char *comm = thread__comm_str(thread);
277 277
278 dSP; 278 dSP;
279 279
@@ -282,7 +282,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
282 282
283 event = find_cache_event(evsel); 283 event = find_cache_event(evsel);
284 if (!event) 284 if (!event)
285 die("ug! no event found for type %" PRIu64, evsel->attr.config); 285 die("ug! no event found for type %" PRIu64, (u64)evsel->attr.config);
286 286
287 pid = raw_field_value(event, "common_pid", data); 287 pid = raw_field_value(event, "common_pid", data);
288 288
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index cc75a3cef388..53c20e7fd900 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -56,6 +56,17 @@ static void handler_call_die(const char *handler_name)
56 Py_FatalError("problem in Python trace event handler"); 56 Py_FatalError("problem in Python trace event handler");
57} 57}
58 58
59/*
60 * Insert val into into the dictionary and decrement the reference counter.
61 * This is necessary for dictionaries since PyDict_SetItemString() does not
62 * steal a reference, as opposed to PyTuple_SetItem().
63 */
64static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObject *val)
65{
66 PyDict_SetItemString(dict, key, val);
67 Py_DECREF(val);
68}
69
59static void define_value(enum print_arg_type field_type, 70static void define_value(enum print_arg_type field_type,
60 const char *ev_name, 71 const char *ev_name,
61 const char *field_name, 72 const char *field_name,
@@ -239,7 +250,7 @@ static void python_process_tracepoint(union perf_event *perf_event
239 int cpu = sample->cpu; 250 int cpu = sample->cpu;
240 void *data = sample->raw_data; 251 void *data = sample->raw_data;
241 unsigned long long nsecs = sample->time; 252 unsigned long long nsecs = sample->time;
242 char *comm = thread->comm; 253 const char *comm = thread__comm_str(thread);
243 254
244 t = PyTuple_New(MAX_FIELDS); 255 t = PyTuple_New(MAX_FIELDS);
245 if (!t) 256 if (!t)
@@ -279,11 +290,11 @@ static void python_process_tracepoint(union perf_event *perf_event
279 PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); 290 PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
280 PyTuple_SetItem(t, n++, PyString_FromString(comm)); 291 PyTuple_SetItem(t, n++, PyString_FromString(comm));
281 } else { 292 } else {
282 PyDict_SetItemString(dict, "common_cpu", PyInt_FromLong(cpu)); 293 pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu));
283 PyDict_SetItemString(dict, "common_s", PyInt_FromLong(s)); 294 pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s));
284 PyDict_SetItemString(dict, "common_ns", PyInt_FromLong(ns)); 295 pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns));
285 PyDict_SetItemString(dict, "common_pid", PyInt_FromLong(pid)); 296 pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid));
286 PyDict_SetItemString(dict, "common_comm", PyString_FromString(comm)); 297 pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm));
287 } 298 }
288 for (field = event->format.fields; field; field = field->next) { 299 for (field = event->format.fields; field; field = field->next) {
289 if (field->flags & FIELD_IS_STRING) { 300 if (field->flags & FIELD_IS_STRING) {
@@ -313,7 +324,7 @@ static void python_process_tracepoint(union perf_event *perf_event
313 if (handler) 324 if (handler)
314 PyTuple_SetItem(t, n++, obj); 325 PyTuple_SetItem(t, n++, obj);
315 else 326 else
316 PyDict_SetItemString(dict, field->name, obj); 327 pydict_set_item_string_decref(dict, field->name, obj);
317 328
318 } 329 }
319 if (!handler) 330 if (!handler)
@@ -370,21 +381,21 @@ static void python_process_general_event(union perf_event *perf_event
370 if (!handler || !PyCallable_Check(handler)) 381 if (!handler || !PyCallable_Check(handler))
371 goto exit; 382 goto exit;
372 383
373 PyDict_SetItemString(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); 384 pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
374 PyDict_SetItemString(dict, "attr", PyString_FromStringAndSize( 385 pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize(
375 (const char *)&evsel->attr, sizeof(evsel->attr))); 386 (const char *)&evsel->attr, sizeof(evsel->attr)));
376 PyDict_SetItemString(dict, "sample", PyString_FromStringAndSize( 387 pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize(
377 (const char *)sample, sizeof(*sample))); 388 (const char *)sample, sizeof(*sample)));
378 PyDict_SetItemString(dict, "raw_buf", PyString_FromStringAndSize( 389 pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize(
379 (const char *)sample->raw_data, sample->raw_size)); 390 (const char *)sample->raw_data, sample->raw_size));
380 PyDict_SetItemString(dict, "comm", 391 pydict_set_item_string_decref(dict, "comm",
381 PyString_FromString(thread->comm)); 392 PyString_FromString(thread__comm_str(thread)));
382 if (al->map) { 393 if (al->map) {
383 PyDict_SetItemString(dict, "dso", 394 pydict_set_item_string_decref(dict, "dso",
384 PyString_FromString(al->map->dso->name)); 395 PyString_FromString(al->map->dso->name));
385 } 396 }
386 if (al->sym) { 397 if (al->sym) {
387 PyDict_SetItemString(dict, "symbol", 398 pydict_set_item_string_decref(dict, "symbol",
388 PyString_FromString(al->sym->name)); 399 PyString_FromString(al->sym->name));
389 } 400 }
390 401
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 568b750c01f6..f36d24a02445 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -16,73 +16,34 @@
16#include "perf_regs.h" 16#include "perf_regs.h"
17#include "vdso.h" 17#include "vdso.h"
18 18
19static int perf_session__open(struct perf_session *self, bool force) 19static int perf_session__open(struct perf_session *session)
20{ 20{
21 struct stat input_stat; 21 struct perf_data_file *file = session->file;
22 22
23 if (!strcmp(self->filename, "-")) { 23 if (perf_session__read_header(session) < 0) {
24 self->fd_pipe = true;
25 self->fd = STDIN_FILENO;
26
27 if (perf_session__read_header(self) < 0)
28 pr_err("incompatible file format (rerun with -v to learn more)");
29
30 return 0;
31 }
32
33 self->fd = open(self->filename, O_RDONLY);
34 if (self->fd < 0) {
35 int err = errno;
36
37 pr_err("failed to open %s: %s", self->filename, strerror(err));
38 if (err == ENOENT && !strcmp(self->filename, "perf.data"))
39 pr_err(" (try 'perf record' first)");
40 pr_err("\n");
41 return -errno;
42 }
43
44 if (fstat(self->fd, &input_stat) < 0)
45 goto out_close;
46
47 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
48 pr_err("file %s not owned by current user or root\n",
49 self->filename);
50 goto out_close;
51 }
52
53 if (!input_stat.st_size) {
54 pr_info("zero-sized file (%s), nothing to do!\n",
55 self->filename);
56 goto out_close;
57 }
58
59 if (perf_session__read_header(self) < 0) {
60 pr_err("incompatible file format (rerun with -v to learn more)"); 24 pr_err("incompatible file format (rerun with -v to learn more)");
61 goto out_close; 25 return -1;
62 } 26 }
63 27
64 if (!perf_evlist__valid_sample_type(self->evlist)) { 28 if (perf_data_file__is_pipe(file))
29 return 0;
30
31 if (!perf_evlist__valid_sample_type(session->evlist)) {
65 pr_err("non matching sample_type"); 32 pr_err("non matching sample_type");
66 goto out_close; 33 return -1;
67 } 34 }
68 35
69 if (!perf_evlist__valid_sample_id_all(self->evlist)) { 36 if (!perf_evlist__valid_sample_id_all(session->evlist)) {
70 pr_err("non matching sample_id_all"); 37 pr_err("non matching sample_id_all");
71 goto out_close; 38 return -1;
72 } 39 }
73 40
74 if (!perf_evlist__valid_read_format(self->evlist)) { 41 if (!perf_evlist__valid_read_format(session->evlist)) {
75 pr_err("non matching read_format"); 42 pr_err("non matching read_format");
76 goto out_close; 43 return -1;
77 } 44 }
78 45
79 self->size = input_stat.st_size;
80 return 0; 46 return 0;
81
82out_close:
83 close(self->fd);
84 self->fd = -1;
85 return -1;
86} 47}
87 48
88void perf_session__set_id_hdr_size(struct perf_session *session) 49void perf_session__set_id_hdr_size(struct perf_session *session)
@@ -92,71 +53,70 @@ void perf_session__set_id_hdr_size(struct perf_session *session)
92 machines__set_id_hdr_size(&session->machines, id_hdr_size); 53 machines__set_id_hdr_size(&session->machines, id_hdr_size);
93} 54}
94 55
95int perf_session__create_kernel_maps(struct perf_session *self) 56int perf_session__create_kernel_maps(struct perf_session *session)
96{ 57{
97 int ret = machine__create_kernel_maps(&self->machines.host); 58 int ret = machine__create_kernel_maps(&session->machines.host);
98 59
99 if (ret >= 0) 60 if (ret >= 0)
100 ret = machines__create_guest_kernel_maps(&self->machines); 61 ret = machines__create_guest_kernel_maps(&session->machines);
101 return ret; 62 return ret;
102} 63}
103 64
104static void perf_session__destroy_kernel_maps(struct perf_session *self) 65static void perf_session__destroy_kernel_maps(struct perf_session *session)
105{ 66{
106 machines__destroy_kernel_maps(&self->machines); 67 machines__destroy_kernel_maps(&session->machines);
107} 68}
108 69
109struct perf_session *perf_session__new(const char *filename, int mode, 70struct perf_session *perf_session__new(struct perf_data_file *file,
110 bool force, bool repipe, 71 bool repipe, struct perf_tool *tool)
111 struct perf_tool *tool)
112{ 72{
113 struct perf_session *self; 73 struct perf_session *session = zalloc(sizeof(*session));
114 struct stat st;
115 size_t len;
116
117 if (!filename || !strlen(filename)) {
118 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
119 filename = "-";
120 else
121 filename = "perf.data";
122 }
123 74
124 len = strlen(filename); 75 if (!session)
125 self = zalloc(sizeof(*self) + len);
126
127 if (self == NULL)
128 goto out; 76 goto out;
129 77
130 memcpy(self->filename, filename, len); 78 session->repipe = repipe;
131 self->repipe = repipe; 79 INIT_LIST_HEAD(&session->ordered_samples.samples);
132 INIT_LIST_HEAD(&self->ordered_samples.samples); 80 INIT_LIST_HEAD(&session->ordered_samples.sample_cache);
133 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 81 INIT_LIST_HEAD(&session->ordered_samples.to_free);
134 INIT_LIST_HEAD(&self->ordered_samples.to_free); 82 machines__init(&session->machines);
135 machines__init(&self->machines);
136 83
137 if (mode == O_RDONLY) { 84 if (file) {
138 if (perf_session__open(self, force) < 0) 85 if (perf_data_file__open(file))
139 goto out_delete; 86 goto out_delete;
140 perf_session__set_id_hdr_size(self); 87
141 } else if (mode == O_WRONLY) { 88 session->file = file;
89
90 if (perf_data_file__is_read(file)) {
91 if (perf_session__open(session) < 0)
92 goto out_close;
93
94 perf_session__set_id_hdr_size(session);
95 }
96 }
97
98 if (!file || perf_data_file__is_write(file)) {
142 /* 99 /*
143 * In O_RDONLY mode this will be performed when reading the 100 * In O_RDONLY mode this will be performed when reading the
144 * kernel MMAP event, in perf_event__process_mmap(). 101 * kernel MMAP event, in perf_event__process_mmap().
145 */ 102 */
146 if (perf_session__create_kernel_maps(self) < 0) 103 if (perf_session__create_kernel_maps(session) < 0)
147 goto out_delete; 104 goto out_delete;
148 } 105 }
149 106
150 if (tool && tool->ordering_requires_timestamps && 107 if (tool && tool->ordering_requires_timestamps &&
151 tool->ordered_samples && !perf_evlist__sample_id_all(self->evlist)) { 108 tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) {
152 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); 109 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
153 tool->ordered_samples = false; 110 tool->ordered_samples = false;
154 } 111 }
155 112
156out: 113 return session;
157 return self; 114
158out_delete: 115 out_close:
159 perf_session__delete(self); 116 perf_data_file__close(file);
117 out_delete:
118 perf_session__delete(session);
119 out:
160 return NULL; 120 return NULL;
161} 121}
162 122
@@ -186,15 +146,16 @@ static void perf_session_env__delete(struct perf_session_env *env)
186 free(env->pmu_mappings); 146 free(env->pmu_mappings);
187} 147}
188 148
189void perf_session__delete(struct perf_session *self) 149void perf_session__delete(struct perf_session *session)
190{ 150{
191 perf_session__destroy_kernel_maps(self); 151 perf_session__destroy_kernel_maps(session);
192 perf_session__delete_dead_threads(self); 152 perf_session__delete_dead_threads(session);
193 perf_session__delete_threads(self); 153 perf_session__delete_threads(session);
194 perf_session_env__delete(&self->header.env); 154 perf_session_env__delete(&session->header.env);
195 machines__exit(&self->machines); 155 machines__exit(&session->machines);
196 close(self->fd); 156 if (session->file)
197 free(self); 157 perf_data_file__close(session->file);
158 free(session);
198 vdso__exit(); 159 vdso__exit();
199} 160}
200 161
@@ -397,6 +358,17 @@ static void perf_event__read_swap(union perf_event *event, bool sample_id_all)
397 swap_sample_id_all(event, &event->read + 1); 358 swap_sample_id_all(event, &event->read + 1);
398} 359}
399 360
361static void perf_event__throttle_swap(union perf_event *event,
362 bool sample_id_all)
363{
364 event->throttle.time = bswap_64(event->throttle.time);
365 event->throttle.id = bswap_64(event->throttle.id);
366 event->throttle.stream_id = bswap_64(event->throttle.stream_id);
367
368 if (sample_id_all)
369 swap_sample_id_all(event, &event->throttle + 1);
370}
371
400static u8 revbyte(u8 b) 372static u8 revbyte(u8 b)
401{ 373{
402 int rev = (b >> 4) | ((b & 0xf) << 4); 374 int rev = (b >> 4) | ((b & 0xf) << 4);
@@ -442,6 +414,9 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
442 attr->bp_type = bswap_32(attr->bp_type); 414 attr->bp_type = bswap_32(attr->bp_type);
443 attr->bp_addr = bswap_64(attr->bp_addr); 415 attr->bp_addr = bswap_64(attr->bp_addr);
444 attr->bp_len = bswap_64(attr->bp_len); 416 attr->bp_len = bswap_64(attr->bp_len);
417 attr->branch_sample_type = bswap_64(attr->branch_sample_type);
418 attr->sample_regs_user = bswap_64(attr->sample_regs_user);
419 attr->sample_stack_user = bswap_32(attr->sample_stack_user);
445 420
446 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); 421 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
447} 422}
@@ -482,6 +457,8 @@ static perf_event__swap_op perf_event__swap_ops[] = {
482 [PERF_RECORD_EXIT] = perf_event__task_swap, 457 [PERF_RECORD_EXIT] = perf_event__task_swap,
483 [PERF_RECORD_LOST] = perf_event__all64_swap, 458 [PERF_RECORD_LOST] = perf_event__all64_swap,
484 [PERF_RECORD_READ] = perf_event__read_swap, 459 [PERF_RECORD_READ] = perf_event__read_swap,
460 [PERF_RECORD_THROTTLE] = perf_event__throttle_swap,
461 [PERF_RECORD_UNTHROTTLE] = perf_event__throttle_swap,
485 [PERF_RECORD_SAMPLE] = perf_event__all64_swap, 462 [PERF_RECORD_SAMPLE] = perf_event__all64_swap,
486 [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap, 463 [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap,
487 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, 464 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
@@ -525,13 +502,16 @@ static int flush_sample_queue(struct perf_session *s,
525 struct perf_sample sample; 502 struct perf_sample sample;
526 u64 limit = os->next_flush; 503 u64 limit = os->next_flush;
527 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; 504 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
528 unsigned idx = 0, progress_next = os->nr_samples / 16;
529 bool show_progress = limit == ULLONG_MAX; 505 bool show_progress = limit == ULLONG_MAX;
506 struct ui_progress prog;
530 int ret; 507 int ret;
531 508
532 if (!tool->ordered_samples || !limit) 509 if (!tool->ordered_samples || !limit)
533 return 0; 510 return 0;
534 511
512 if (show_progress)
513 ui_progress__init(&prog, os->nr_samples, "Processing time ordered events...");
514
535 list_for_each_entry_safe(iter, tmp, head, list) { 515 list_for_each_entry_safe(iter, tmp, head, list) {
536 if (session_done()) 516 if (session_done())
537 return 0; 517 return 0;
@@ -552,11 +532,9 @@ static int flush_sample_queue(struct perf_session *s,
552 os->last_flush = iter->timestamp; 532 os->last_flush = iter->timestamp;
553 list_del(&iter->list); 533 list_del(&iter->list);
554 list_add(&iter->list, &os->sample_cache); 534 list_add(&iter->list, &os->sample_cache);
555 if (show_progress && (++idx >= progress_next)) { 535
556 progress_next += os->nr_samples / 16; 536 if (show_progress)
557 ui_progress__update(idx, os->nr_samples, 537 ui_progress__update(&prog, 1);
558 "Processing time ordered events...");
559 }
560 } 538 }
561 539
562 if (list_empty(head)) { 540 if (list_empty(head)) {
@@ -860,6 +838,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
860 if (sample_type & PERF_SAMPLE_DATA_SRC) 838 if (sample_type & PERF_SAMPLE_DATA_SRC)
861 printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); 839 printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
862 840
841 if (sample_type & PERF_SAMPLE_TRANSACTION)
842 printf("... transaction: %" PRIx64 "\n", sample->transaction);
843
863 if (sample_type & PERF_SAMPLE_READ) 844 if (sample_type & PERF_SAMPLE_READ)
864 sample_read__printf(sample, evsel->attr.read_format); 845 sample_read__printf(sample, evsel->attr.read_format);
865} 846}
@@ -1031,6 +1012,7 @@ static int perf_session_deliver_event(struct perf_session *session,
1031static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 1012static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
1032 struct perf_tool *tool, u64 file_offset) 1013 struct perf_tool *tool, u64 file_offset)
1033{ 1014{
1015 int fd = perf_data_file__fd(session->file);
1034 int err; 1016 int err;
1035 1017
1036 dump_event(session, event, file_offset, NULL); 1018 dump_event(session, event, file_offset, NULL);
@@ -1044,7 +1026,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
1044 return err; 1026 return err;
1045 case PERF_RECORD_HEADER_TRACING_DATA: 1027 case PERF_RECORD_HEADER_TRACING_DATA:
1046 /* setup for reading amidst mmap */ 1028 /* setup for reading amidst mmap */
1047 lseek(session->fd, file_offset, SEEK_SET); 1029 lseek(fd, file_offset, SEEK_SET);
1048 return tool->tracing_data(tool, event, session); 1030 return tool->tracing_data(tool, event, session);
1049 case PERF_RECORD_HEADER_BUILD_ID: 1031 case PERF_RECORD_HEADER_BUILD_ID:
1050 return tool->build_id(tool, event, session); 1032 return tool->build_id(tool, event, session);
@@ -1101,11 +1083,11 @@ static int perf_session__process_event(struct perf_session *session,
1101 file_offset); 1083 file_offset);
1102} 1084}
1103 1085
1104void perf_event_header__bswap(struct perf_event_header *self) 1086void perf_event_header__bswap(struct perf_event_header *hdr)
1105{ 1087{
1106 self->type = bswap_32(self->type); 1088 hdr->type = bswap_32(hdr->type);
1107 self->misc = bswap_16(self->misc); 1089 hdr->misc = bswap_16(hdr->misc);
1108 self->size = bswap_16(self->size); 1090 hdr->size = bswap_16(hdr->size);
1109} 1091}
1110 1092
1111struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 1093struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
@@ -1113,11 +1095,11 @@ struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1113 return machine__findnew_thread(&session->machines.host, 0, pid); 1095 return machine__findnew_thread(&session->machines.host, 0, pid);
1114} 1096}
1115 1097
1116static struct thread *perf_session__register_idle_thread(struct perf_session *self) 1098static struct thread *perf_session__register_idle_thread(struct perf_session *session)
1117{ 1099{
1118 struct thread *thread = perf_session__findnew(self, 0); 1100 struct thread *thread = perf_session__findnew(session, 0);
1119 1101
1120 if (thread == NULL || thread__set_comm(thread, "swapper")) { 1102 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
1121 pr_err("problem inserting idle task.\n"); 1103 pr_err("problem inserting idle task.\n");
1122 thread = NULL; 1104 thread = NULL;
1123 } 1105 }
@@ -1167,9 +1149,10 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
1167 1149
1168volatile int session_done; 1150volatile int session_done;
1169 1151
1170static int __perf_session__process_pipe_events(struct perf_session *self, 1152static int __perf_session__process_pipe_events(struct perf_session *session,
1171 struct perf_tool *tool) 1153 struct perf_tool *tool)
1172{ 1154{
1155 int fd = perf_data_file__fd(session->file);
1173 union perf_event *event; 1156 union perf_event *event;
1174 uint32_t size, cur_size = 0; 1157 uint32_t size, cur_size = 0;
1175 void *buf = NULL; 1158 void *buf = NULL;
@@ -1188,7 +1171,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
1188 return -errno; 1171 return -errno;
1189more: 1172more:
1190 event = buf; 1173 event = buf;
1191 err = readn(self->fd, event, sizeof(struct perf_event_header)); 1174 err = readn(fd, event, sizeof(struct perf_event_header));
1192 if (err <= 0) { 1175 if (err <= 0) {
1193 if (err == 0) 1176 if (err == 0)
1194 goto done; 1177 goto done;
@@ -1197,7 +1180,7 @@ more:
1197 goto out_err; 1180 goto out_err;
1198 } 1181 }
1199 1182
1200 if (self->header.needs_swap) 1183 if (session->header.needs_swap)
1201 perf_event_header__bswap(&event->header); 1184 perf_event_header__bswap(&event->header);
1202 1185
1203 size = event->header.size; 1186 size = event->header.size;
@@ -1220,7 +1203,7 @@ more:
1220 p += sizeof(struct perf_event_header); 1203 p += sizeof(struct perf_event_header);
1221 1204
1222 if (size - sizeof(struct perf_event_header)) { 1205 if (size - sizeof(struct perf_event_header)) {
1223 err = readn(self->fd, p, size - sizeof(struct perf_event_header)); 1206 err = readn(fd, p, size - sizeof(struct perf_event_header));
1224 if (err <= 0) { 1207 if (err <= 0) {
1225 if (err == 0) { 1208 if (err == 0) {
1226 pr_err("unexpected end of event stream\n"); 1209 pr_err("unexpected end of event stream\n");
@@ -1232,7 +1215,7 @@ more:
1232 } 1215 }
1233 } 1216 }
1234 1217
1235 if ((skip = perf_session__process_event(self, event, tool, head)) < 0) { 1218 if ((skip = perf_session__process_event(session, event, tool, head)) < 0) {
1236 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", 1219 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1237 head, event->header.size, event->header.type); 1220 head, event->header.size, event->header.type);
1238 err = -EINVAL; 1221 err = -EINVAL;
@@ -1247,11 +1230,13 @@ more:
1247 if (!session_done()) 1230 if (!session_done())
1248 goto more; 1231 goto more;
1249done: 1232done:
1250 err = 0; 1233 /* do the final flush for ordered samples */
1234 session->ordered_samples.next_flush = ULLONG_MAX;
1235 err = flush_sample_queue(session, tool);
1251out_err: 1236out_err:
1252 free(buf); 1237 free(buf);
1253 perf_session__warn_about_errors(self, tool); 1238 perf_session__warn_about_errors(session, tool);
1254 perf_session_free_sample_buffers(self); 1239 perf_session_free_sample_buffers(session);
1255 return err; 1240 return err;
1256} 1241}
1257 1242
@@ -1299,12 +1284,14 @@ int __perf_session__process_events(struct perf_session *session,
1299 u64 data_offset, u64 data_size, 1284 u64 data_offset, u64 data_size,
1300 u64 file_size, struct perf_tool *tool) 1285 u64 file_size, struct perf_tool *tool)
1301{ 1286{
1302 u64 head, page_offset, file_offset, file_pos, progress_next; 1287 int fd = perf_data_file__fd(session->file);
1288 u64 head, page_offset, file_offset, file_pos;
1303 int err, mmap_prot, mmap_flags, map_idx = 0; 1289 int err, mmap_prot, mmap_flags, map_idx = 0;
1304 size_t mmap_size; 1290 size_t mmap_size;
1305 char *buf, *mmaps[NUM_MMAPS]; 1291 char *buf, *mmaps[NUM_MMAPS];
1306 union perf_event *event; 1292 union perf_event *event;
1307 uint32_t size; 1293 uint32_t size;
1294 struct ui_progress prog;
1308 1295
1309 perf_tool__fill_defaults(tool); 1296 perf_tool__fill_defaults(tool);
1310 1297
@@ -1315,7 +1302,7 @@ int __perf_session__process_events(struct perf_session *session,
1315 if (data_size && (data_offset + data_size < file_size)) 1302 if (data_size && (data_offset + data_size < file_size))
1316 file_size = data_offset + data_size; 1303 file_size = data_offset + data_size;
1317 1304
1318 progress_next = file_size / 16; 1305 ui_progress__init(&prog, file_size, "Processing events...");
1319 1306
1320 mmap_size = MMAP_SIZE; 1307 mmap_size = MMAP_SIZE;
1321 if (mmap_size > file_size) 1308 if (mmap_size > file_size)
@@ -1331,7 +1318,7 @@ int __perf_session__process_events(struct perf_session *session,
1331 mmap_flags = MAP_PRIVATE; 1318 mmap_flags = MAP_PRIVATE;
1332 } 1319 }
1333remap: 1320remap:
1334 buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd, 1321 buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, fd,
1335 file_offset); 1322 file_offset);
1336 if (buf == MAP_FAILED) { 1323 if (buf == MAP_FAILED) {
1337 pr_err("failed to mmap file\n"); 1324 pr_err("failed to mmap file\n");
@@ -1370,19 +1357,15 @@ more:
1370 head += size; 1357 head += size;
1371 file_pos += size; 1358 file_pos += size;
1372 1359
1373 if (file_pos >= progress_next) { 1360 ui_progress__update(&prog, size);
1374 progress_next += file_size / 16;
1375 ui_progress__update(file_pos, file_size,
1376 "Processing events...");
1377 }
1378 1361
1379 err = 0;
1380 if (session_done()) 1362 if (session_done())
1381 goto out_err; 1363 goto out;
1382 1364
1383 if (file_pos < file_size) 1365 if (file_pos < file_size)
1384 goto more; 1366 goto more;
1385 1367
1368out:
1386 /* do the final flush for ordered samples */ 1369 /* do the final flush for ordered samples */
1387 session->ordered_samples.next_flush = ULLONG_MAX; 1370 session->ordered_samples.next_flush = ULLONG_MAX;
1388 err = flush_sample_queue(session, tool); 1371 err = flush_sample_queue(session, tool);
@@ -1393,21 +1376,22 @@ out_err:
1393 return err; 1376 return err;
1394} 1377}
1395 1378
1396int perf_session__process_events(struct perf_session *self, 1379int perf_session__process_events(struct perf_session *session,
1397 struct perf_tool *tool) 1380 struct perf_tool *tool)
1398{ 1381{
1382 u64 size = perf_data_file__size(session->file);
1399 int err; 1383 int err;
1400 1384
1401 if (perf_session__register_idle_thread(self) == NULL) 1385 if (perf_session__register_idle_thread(session) == NULL)
1402 return -ENOMEM; 1386 return -ENOMEM;
1403 1387
1404 if (!self->fd_pipe) 1388 if (!perf_data_file__is_pipe(session->file))
1405 err = __perf_session__process_events(self, 1389 err = __perf_session__process_events(session,
1406 self->header.data_offset, 1390 session->header.data_offset,
1407 self->header.data_size, 1391 session->header.data_size,
1408 self->size, tool); 1392 size, tool);
1409 else 1393 else
1410 err = __perf_session__process_pipe_events(self, tool); 1394 err = __perf_session__process_pipe_events(session, tool);
1411 1395
1412 return err; 1396 return err;
1413} 1397}
@@ -1456,15 +1440,15 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
1456 return 0; 1440 return 0;
1457} 1441}
1458 1442
1459size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) 1443size_t perf_session__fprintf_dsos(struct perf_session *session, FILE *fp)
1460{ 1444{
1461 return machines__fprintf_dsos(&self->machines, fp); 1445 return machines__fprintf_dsos(&session->machines, fp);
1462} 1446}
1463 1447
1464size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, 1448size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
1465 bool (skip)(struct dso *dso, int parm), int parm) 1449 bool (skip)(struct dso *dso, int parm), int parm)
1466{ 1450{
1467 return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm); 1451 return machines__fprintf_dsos_buildid(&session->machines, fp, skip, parm);
1468} 1452}
1469 1453
1470size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) 1454size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
@@ -1525,7 +1509,8 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1525 if (symbol_conf.use_callchain && sample->callchain) { 1509 if (symbol_conf.use_callchain && sample->callchain) {
1526 1510
1527 if (machine__resolve_callchain(machine, evsel, al.thread, 1511 if (machine__resolve_callchain(machine, evsel, al.thread,
1528 sample, NULL, NULL) != 0) { 1512 sample, NULL, NULL,
1513 PERF_MAX_STACK_DEPTH) != 0) {
1529 if (verbose) 1514 if (verbose)
1530 error("Failed to resolve callchain. Skipping\n"); 1515 error("Failed to resolve callchain. Skipping\n");
1531 return; 1516 return;
@@ -1629,13 +1614,14 @@ int perf_session__cpu_bitmap(struct perf_session *session,
1629void perf_session__fprintf_info(struct perf_session *session, FILE *fp, 1614void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
1630 bool full) 1615 bool full)
1631{ 1616{
1617 int fd = perf_data_file__fd(session->file);
1632 struct stat st; 1618 struct stat st;
1633 int ret; 1619 int ret;
1634 1620
1635 if (session == NULL || fp == NULL) 1621 if (session == NULL || fp == NULL)
1636 return; 1622 return;
1637 1623
1638 ret = fstat(session->fd, &st); 1624 ret = fstat(fd, &st);
1639 if (ret == -1) 1625 if (ret == -1)
1640 return; 1626 return;
1641 1627
@@ -1664,9 +1650,9 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
1664 continue; 1650 continue;
1665 1651
1666 err = -EEXIST; 1652 err = -EEXIST;
1667 if (evsel->handler.func != NULL) 1653 if (evsel->handler != NULL)
1668 goto out; 1654 goto out;
1669 evsel->handler.func = assocs[i].handler; 1655 evsel->handler = assocs[i].handler;
1670 } 1656 }
1671 1657
1672 err = 0; 1658 err = 0;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 04bf7373a7e5..50f640958f0f 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -7,6 +7,7 @@
7#include "machine.h" 7#include "machine.h"
8#include "symbol.h" 8#include "symbol.h"
9#include "thread.h" 9#include "thread.h"
10#include "data.h"
10#include <linux/rbtree.h> 11#include <linux/rbtree.h>
11#include <linux/perf_event.h> 12#include <linux/perf_event.h>
12 13
@@ -29,16 +30,13 @@ struct ordered_samples {
29 30
30struct perf_session { 31struct perf_session {
31 struct perf_header header; 32 struct perf_header header;
32 unsigned long size;
33 struct machines machines; 33 struct machines machines;
34 struct perf_evlist *evlist; 34 struct perf_evlist *evlist;
35 struct pevent *pevent; 35 struct pevent *pevent;
36 struct events_stats stats; 36 struct events_stats stats;
37 int fd;
38 bool fd_pipe;
39 bool repipe; 37 bool repipe;
40 struct ordered_samples ordered_samples; 38 struct ordered_samples ordered_samples;
41 char filename[1]; 39 struct perf_data_file *file;
42}; 40};
43 41
44#define PRINT_IP_OPT_IP (1<<0) 42#define PRINT_IP_OPT_IP (1<<0)
@@ -49,17 +47,16 @@ struct perf_session {
49 47
50struct perf_tool; 48struct perf_tool;
51 49
52struct perf_session *perf_session__new(const char *filename, int mode, 50struct perf_session *perf_session__new(struct perf_data_file *file,
53 bool force, bool repipe, 51 bool repipe, struct perf_tool *tool);
54 struct perf_tool *tool);
55void perf_session__delete(struct perf_session *session); 52void perf_session__delete(struct perf_session *session);
56 53
57void perf_event_header__bswap(struct perf_event_header *self); 54void perf_event_header__bswap(struct perf_event_header *hdr);
58 55
59int __perf_session__process_events(struct perf_session *self, 56int __perf_session__process_events(struct perf_session *session,
60 u64 data_offset, u64 data_size, u64 size, 57 u64 data_offset, u64 data_size, u64 size,
61 struct perf_tool *tool); 58 struct perf_tool *tool);
62int perf_session__process_events(struct perf_session *self, 59int perf_session__process_events(struct perf_session *session,
63 struct perf_tool *tool); 60 struct perf_tool *tool);
64 61
65int perf_session_queue_event(struct perf_session *s, union perf_event *event, 62int perf_session_queue_event(struct perf_session *s, union perf_event *event,
@@ -67,37 +64,38 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event,
67 64
68void perf_tool__fill_defaults(struct perf_tool *tool); 65void perf_tool__fill_defaults(struct perf_tool *tool);
69 66
70int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel, 67int perf_session__resolve_callchain(struct perf_session *session,
68 struct perf_evsel *evsel,
71 struct thread *thread, 69 struct thread *thread,
72 struct ip_callchain *chain, 70 struct ip_callchain *chain,
73 struct symbol **parent); 71 struct symbol **parent);
74 72
75bool perf_session__has_traces(struct perf_session *self, const char *msg); 73bool perf_session__has_traces(struct perf_session *session, const char *msg);
76 74
77void mem_bswap_64(void *src, int byte_size); 75void mem_bswap_64(void *src, int byte_size);
78void mem_bswap_32(void *src, int byte_size); 76void mem_bswap_32(void *src, int byte_size);
79void perf_event__attr_swap(struct perf_event_attr *attr); 77void perf_event__attr_swap(struct perf_event_attr *attr);
80 78
81int perf_session__create_kernel_maps(struct perf_session *self); 79int perf_session__create_kernel_maps(struct perf_session *session);
82 80
83void perf_session__set_id_hdr_size(struct perf_session *session); 81void perf_session__set_id_hdr_size(struct perf_session *session);
84 82
85static inline 83static inline
86struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) 84struct machine *perf_session__find_machine(struct perf_session *session, pid_t pid)
87{ 85{
88 return machines__find(&self->machines, pid); 86 return machines__find(&session->machines, pid);
89} 87}
90 88
91static inline 89static inline
92struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) 90struct machine *perf_session__findnew_machine(struct perf_session *session, pid_t pid)
93{ 91{
94 return machines__findnew(&self->machines, pid); 92 return machines__findnew(&session->machines, pid);
95} 93}
96 94
97struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 95struct thread *perf_session__findnew(struct perf_session *session, pid_t pid);
98size_t perf_session__fprintf(struct perf_session *self, FILE *fp); 96size_t perf_session__fprintf(struct perf_session *session, FILE *fp);
99 97
100size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); 98size_t perf_session__fprintf_dsos(struct perf_session *session, FILE *fp);
101 99
102size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp, 100size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
103 bool (fn)(struct dso *dso, int parm), int parm); 101 bool (fn)(struct dso *dso, int parm), int parm);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 5f118a089519..8b0bb1f4494a 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,5 +1,6 @@
1#include "sort.h" 1#include "sort.h"
2#include "hist.h" 2#include "hist.h"
3#include "comm.h"
3#include "symbol.h" 4#include "symbol.h"
4 5
5regex_t parent_regex; 6regex_t parent_regex;
@@ -42,7 +43,7 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
42 return n; 43 return n;
43} 44}
44 45
45static int64_t cmp_null(void *l, void *r) 46static int64_t cmp_null(const void *l, const void *r)
46{ 47{
47 if (!l && !r) 48 if (!l && !r)
48 return 0; 49 return 0;
@@ -60,11 +61,12 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
60 return right->thread->tid - left->thread->tid; 61 return right->thread->tid - left->thread->tid;
61} 62}
62 63
63static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, 64static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
64 size_t size, unsigned int width) 65 size_t size, unsigned int width)
65{ 66{
67 const char *comm = thread__comm_str(he->thread);
66 return repsep_snprintf(bf, size, "%*s:%5d", width - 6, 68 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
67 self->thread->comm ?: "", self->thread->tid); 69 comm ?: "", he->thread->tid);
68} 70}
69 71
70struct sort_entry sort_thread = { 72struct sort_entry sort_thread = {
@@ -79,25 +81,21 @@ struct sort_entry sort_thread = {
79static int64_t 81static int64_t
80sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 82sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
81{ 83{
82 return right->thread->tid - left->thread->tid; 84 /* Compare the addr that should be unique among comm */
85 return comm__str(right->comm) - comm__str(left->comm);
83} 86}
84 87
85static int64_t 88static int64_t
86sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) 89sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
87{ 90{
88 char *comm_l = left->thread->comm; 91 /* Compare the addr that should be unique among comm */
89 char *comm_r = right->thread->comm; 92 return comm__str(right->comm) - comm__str(left->comm);
90
91 if (!comm_l || !comm_r)
92 return cmp_null(comm_l, comm_r);
93
94 return strcmp(comm_l, comm_r);
95} 93}
96 94
97static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf, 95static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
98 size_t size, unsigned int width) 96 size_t size, unsigned int width)
99{ 97{
100 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 98 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
101} 99}
102 100
103struct sort_entry sort_comm = { 101struct sort_entry sort_comm = {
@@ -148,10 +146,10 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf,
148 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); 146 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
149} 147}
150 148
151static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, 149static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
152 size_t size, unsigned int width) 150 size_t size, unsigned int width)
153{ 151{
154 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); 152 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
155} 153}
156 154
157struct sort_entry sort_dso = { 155struct sort_entry sort_dso = {
@@ -182,9 +180,19 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
182static int64_t 180static int64_t
183sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 181sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
184{ 182{
183 int64_t ret;
184
185 if (!left->ms.sym && !right->ms.sym) 185 if (!left->ms.sym && !right->ms.sym)
186 return right->level - left->level; 186 return right->level - left->level;
187 187
188 /*
189 * comparing symbol address alone is not enough since it's a
190 * relative address within a dso.
191 */
192 ret = sort__dso_cmp(left, right);
193 if (ret != 0)
194 return ret;
195
188 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 196 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
189} 197}
190 198
@@ -224,11 +232,11 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
224 return ret; 232 return ret;
225} 233}
226 234
227static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, 235static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
228 size_t size, unsigned int width) 236 size_t size, unsigned int width)
229{ 237{
230 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, 238 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
231 self->level, bf, size, width); 239 he->level, bf, size, width);
232} 240}
233 241
234struct sort_entry sort_sym = { 242struct sort_entry sort_sym = {
@@ -243,50 +251,32 @@ struct sort_entry sort_sym = {
243static int64_t 251static int64_t
244sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) 252sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
245{ 253{
246 return (int64_t)(right->ip - left->ip); 254 if (!left->srcline) {
255 if (!left->ms.map)
256 left->srcline = SRCLINE_UNKNOWN;
257 else {
258 struct map *map = left->ms.map;
259 left->srcline = get_srcline(map->dso,
260 map__rip_2objdump(map, left->ip));
261 }
262 }
263 if (!right->srcline) {
264 if (!right->ms.map)
265 right->srcline = SRCLINE_UNKNOWN;
266 else {
267 struct map *map = right->ms.map;
268 right->srcline = get_srcline(map->dso,
269 map__rip_2objdump(map, right->ip));
270 }
271 }
272 return strcmp(left->srcline, right->srcline);
247} 273}
248 274
249static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, 275static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
250 size_t size, 276 size_t size,
251 unsigned int width __maybe_unused) 277 unsigned int width __maybe_unused)
252{ 278{
253 FILE *fp = NULL; 279 return repsep_snprintf(bf, size, "%s", he->srcline);
254 char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
255 size_t line_len;
256
257 if (path != NULL)
258 goto out_path;
259
260 if (!self->ms.map)
261 goto out_ip;
262
263 if (!strncmp(self->ms.map->dso->long_name, "/tmp/perf-", 10))
264 goto out_ip;
265
266 snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
267 self->ms.map->dso->long_name, self->ip);
268 fp = popen(cmd, "r");
269 if (!fp)
270 goto out_ip;
271
272 if (getline(&path, &line_len, fp) < 0 || !line_len)
273 goto out_ip;
274 self->srcline = strdup(path);
275 if (self->srcline == NULL)
276 goto out_ip;
277
278 nl = strchr(self->srcline, '\n');
279 if (nl != NULL)
280 *nl = '\0';
281 path = self->srcline;
282out_path:
283 if (fp)
284 pclose(fp);
285 return repsep_snprintf(bf, size, "%s", path);
286out_ip:
287 if (fp)
288 pclose(fp);
289 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
290} 280}
291 281
292struct sort_entry sort_srcline = { 282struct sort_entry sort_srcline = {
@@ -310,11 +300,11 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
310 return strcmp(sym_l->name, sym_r->name); 300 return strcmp(sym_l->name, sym_r->name);
311} 301}
312 302
313static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, 303static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
314 size_t size, unsigned int width) 304 size_t size, unsigned int width)
315{ 305{
316 return repsep_snprintf(bf, size, "%-*s", width, 306 return repsep_snprintf(bf, size, "%-*s", width,
317 self->parent ? self->parent->name : "[other]"); 307 he->parent ? he->parent->name : "[other]");
318} 308}
319 309
320struct sort_entry sort_parent = { 310struct sort_entry sort_parent = {
@@ -332,10 +322,10 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
332 return right->cpu - left->cpu; 322 return right->cpu - left->cpu;
333} 323}
334 324
335static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, 325static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
336 size_t size, unsigned int width) 326 size_t size, unsigned int width)
337{ 327{
338 return repsep_snprintf(bf, size, "%*d", width, self->cpu); 328 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
339} 329}
340 330
341struct sort_entry sort_cpu = { 331struct sort_entry sort_cpu = {
@@ -354,10 +344,10 @@ sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
354 right->branch_info->from.map); 344 right->branch_info->from.map);
355} 345}
356 346
357static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf, 347static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
358 size_t size, unsigned int width) 348 size_t size, unsigned int width)
359{ 349{
360 return _hist_entry__dso_snprintf(self->branch_info->from.map, 350 return _hist_entry__dso_snprintf(he->branch_info->from.map,
361 bf, size, width); 351 bf, size, width);
362} 352}
363 353
@@ -368,10 +358,10 @@ sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
368 right->branch_info->to.map); 358 right->branch_info->to.map);
369} 359}
370 360
371static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf, 361static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
372 size_t size, unsigned int width) 362 size_t size, unsigned int width)
373{ 363{
374 return _hist_entry__dso_snprintf(self->branch_info->to.map, 364 return _hist_entry__dso_snprintf(he->branch_info->to.map,
375 bf, size, width); 365 bf, size, width);
376} 366}
377 367
@@ -399,21 +389,21 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
399 return _sort__sym_cmp(to_l->sym, to_r->sym); 389 return _sort__sym_cmp(to_l->sym, to_r->sym);
400} 390}
401 391
402static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, 392static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
403 size_t size, unsigned int width) 393 size_t size, unsigned int width)
404{ 394{
405 struct addr_map_symbol *from = &self->branch_info->from; 395 struct addr_map_symbol *from = &he->branch_info->from;
406 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, 396 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
407 self->level, bf, size, width); 397 he->level, bf, size, width);
408 398
409} 399}
410 400
411static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, 401static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
412 size_t size, unsigned int width) 402 size_t size, unsigned int width)
413{ 403{
414 struct addr_map_symbol *to = &self->branch_info->to; 404 struct addr_map_symbol *to = &he->branch_info->to;
415 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, 405 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
416 self->level, bf, size, width); 406 he->level, bf, size, width);
417 407
418} 408}
419 409
@@ -456,13 +446,13 @@ sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
456 return mp || p; 446 return mp || p;
457} 447}
458 448
459static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf, 449static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
460 size_t size, unsigned int width){ 450 size_t size, unsigned int width){
461 static const char *out = "N/A"; 451 static const char *out = "N/A";
462 452
463 if (self->branch_info->flags.predicted) 453 if (he->branch_info->flags.predicted)
464 out = "N"; 454 out = "N";
465 else if (self->branch_info->flags.mispred) 455 else if (he->branch_info->flags.mispred)
466 out = "Y"; 456 out = "Y";
467 457
468 return repsep_snprintf(bf, size, "%-*s", width, out); 458 return repsep_snprintf(bf, size, "%-*s", width, out);
@@ -482,19 +472,19 @@ sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
482 return (int64_t)(r - l); 472 return (int64_t)(r - l);
483} 473}
484 474
485static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf, 475static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
486 size_t size, unsigned int width) 476 size_t size, unsigned int width)
487{ 477{
488 uint64_t addr = 0; 478 uint64_t addr = 0;
489 struct map *map = NULL; 479 struct map *map = NULL;
490 struct symbol *sym = NULL; 480 struct symbol *sym = NULL;
491 481
492 if (self->mem_info) { 482 if (he->mem_info) {
493 addr = self->mem_info->daddr.addr; 483 addr = he->mem_info->daddr.addr;
494 map = self->mem_info->daddr.map; 484 map = he->mem_info->daddr.map;
495 sym = self->mem_info->daddr.sym; 485 sym = he->mem_info->daddr.sym;
496 } 486 }
497 return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size, 487 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
498 width); 488 width);
499} 489}
500 490
@@ -512,13 +502,13 @@ sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
512 return _sort__dso_cmp(map_l, map_r); 502 return _sort__dso_cmp(map_l, map_r);
513} 503}
514 504
515static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf, 505static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
516 size_t size, unsigned int width) 506 size_t size, unsigned int width)
517{ 507{
518 struct map *map = NULL; 508 struct map *map = NULL;
519 509
520 if (self->mem_info) 510 if (he->mem_info)
521 map = self->mem_info->daddr.map; 511 map = he->mem_info->daddr.map;
522 512
523 return _hist_entry__dso_snprintf(map, bf, size, width); 513 return _hist_entry__dso_snprintf(map, bf, size, width);
524} 514}
@@ -542,14 +532,14 @@ sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
542 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock); 532 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
543} 533}
544 534
545static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf, 535static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
546 size_t size, unsigned int width) 536 size_t size, unsigned int width)
547{ 537{
548 const char *out; 538 const char *out;
549 u64 mask = PERF_MEM_LOCK_NA; 539 u64 mask = PERF_MEM_LOCK_NA;
550 540
551 if (self->mem_info) 541 if (he->mem_info)
552 mask = self->mem_info->data_src.mem_lock; 542 mask = he->mem_info->data_src.mem_lock;
553 543
554 if (mask & PERF_MEM_LOCK_NA) 544 if (mask & PERF_MEM_LOCK_NA)
555 out = "N/A"; 545 out = "N/A";
@@ -591,7 +581,7 @@ static const char * const tlb_access[] = {
591}; 581};
592#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *)) 582#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
593 583
594static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf, 584static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
595 size_t size, unsigned int width) 585 size_t size, unsigned int width)
596{ 586{
597 char out[64]; 587 char out[64];
@@ -602,8 +592,8 @@ static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf,
602 592
603 out[0] = '\0'; 593 out[0] = '\0';
604 594
605 if (self->mem_info) 595 if (he->mem_info)
606 m = self->mem_info->data_src.mem_dtlb; 596 m = he->mem_info->data_src.mem_dtlb;
607 597
608 hit = m & PERF_MEM_TLB_HIT; 598 hit = m & PERF_MEM_TLB_HIT;
609 miss = m & PERF_MEM_TLB_MISS; 599 miss = m & PERF_MEM_TLB_MISS;
@@ -668,7 +658,7 @@ static const char * const mem_lvl[] = {
668}; 658};
669#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *)) 659#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
670 660
671static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf, 661static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
672 size_t size, unsigned int width) 662 size_t size, unsigned int width)
673{ 663{
674 char out[64]; 664 char out[64];
@@ -677,8 +667,8 @@ static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf,
677 u64 m = PERF_MEM_LVL_NA; 667 u64 m = PERF_MEM_LVL_NA;
678 u64 hit, miss; 668 u64 hit, miss;
679 669
680 if (self->mem_info) 670 if (he->mem_info)
681 m = self->mem_info->data_src.mem_lvl; 671 m = he->mem_info->data_src.mem_lvl;
682 672
683 out[0] = '\0'; 673 out[0] = '\0';
684 674
@@ -736,7 +726,7 @@ static const char * const snoop_access[] = {
736}; 726};
737#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *)) 727#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
738 728
739static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf, 729static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
740 size_t size, unsigned int width) 730 size_t size, unsigned int width)
741{ 731{
742 char out[64]; 732 char out[64];
@@ -746,8 +736,8 @@ static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf,
746 736
747 out[0] = '\0'; 737 out[0] = '\0';
748 738
749 if (self->mem_info) 739 if (he->mem_info)
750 m = self->mem_info->data_src.mem_snoop; 740 m = he->mem_info->data_src.mem_snoop;
751 741
752 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) { 742 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
753 if (!(m & 0x1)) 743 if (!(m & 0x1))
@@ -784,10 +774,10 @@ sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
784 return he_weight(left) - he_weight(right); 774 return he_weight(left) - he_weight(right);
785} 775}
786 776
787static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf, 777static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
788 size_t size, unsigned int width) 778 size_t size, unsigned int width)
789{ 779{
790 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self)); 780 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
791} 781}
792 782
793struct sort_entry sort_local_weight = { 783struct sort_entry sort_local_weight = {
@@ -803,10 +793,10 @@ sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
803 return left->stat.weight - right->stat.weight; 793 return left->stat.weight - right->stat.weight;
804} 794}
805 795
806static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf, 796static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
807 size_t size, unsigned int width) 797 size_t size, unsigned int width)
808{ 798{
809 return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight); 799 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
810} 800}
811 801
812struct sort_entry sort_global_weight = { 802struct sort_entry sort_global_weight = {
@@ -858,6 +848,127 @@ struct sort_entry sort_mem_snoop = {
858 .se_width_idx = HISTC_MEM_SNOOP, 848 .se_width_idx = HISTC_MEM_SNOOP,
859}; 849};
860 850
851static int64_t
852sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
853{
854 return left->branch_info->flags.abort !=
855 right->branch_info->flags.abort;
856}
857
858static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
859 size_t size, unsigned int width)
860{
861 static const char *out = ".";
862
863 if (he->branch_info->flags.abort)
864 out = "A";
865 return repsep_snprintf(bf, size, "%-*s", width, out);
866}
867
868struct sort_entry sort_abort = {
869 .se_header = "Transaction abort",
870 .se_cmp = sort__abort_cmp,
871 .se_snprintf = hist_entry__abort_snprintf,
872 .se_width_idx = HISTC_ABORT,
873};
874
875static int64_t
876sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
877{
878 return left->branch_info->flags.in_tx !=
879 right->branch_info->flags.in_tx;
880}
881
882static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
883 size_t size, unsigned int width)
884{
885 static const char *out = ".";
886
887 if (he->branch_info->flags.in_tx)
888 out = "T";
889
890 return repsep_snprintf(bf, size, "%-*s", width, out);
891}
892
893struct sort_entry sort_in_tx = {
894 .se_header = "Branch in transaction",
895 .se_cmp = sort__in_tx_cmp,
896 .se_snprintf = hist_entry__in_tx_snprintf,
897 .se_width_idx = HISTC_IN_TX,
898};
899
900static int64_t
901sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
902{
903 return left->transaction - right->transaction;
904}
905
906static inline char *add_str(char *p, const char *str)
907{
908 strcpy(p, str);
909 return p + strlen(str);
910}
911
912static struct txbit {
913 unsigned flag;
914 const char *name;
915 int skip_for_len;
916} txbits[] = {
917 { PERF_TXN_ELISION, "EL ", 0 },
918 { PERF_TXN_TRANSACTION, "TX ", 1 },
919 { PERF_TXN_SYNC, "SYNC ", 1 },
920 { PERF_TXN_ASYNC, "ASYNC ", 0 },
921 { PERF_TXN_RETRY, "RETRY ", 0 },
922 { PERF_TXN_CONFLICT, "CON ", 0 },
923 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
924 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
925 { 0, NULL, 0 }
926};
927
928int hist_entry__transaction_len(void)
929{
930 int i;
931 int len = 0;
932
933 for (i = 0; txbits[i].name; i++) {
934 if (!txbits[i].skip_for_len)
935 len += strlen(txbits[i].name);
936 }
937 len += 4; /* :XX<space> */
938 return len;
939}
940
941static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
942 size_t size, unsigned int width)
943{
944 u64 t = he->transaction;
945 char buf[128];
946 char *p = buf;
947 int i;
948
949 buf[0] = 0;
950 for (i = 0; txbits[i].name; i++)
951 if (txbits[i].flag & t)
952 p = add_str(p, txbits[i].name);
953 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
954 p = add_str(p, "NEITHER ");
955 if (t & PERF_TXN_ABORT_MASK) {
956 sprintf(p, ":%" PRIx64,
957 (t & PERF_TXN_ABORT_MASK) >>
958 PERF_TXN_ABORT_SHIFT);
959 p += strlen(p);
960 }
961
962 return repsep_snprintf(bf, size, "%-*s", width, buf);
963}
964
965struct sort_entry sort_transaction = {
966 .se_header = "Transaction ",
967 .se_cmp = sort__transaction_cmp,
968 .se_snprintf = hist_entry__transaction_snprintf,
969 .se_width_idx = HISTC_TRANSACTION,
970};
971
861struct sort_dimension { 972struct sort_dimension {
862 const char *name; 973 const char *name;
863 struct sort_entry *entry; 974 struct sort_entry *entry;
@@ -876,6 +987,7 @@ static struct sort_dimension common_sort_dimensions[] = {
876 DIM(SORT_SRCLINE, "srcline", sort_srcline), 987 DIM(SORT_SRCLINE, "srcline", sort_srcline),
877 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), 988 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
878 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 989 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
990 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
879}; 991};
880 992
881#undef DIM 993#undef DIM
@@ -888,6 +1000,8 @@ static struct sort_dimension bstack_sort_dimensions[] = {
888 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from), 1000 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
889 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to), 1001 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
890 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), 1002 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
1003 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1004 DIM(SORT_ABORT, "abort", sort_abort),
891}; 1005};
892 1006
893#undef DIM 1007#undef DIM
@@ -1009,7 +1123,7 @@ int setup_sorting(void)
1009 return ret; 1123 return ret;
1010} 1124}
1011 1125
1012static void sort_entry__setup_elide(struct sort_entry *self, 1126static void sort_entry__setup_elide(struct sort_entry *se,
1013 struct strlist *list, 1127 struct strlist *list,
1014 const char *list_name, FILE *fp) 1128 const char *list_name, FILE *fp)
1015{ 1129{
@@ -1017,12 +1131,14 @@ static void sort_entry__setup_elide(struct sort_entry *self,
1017 if (fp != NULL) 1131 if (fp != NULL)
1018 fprintf(fp, "# %s: %s\n", list_name, 1132 fprintf(fp, "# %s: %s\n", list_name,
1019 strlist__entry(list, 0)->s); 1133 strlist__entry(list, 0)->s);
1020 self->elide = true; 1134 se->elide = true;
1021 } 1135 }
1022} 1136}
1023 1137
1024void sort__setup_elide(FILE *output) 1138void sort__setup_elide(FILE *output)
1025{ 1139{
1140 struct sort_entry *se;
1141
1026 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, 1142 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1027 "dso", output); 1143 "dso", output);
1028 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, 1144 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
@@ -1058,4 +1174,15 @@ void sort__setup_elide(FILE *output)
1058 "snoop", output); 1174 "snoop", output);
1059 } 1175 }
1060 1176
1177 /*
1178 * It makes no sense to elide all of sort entries.
1179 * Just revert them to show up again.
1180 */
1181 list_for_each_entry(se, &hist_entry__sort_list, list) {
1182 if (!se->elide)
1183 return;
1184 }
1185
1186 list_for_each_entry(se, &hist_entry__sort_list, list)
1187 se->elide = false;
1061} 1188}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 4e80dbd271e7..43e5ff42a609 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -22,7 +22,6 @@
22#include "parse-events.h" 22#include "parse-events.h"
23 23
24#include "thread.h" 24#include "thread.h"
25#include "sort.h"
26 25
27extern regex_t parent_regex; 26extern regex_t parent_regex;
28extern const char *sort_order; 27extern const char *sort_order;
@@ -84,7 +83,9 @@ struct hist_entry {
84 struct he_stat stat; 83 struct he_stat stat;
85 struct map_symbol ms; 84 struct map_symbol ms;
86 struct thread *thread; 85 struct thread *thread;
86 struct comm *comm;
87 u64 ip; 87 u64 ip;
88 u64 transaction;
88 s32 cpu; 89 s32 cpu;
89 90
90 struct hist_entry_diff diff; 91 struct hist_entry_diff diff;
@@ -145,6 +146,7 @@ enum sort_type {
145 SORT_SRCLINE, 146 SORT_SRCLINE,
146 SORT_LOCAL_WEIGHT, 147 SORT_LOCAL_WEIGHT,
147 SORT_GLOBAL_WEIGHT, 148 SORT_GLOBAL_WEIGHT,
149 SORT_TRANSACTION,
148 150
149 /* branch stack specific sort keys */ 151 /* branch stack specific sort keys */
150 __SORT_BRANCH_STACK, 152 __SORT_BRANCH_STACK,
@@ -153,6 +155,8 @@ enum sort_type {
153 SORT_SYM_FROM, 155 SORT_SYM_FROM,
154 SORT_SYM_TO, 156 SORT_SYM_TO,
155 SORT_MISPREDICT, 157 SORT_MISPREDICT,
158 SORT_ABORT,
159 SORT_IN_TX,
156 160
157 /* memory mode specific sort keys */ 161 /* memory mode specific sort keys */
158 __SORT_MEMORY_MODE, 162 __SORT_MEMORY_MODE,
@@ -175,7 +179,7 @@ struct sort_entry {
175 179
176 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); 180 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
177 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *); 181 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
178 int (*se_snprintf)(struct hist_entry *self, char *bf, size_t size, 182 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
179 unsigned int width); 183 unsigned int width);
180 u8 se_width_idx; 184 u8 se_width_idx;
181 bool elide; 185 bool elide;
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
new file mode 100644
index 000000000000..d11aefbc4b8d
--- /dev/null
+++ b/tools/perf/util/srcline.c
@@ -0,0 +1,265 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include <linux/kernel.h>
6
7#include "util/dso.h"
8#include "util/util.h"
9#include "util/debug.h"
10
11#ifdef HAVE_LIBBFD_SUPPORT
12
13/*
14 * Implement addr2line using libbfd.
15 */
16#define PACKAGE "perf"
17#include <bfd.h>
18
19struct a2l_data {
20 const char *input;
21 unsigned long addr;
22
23 bool found;
24 const char *filename;
25 const char *funcname;
26 unsigned line;
27
28 bfd *abfd;
29 asymbol **syms;
30};
31
32static int bfd_error(const char *string)
33{
34 const char *errmsg;
35
36 errmsg = bfd_errmsg(bfd_get_error());
37 fflush(stdout);
38
39 if (string)
40 pr_debug("%s: %s\n", string, errmsg);
41 else
42 pr_debug("%s\n", errmsg);
43
44 return -1;
45}
46
47static int slurp_symtab(bfd *abfd, struct a2l_data *a2l)
48{
49 long storage;
50 long symcount;
51 asymbol **syms;
52 bfd_boolean dynamic = FALSE;
53
54 if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
55 return bfd_error(bfd_get_filename(abfd));
56
57 storage = bfd_get_symtab_upper_bound(abfd);
58 if (storage == 0L) {
59 storage = bfd_get_dynamic_symtab_upper_bound(abfd);
60 dynamic = TRUE;
61 }
62 if (storage < 0L)
63 return bfd_error(bfd_get_filename(abfd));
64
65 syms = malloc(storage);
66 if (dynamic)
67 symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
68 else
69 symcount = bfd_canonicalize_symtab(abfd, syms);
70
71 if (symcount < 0) {
72 free(syms);
73 return bfd_error(bfd_get_filename(abfd));
74 }
75
76 a2l->syms = syms;
77 return 0;
78}
79
80static void find_address_in_section(bfd *abfd, asection *section, void *data)
81{
82 bfd_vma pc, vma;
83 bfd_size_type size;
84 struct a2l_data *a2l = data;
85
86 if (a2l->found)
87 return;
88
89 if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
90 return;
91
92 pc = a2l->addr;
93 vma = bfd_get_section_vma(abfd, section);
94 size = bfd_get_section_size(section);
95
96 if (pc < vma || pc >= vma + size)
97 return;
98
99 a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma,
100 &a2l->filename, &a2l->funcname,
101 &a2l->line);
102}
103
104static struct a2l_data *addr2line_init(const char *path)
105{
106 bfd *abfd;
107 struct a2l_data *a2l = NULL;
108
109 abfd = bfd_openr(path, NULL);
110 if (abfd == NULL)
111 return NULL;
112
113 if (!bfd_check_format(abfd, bfd_object))
114 goto out;
115
116 a2l = zalloc(sizeof(*a2l));
117 if (a2l == NULL)
118 goto out;
119
120 a2l->abfd = abfd;
121 a2l->input = strdup(path);
122 if (a2l->input == NULL)
123 goto out;
124
125 if (slurp_symtab(abfd, a2l))
126 goto out;
127
128 return a2l;
129
130out:
131 if (a2l) {
132 free((void *)a2l->input);
133 free(a2l);
134 }
135 bfd_close(abfd);
136 return NULL;
137}
138
139static void addr2line_cleanup(struct a2l_data *a2l)
140{
141 if (a2l->abfd)
142 bfd_close(a2l->abfd);
143 free((void *)a2l->input);
144 free(a2l->syms);
145 free(a2l);
146}
147
148static int addr2line(const char *dso_name, unsigned long addr,
149 char **file, unsigned int *line)
150{
151 int ret = 0;
152 struct a2l_data *a2l;
153
154 a2l = addr2line_init(dso_name);
155 if (a2l == NULL) {
156 pr_warning("addr2line_init failed for %s\n", dso_name);
157 return 0;
158 }
159
160 a2l->addr = addr;
161 bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
162
163 if (a2l->found && a2l->filename) {
164 *file = strdup(a2l->filename);
165 *line = a2l->line;
166
167 if (*file)
168 ret = 1;
169 }
170
171 addr2line_cleanup(a2l);
172 return ret;
173}
174
175#else /* HAVE_LIBBFD_SUPPORT */
176
177static int addr2line(const char *dso_name, unsigned long addr,
178 char **file, unsigned int *line_nr)
179{
180 FILE *fp;
181 char cmd[PATH_MAX];
182 char *filename = NULL;
183 size_t len;
184 char *sep;
185 int ret = 0;
186
187 scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
188 dso_name, addr);
189
190 fp = popen(cmd, "r");
191 if (fp == NULL) {
192 pr_warning("popen failed for %s\n", dso_name);
193 return 0;
194 }
195
196 if (getline(&filename, &len, fp) < 0 || !len) {
197 pr_warning("addr2line has no output for %s\n", dso_name);
198 goto out;
199 }
200
201 sep = strchr(filename, '\n');
202 if (sep)
203 *sep = '\0';
204
205 if (!strcmp(filename, "??:0")) {
206 pr_debug("no debugging info in %s\n", dso_name);
207 free(filename);
208 goto out;
209 }
210
211 sep = strchr(filename, ':');
212 if (sep) {
213 *sep++ = '\0';
214 *file = filename;
215 *line_nr = strtoul(sep, NULL, 0);
216 ret = 1;
217 }
218out:
219 pclose(fp);
220 return ret;
221}
222#endif /* HAVE_LIBBFD_SUPPORT */
223
224char *get_srcline(struct dso *dso, unsigned long addr)
225{
226 char *file = NULL;
227 unsigned line = 0;
228 char *srcline;
229 char *dso_name = dso->long_name;
230 size_t size;
231
232 if (!dso->has_srcline)
233 return SRCLINE_UNKNOWN;
234
235 if (dso_name[0] == '[')
236 goto out;
237
238 if (!strncmp(dso_name, "/tmp/perf-", 10))
239 goto out;
240
241 if (!addr2line(dso_name, addr, &file, &line))
242 goto out;
243
244 /* just calculate actual length */
245 size = snprintf(NULL, 0, "%s:%u", file, line) + 1;
246
247 srcline = malloc(size);
248 if (srcline)
249 snprintf(srcline, size, "%s:%u", file, line);
250 else
251 srcline = SRCLINE_UNKNOWN;
252
253 free(file);
254 return srcline;
255
256out:
257 dso->has_srcline = 0;
258 return SRCLINE_UNKNOWN;
259}
260
261void free_srcline(char *srcline)
262{
263 if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
264 free(srcline);
265}
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
index 834c8ebfe38e..3edd0538161f 100644
--- a/tools/perf/util/strfilter.c
+++ b/tools/perf/util/strfilter.c
@@ -10,22 +10,22 @@ static const char *OP_not = "!"; /* Logical NOT */
10#define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!') 10#define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!')
11#define is_separator(c) (is_operator(c) || (c) == '(' || (c) == ')') 11#define is_separator(c) (is_operator(c) || (c) == '(' || (c) == ')')
12 12
13static void strfilter_node__delete(struct strfilter_node *self) 13static void strfilter_node__delete(struct strfilter_node *node)
14{ 14{
15 if (self) { 15 if (node) {
16 if (self->p && !is_operator(*self->p)) 16 if (node->p && !is_operator(*node->p))
17 free((char *)self->p); 17 free((char *)node->p);
18 strfilter_node__delete(self->l); 18 strfilter_node__delete(node->l);
19 strfilter_node__delete(self->r); 19 strfilter_node__delete(node->r);
20 free(self); 20 free(node);
21 } 21 }
22} 22}
23 23
24void strfilter__delete(struct strfilter *self) 24void strfilter__delete(struct strfilter *filter)
25{ 25{
26 if (self) { 26 if (filter) {
27 strfilter_node__delete(self->root); 27 strfilter_node__delete(filter->root);
28 free(self); 28 free(filter);
29 } 29 }
30} 30}
31 31
@@ -62,15 +62,15 @@ static struct strfilter_node *strfilter_node__alloc(const char *op,
62 struct strfilter_node *l, 62 struct strfilter_node *l,
63 struct strfilter_node *r) 63 struct strfilter_node *r)
64{ 64{
65 struct strfilter_node *ret = zalloc(sizeof(struct strfilter_node)); 65 struct strfilter_node *node = zalloc(sizeof(*node));
66 66
67 if (ret) { 67 if (node) {
68 ret->p = op; 68 node->p = op;
69 ret->l = l; 69 node->l = l;
70 ret->r = r; 70 node->r = r;
71 } 71 }
72 72
73 return ret; 73 return node;
74} 74}
75 75
76static struct strfilter_node *strfilter_node__new(const char *s, 76static struct strfilter_node *strfilter_node__new(const char *s,
@@ -154,46 +154,46 @@ error:
154 */ 154 */
155struct strfilter *strfilter__new(const char *rules, const char **err) 155struct strfilter *strfilter__new(const char *rules, const char **err)
156{ 156{
157 struct strfilter *ret = zalloc(sizeof(struct strfilter)); 157 struct strfilter *filter = zalloc(sizeof(*filter));
158 const char *ep = NULL; 158 const char *ep = NULL;
159 159
160 if (ret) 160 if (filter)
161 ret->root = strfilter_node__new(rules, &ep); 161 filter->root = strfilter_node__new(rules, &ep);
162 162
163 if (!ret || !ret->root || *ep != '\0') { 163 if (!filter || !filter->root || *ep != '\0') {
164 if (err) 164 if (err)
165 *err = ep; 165 *err = ep;
166 strfilter__delete(ret); 166 strfilter__delete(filter);
167 ret = NULL; 167 filter = NULL;
168 } 168 }
169 169
170 return ret; 170 return filter;
171} 171}
172 172
173static bool strfilter_node__compare(struct strfilter_node *self, 173static bool strfilter_node__compare(struct strfilter_node *node,
174 const char *str) 174 const char *str)
175{ 175{
176 if (!self || !self->p) 176 if (!node || !node->p)
177 return false; 177 return false;
178 178
179 switch (*self->p) { 179 switch (*node->p) {
180 case '|': /* OR */ 180 case '|': /* OR */
181 return strfilter_node__compare(self->l, str) || 181 return strfilter_node__compare(node->l, str) ||
182 strfilter_node__compare(self->r, str); 182 strfilter_node__compare(node->r, str);
183 case '&': /* AND */ 183 case '&': /* AND */
184 return strfilter_node__compare(self->l, str) && 184 return strfilter_node__compare(node->l, str) &&
185 strfilter_node__compare(self->r, str); 185 strfilter_node__compare(node->r, str);
186 case '!': /* NOT */ 186 case '!': /* NOT */
187 return !strfilter_node__compare(self->r, str); 187 return !strfilter_node__compare(node->r, str);
188 default: 188 default:
189 return strglobmatch(str, self->p); 189 return strglobmatch(str, node->p);
190 } 190 }
191} 191}
192 192
193/* Return true if STR matches the filter rules */ 193/* Return true if STR matches the filter rules */
194bool strfilter__compare(struct strfilter *self, const char *str) 194bool strfilter__compare(struct strfilter *filter, const char *str)
195{ 195{
196 if (!self) 196 if (!filter)
197 return false; 197 return false;
198 return strfilter_node__compare(self->root, str); 198 return strfilter_node__compare(filter->root, str);
199} 199}
diff --git a/tools/perf/util/strfilter.h b/tools/perf/util/strfilter.h
index 00f58a7506de..fe611f3c9e39 100644
--- a/tools/perf/util/strfilter.h
+++ b/tools/perf/util/strfilter.h
@@ -30,19 +30,19 @@ struct strfilter *strfilter__new(const char *rules, const char **err);
30 30
31/** 31/**
32 * strfilter__compare - compare given string and a string filter 32 * strfilter__compare - compare given string and a string filter
33 * @self: String filter 33 * @filter: String filter
34 * @str: target string 34 * @str: target string
35 * 35 *
36 * Compare @str and @self. Return true if the str match the rule 36 * Compare @str and @filter. Return true if the str match the rule
37 */ 37 */
38bool strfilter__compare(struct strfilter *self, const char *str); 38bool strfilter__compare(struct strfilter *filter, const char *str);
39 39
40/** 40/**
41 * strfilter__delete - delete a string filter 41 * strfilter__delete - delete a string filter
42 * @self: String filter to delete 42 * @filter: String filter to delete
43 * 43 *
44 * Delete @self. 44 * Delete @filter.
45 */ 45 */
46void strfilter__delete(struct strfilter *self); 46void strfilter__delete(struct strfilter *filter);
47 47
48#endif 48#endif
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index a9c829be5216..eed0b96302af 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -8,7 +8,7 @@
8#include "symbol.h" 8#include "symbol.h"
9#include "debug.h" 9#include "debug.h"
10 10
11#ifndef HAVE_ELF_GETPHDRNUM 11#ifndef HAVE_ELF_GETPHDRNUM_SUPPORT
12static int elf_getphdrnum(Elf *elf, size_t *dst) 12static int elf_getphdrnum(Elf *elf, size_t *dst)
13{ 13{
14 GElf_Ehdr gehdr; 14 GElf_Ehdr gehdr;
@@ -487,27 +487,27 @@ int filename__read_debuglink(const char *filename, char *debuglink,
487 487
488 ek = elf_kind(elf); 488 ek = elf_kind(elf);
489 if (ek != ELF_K_ELF) 489 if (ek != ELF_K_ELF)
490 goto out_close; 490 goto out_elf_end;
491 491
492 if (gelf_getehdr(elf, &ehdr) == NULL) { 492 if (gelf_getehdr(elf, &ehdr) == NULL) {
493 pr_err("%s: cannot get elf header.\n", __func__); 493 pr_err("%s: cannot get elf header.\n", __func__);
494 goto out_close; 494 goto out_elf_end;
495 } 495 }
496 496
497 sec = elf_section_by_name(elf, &ehdr, &shdr, 497 sec = elf_section_by_name(elf, &ehdr, &shdr,
498 ".gnu_debuglink", NULL); 498 ".gnu_debuglink", NULL);
499 if (sec == NULL) 499 if (sec == NULL)
500 goto out_close; 500 goto out_elf_end;
501 501
502 data = elf_getdata(sec, NULL); 502 data = elf_getdata(sec, NULL);
503 if (data == NULL) 503 if (data == NULL)
504 goto out_close; 504 goto out_elf_end;
505 505
506 /* the start of this section is a zero-terminated string */ 506 /* the start of this section is a zero-terminated string */
507 strncpy(debuglink, data->d_buf, size); 507 strncpy(debuglink, data->d_buf, size);
508 508
509out_elf_end:
509 elf_end(elf); 510 elf_end(elf);
510
511out_close: 511out_close:
512 close(fd); 512 close(fd);
513out: 513out:
@@ -1018,6 +1018,601 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
1018 return err; 1018 return err;
1019} 1019}
1020 1020
1021static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len)
1022{
1023 ssize_t r;
1024 size_t n;
1025 int err = -1;
1026 char *buf = malloc(page_size);
1027
1028 if (buf == NULL)
1029 return -1;
1030
1031 if (lseek(to, to_offs, SEEK_SET) != to_offs)
1032 goto out;
1033
1034 if (lseek(from, from_offs, SEEK_SET) != from_offs)
1035 goto out;
1036
1037 while (len) {
1038 n = page_size;
1039 if (len < n)
1040 n = len;
1041 /* Use read because mmap won't work on proc files */
1042 r = read(from, buf, n);
1043 if (r < 0)
1044 goto out;
1045 if (!r)
1046 break;
1047 n = r;
1048 r = write(to, buf, n);
1049 if (r < 0)
1050 goto out;
1051 if ((size_t)r != n)
1052 goto out;
1053 len -= n;
1054 }
1055
1056 err = 0;
1057out:
1058 free(buf);
1059 return err;
1060}
1061
1062struct kcore {
1063 int fd;
1064 int elfclass;
1065 Elf *elf;
1066 GElf_Ehdr ehdr;
1067};
1068
1069static int kcore__open(struct kcore *kcore, const char *filename)
1070{
1071 GElf_Ehdr *ehdr;
1072
1073 kcore->fd = open(filename, O_RDONLY);
1074 if (kcore->fd == -1)
1075 return -1;
1076
1077 kcore->elf = elf_begin(kcore->fd, ELF_C_READ, NULL);
1078 if (!kcore->elf)
1079 goto out_close;
1080
1081 kcore->elfclass = gelf_getclass(kcore->elf);
1082 if (kcore->elfclass == ELFCLASSNONE)
1083 goto out_end;
1084
1085 ehdr = gelf_getehdr(kcore->elf, &kcore->ehdr);
1086 if (!ehdr)
1087 goto out_end;
1088
1089 return 0;
1090
1091out_end:
1092 elf_end(kcore->elf);
1093out_close:
1094 close(kcore->fd);
1095 return -1;
1096}
1097
1098static int kcore__init(struct kcore *kcore, char *filename, int elfclass,
1099 bool temp)
1100{
1101 GElf_Ehdr *ehdr;
1102
1103 kcore->elfclass = elfclass;
1104
1105 if (temp)
1106 kcore->fd = mkstemp(filename);
1107 else
1108 kcore->fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400);
1109 if (kcore->fd == -1)
1110 return -1;
1111
1112 kcore->elf = elf_begin(kcore->fd, ELF_C_WRITE, NULL);
1113 if (!kcore->elf)
1114 goto out_close;
1115
1116 if (!gelf_newehdr(kcore->elf, elfclass))
1117 goto out_end;
1118
1119 ehdr = gelf_getehdr(kcore->elf, &kcore->ehdr);
1120 if (!ehdr)
1121 goto out_end;
1122
1123 return 0;
1124
1125out_end:
1126 elf_end(kcore->elf);
1127out_close:
1128 close(kcore->fd);
1129 unlink(filename);
1130 return -1;
1131}
1132
1133static void kcore__close(struct kcore *kcore)
1134{
1135 elf_end(kcore->elf);
1136 close(kcore->fd);
1137}
1138
1139static int kcore__copy_hdr(struct kcore *from, struct kcore *to, size_t count)
1140{
1141 GElf_Ehdr *ehdr = &to->ehdr;
1142 GElf_Ehdr *kehdr = &from->ehdr;
1143
1144 memcpy(ehdr->e_ident, kehdr->e_ident, EI_NIDENT);
1145 ehdr->e_type = kehdr->e_type;
1146 ehdr->e_machine = kehdr->e_machine;
1147 ehdr->e_version = kehdr->e_version;
1148 ehdr->e_entry = 0;
1149 ehdr->e_shoff = 0;
1150 ehdr->e_flags = kehdr->e_flags;
1151 ehdr->e_phnum = count;
1152 ehdr->e_shentsize = 0;
1153 ehdr->e_shnum = 0;
1154 ehdr->e_shstrndx = 0;
1155
1156 if (from->elfclass == ELFCLASS32) {
1157 ehdr->e_phoff = sizeof(Elf32_Ehdr);
1158 ehdr->e_ehsize = sizeof(Elf32_Ehdr);
1159 ehdr->e_phentsize = sizeof(Elf32_Phdr);
1160 } else {
1161 ehdr->e_phoff = sizeof(Elf64_Ehdr);
1162 ehdr->e_ehsize = sizeof(Elf64_Ehdr);
1163 ehdr->e_phentsize = sizeof(Elf64_Phdr);
1164 }
1165
1166 if (!gelf_update_ehdr(to->elf, ehdr))
1167 return -1;
1168
1169 if (!gelf_newphdr(to->elf, count))
1170 return -1;
1171
1172 return 0;
1173}
1174
1175static int kcore__add_phdr(struct kcore *kcore, int idx, off_t offset,
1176 u64 addr, u64 len)
1177{
1178 GElf_Phdr gphdr;
1179 GElf_Phdr *phdr;
1180
1181 phdr = gelf_getphdr(kcore->elf, idx, &gphdr);
1182 if (!phdr)
1183 return -1;
1184
1185 phdr->p_type = PT_LOAD;
1186 phdr->p_flags = PF_R | PF_W | PF_X;
1187 phdr->p_offset = offset;
1188 phdr->p_vaddr = addr;
1189 phdr->p_paddr = 0;
1190 phdr->p_filesz = len;
1191 phdr->p_memsz = len;
1192 phdr->p_align = page_size;
1193
1194 if (!gelf_update_phdr(kcore->elf, idx, phdr))
1195 return -1;
1196
1197 return 0;
1198}
1199
1200static off_t kcore__write(struct kcore *kcore)
1201{
1202 return elf_update(kcore->elf, ELF_C_WRITE);
1203}
1204
1205struct phdr_data {
1206 off_t offset;
1207 u64 addr;
1208 u64 len;
1209};
1210
1211struct kcore_copy_info {
1212 u64 stext;
1213 u64 etext;
1214 u64 first_symbol;
1215 u64 last_symbol;
1216 u64 first_module;
1217 u64 last_module_symbol;
1218 struct phdr_data kernel_map;
1219 struct phdr_data modules_map;
1220};
1221
1222static int kcore_copy__process_kallsyms(void *arg, const char *name, char type,
1223 u64 start)
1224{
1225 struct kcore_copy_info *kci = arg;
1226
1227 if (!symbol_type__is_a(type, MAP__FUNCTION))
1228 return 0;
1229
1230 if (strchr(name, '[')) {
1231 if (start > kci->last_module_symbol)
1232 kci->last_module_symbol = start;
1233 return 0;
1234 }
1235
1236 if (!kci->first_symbol || start < kci->first_symbol)
1237 kci->first_symbol = start;
1238
1239 if (!kci->last_symbol || start > kci->last_symbol)
1240 kci->last_symbol = start;
1241
1242 if (!strcmp(name, "_stext")) {
1243 kci->stext = start;
1244 return 0;
1245 }
1246
1247 if (!strcmp(name, "_etext")) {
1248 kci->etext = start;
1249 return 0;
1250 }
1251
1252 return 0;
1253}
1254
1255static int kcore_copy__parse_kallsyms(struct kcore_copy_info *kci,
1256 const char *dir)
1257{
1258 char kallsyms_filename[PATH_MAX];
1259
1260 scnprintf(kallsyms_filename, PATH_MAX, "%s/kallsyms", dir);
1261
1262 if (symbol__restricted_filename(kallsyms_filename, "/proc/kallsyms"))
1263 return -1;
1264
1265 if (kallsyms__parse(kallsyms_filename, kci,
1266 kcore_copy__process_kallsyms) < 0)
1267 return -1;
1268
1269 return 0;
1270}
1271
1272static int kcore_copy__process_modules(void *arg,
1273 const char *name __maybe_unused,
1274 u64 start)
1275{
1276 struct kcore_copy_info *kci = arg;
1277
1278 if (!kci->first_module || start < kci->first_module)
1279 kci->first_module = start;
1280
1281 return 0;
1282}
1283
1284static int kcore_copy__parse_modules(struct kcore_copy_info *kci,
1285 const char *dir)
1286{
1287 char modules_filename[PATH_MAX];
1288
1289 scnprintf(modules_filename, PATH_MAX, "%s/modules", dir);
1290
1291 if (symbol__restricted_filename(modules_filename, "/proc/modules"))
1292 return -1;
1293
1294 if (modules__parse(modules_filename, kci,
1295 kcore_copy__process_modules) < 0)
1296 return -1;
1297
1298 return 0;
1299}
1300
1301static void kcore_copy__map(struct phdr_data *p, u64 start, u64 end, u64 pgoff,
1302 u64 s, u64 e)
1303{
1304 if (p->addr || s < start || s >= end)
1305 return;
1306
1307 p->addr = s;
1308 p->offset = (s - start) + pgoff;
1309 p->len = e < end ? e - s : end - s;
1310}
1311
1312static int kcore_copy__read_map(u64 start, u64 len, u64 pgoff, void *data)
1313{
1314 struct kcore_copy_info *kci = data;
1315 u64 end = start + len;
1316
1317 kcore_copy__map(&kci->kernel_map, start, end, pgoff, kci->stext,
1318 kci->etext);
1319
1320 kcore_copy__map(&kci->modules_map, start, end, pgoff, kci->first_module,
1321 kci->last_module_symbol);
1322
1323 return 0;
1324}
1325
1326static int kcore_copy__read_maps(struct kcore_copy_info *kci, Elf *elf)
1327{
1328 if (elf_read_maps(elf, true, kcore_copy__read_map, kci) < 0)
1329 return -1;
1330
1331 return 0;
1332}
1333
1334static int kcore_copy__calc_maps(struct kcore_copy_info *kci, const char *dir,
1335 Elf *elf)
1336{
1337 if (kcore_copy__parse_kallsyms(kci, dir))
1338 return -1;
1339
1340 if (kcore_copy__parse_modules(kci, dir))
1341 return -1;
1342
1343 if (kci->stext)
1344 kci->stext = round_down(kci->stext, page_size);
1345 else
1346 kci->stext = round_down(kci->first_symbol, page_size);
1347
1348 if (kci->etext) {
1349 kci->etext = round_up(kci->etext, page_size);
1350 } else if (kci->last_symbol) {
1351 kci->etext = round_up(kci->last_symbol, page_size);
1352 kci->etext += page_size;
1353 }
1354
1355 kci->first_module = round_down(kci->first_module, page_size);
1356
1357 if (kci->last_module_symbol) {
1358 kci->last_module_symbol = round_up(kci->last_module_symbol,
1359 page_size);
1360 kci->last_module_symbol += page_size;
1361 }
1362
1363 if (!kci->stext || !kci->etext)
1364 return -1;
1365
1366 if (kci->first_module && !kci->last_module_symbol)
1367 return -1;
1368
1369 return kcore_copy__read_maps(kci, elf);
1370}
1371
1372static int kcore_copy__copy_file(const char *from_dir, const char *to_dir,
1373 const char *name)
1374{
1375 char from_filename[PATH_MAX];
1376 char to_filename[PATH_MAX];
1377
1378 scnprintf(from_filename, PATH_MAX, "%s/%s", from_dir, name);
1379 scnprintf(to_filename, PATH_MAX, "%s/%s", to_dir, name);
1380
1381 return copyfile_mode(from_filename, to_filename, 0400);
1382}
1383
1384static int kcore_copy__unlink(const char *dir, const char *name)
1385{
1386 char filename[PATH_MAX];
1387
1388 scnprintf(filename, PATH_MAX, "%s/%s", dir, name);
1389
1390 return unlink(filename);
1391}
1392
1393static int kcore_copy__compare_fds(int from, int to)
1394{
1395 char *buf_from;
1396 char *buf_to;
1397 ssize_t ret;
1398 size_t len;
1399 int err = -1;
1400
1401 buf_from = malloc(page_size);
1402 buf_to = malloc(page_size);
1403 if (!buf_from || !buf_to)
1404 goto out;
1405
1406 while (1) {
1407 /* Use read because mmap won't work on proc files */
1408 ret = read(from, buf_from, page_size);
1409 if (ret < 0)
1410 goto out;
1411
1412 if (!ret)
1413 break;
1414
1415 len = ret;
1416
1417 if (readn(to, buf_to, len) != (int)len)
1418 goto out;
1419
1420 if (memcmp(buf_from, buf_to, len))
1421 goto out;
1422 }
1423
1424 err = 0;
1425out:
1426 free(buf_to);
1427 free(buf_from);
1428 return err;
1429}
1430
1431static int kcore_copy__compare_files(const char *from_filename,
1432 const char *to_filename)
1433{
1434 int from, to, err = -1;
1435
1436 from = open(from_filename, O_RDONLY);
1437 if (from < 0)
1438 return -1;
1439
1440 to = open(to_filename, O_RDONLY);
1441 if (to < 0)
1442 goto out_close_from;
1443
1444 err = kcore_copy__compare_fds(from, to);
1445
1446 close(to);
1447out_close_from:
1448 close(from);
1449 return err;
1450}
1451
1452static int kcore_copy__compare_file(const char *from_dir, const char *to_dir,
1453 const char *name)
1454{
1455 char from_filename[PATH_MAX];
1456 char to_filename[PATH_MAX];
1457
1458 scnprintf(from_filename, PATH_MAX, "%s/%s", from_dir, name);
1459 scnprintf(to_filename, PATH_MAX, "%s/%s", to_dir, name);
1460
1461 return kcore_copy__compare_files(from_filename, to_filename);
1462}
1463
1464/**
1465 * kcore_copy - copy kallsyms, modules and kcore from one directory to another.
1466 * @from_dir: from directory
1467 * @to_dir: to directory
1468 *
1469 * This function copies kallsyms, modules and kcore files from one directory to
1470 * another. kallsyms and modules are copied entirely. Only code segments are
1471 * copied from kcore. It is assumed that two segments suffice: one for the
1472 * kernel proper and one for all the modules. The code segments are determined
1473 * from kallsyms and modules files. The kernel map starts at _stext or the
1474 * lowest function symbol, and ends at _etext or the highest function symbol.
1475 * The module map starts at the lowest module address and ends at the highest
1476 * module symbol. Start addresses are rounded down to the nearest page. End
1477 * addresses are rounded up to the nearest page. An extra page is added to the
1478 * highest kernel symbol and highest module symbol to, hopefully, encompass that
1479 * symbol too. Because it contains only code sections, the resulting kcore is
1480 * unusual. One significant peculiarity is that the mapping (start -> pgoff)
1481 * is not the same for the kernel map and the modules map. That happens because
1482 * the data is copied adjacently whereas the original kcore has gaps. Finally,
1483 * kallsyms and modules files are compared with their copies to check that
1484 * modules have not been loaded or unloaded while the copies were taking place.
1485 *
1486 * Return: %0 on success, %-1 on failure.
1487 */
1488int kcore_copy(const char *from_dir, const char *to_dir)
1489{
1490 struct kcore kcore;
1491 struct kcore extract;
1492 size_t count = 2;
1493 int idx = 0, err = -1;
1494 off_t offset = page_size, sz, modules_offset = 0;
1495 struct kcore_copy_info kci = { .stext = 0, };
1496 char kcore_filename[PATH_MAX];
1497 char extract_filename[PATH_MAX];
1498
1499 if (kcore_copy__copy_file(from_dir, to_dir, "kallsyms"))
1500 return -1;
1501
1502 if (kcore_copy__copy_file(from_dir, to_dir, "modules"))
1503 goto out_unlink_kallsyms;
1504
1505 scnprintf(kcore_filename, PATH_MAX, "%s/kcore", from_dir);
1506 scnprintf(extract_filename, PATH_MAX, "%s/kcore", to_dir);
1507
1508 if (kcore__open(&kcore, kcore_filename))
1509 goto out_unlink_modules;
1510
1511 if (kcore_copy__calc_maps(&kci, from_dir, kcore.elf))
1512 goto out_kcore_close;
1513
1514 if (kcore__init(&extract, extract_filename, kcore.elfclass, false))
1515 goto out_kcore_close;
1516
1517 if (!kci.modules_map.addr)
1518 count -= 1;
1519
1520 if (kcore__copy_hdr(&kcore, &extract, count))
1521 goto out_extract_close;
1522
1523 if (kcore__add_phdr(&extract, idx++, offset, kci.kernel_map.addr,
1524 kci.kernel_map.len))
1525 goto out_extract_close;
1526
1527 if (kci.modules_map.addr) {
1528 modules_offset = offset + kci.kernel_map.len;
1529 if (kcore__add_phdr(&extract, idx, modules_offset,
1530 kci.modules_map.addr, kci.modules_map.len))
1531 goto out_extract_close;
1532 }
1533
1534 sz = kcore__write(&extract);
1535 if (sz < 0 || sz > offset)
1536 goto out_extract_close;
1537
1538 if (copy_bytes(kcore.fd, kci.kernel_map.offset, extract.fd, offset,
1539 kci.kernel_map.len))
1540 goto out_extract_close;
1541
1542 if (modules_offset && copy_bytes(kcore.fd, kci.modules_map.offset,
1543 extract.fd, modules_offset,
1544 kci.modules_map.len))
1545 goto out_extract_close;
1546
1547 if (kcore_copy__compare_file(from_dir, to_dir, "modules"))
1548 goto out_extract_close;
1549
1550 if (kcore_copy__compare_file(from_dir, to_dir, "kallsyms"))
1551 goto out_extract_close;
1552
1553 err = 0;
1554
1555out_extract_close:
1556 kcore__close(&extract);
1557 if (err)
1558 unlink(extract_filename);
1559out_kcore_close:
1560 kcore__close(&kcore);
1561out_unlink_modules:
1562 if (err)
1563 kcore_copy__unlink(to_dir, "modules");
1564out_unlink_kallsyms:
1565 if (err)
1566 kcore_copy__unlink(to_dir, "kallsyms");
1567
1568 return err;
1569}
1570
1571int kcore_extract__create(struct kcore_extract *kce)
1572{
1573 struct kcore kcore;
1574 struct kcore extract;
1575 size_t count = 1;
1576 int idx = 0, err = -1;
1577 off_t offset = page_size, sz;
1578
1579 if (kcore__open(&kcore, kce->kcore_filename))
1580 return -1;
1581
1582 strcpy(kce->extract_filename, PERF_KCORE_EXTRACT);
1583 if (kcore__init(&extract, kce->extract_filename, kcore.elfclass, true))
1584 goto out_kcore_close;
1585
1586 if (kcore__copy_hdr(&kcore, &extract, count))
1587 goto out_extract_close;
1588
1589 if (kcore__add_phdr(&extract, idx, offset, kce->addr, kce->len))
1590 goto out_extract_close;
1591
1592 sz = kcore__write(&extract);
1593 if (sz < 0 || sz > offset)
1594 goto out_extract_close;
1595
1596 if (copy_bytes(kcore.fd, kce->offs, extract.fd, offset, kce->len))
1597 goto out_extract_close;
1598
1599 err = 0;
1600
1601out_extract_close:
1602 kcore__close(&extract);
1603 if (err)
1604 unlink(kce->extract_filename);
1605out_kcore_close:
1606 kcore__close(&kcore);
1607
1608 return err;
1609}
1610
1611void kcore_extract__delete(struct kcore_extract *kce)
1612{
1613 unlink(kce->extract_filename);
1614}
1615
1021void symbol__elf_init(void) 1616void symbol__elf_init(void)
1022{ 1617{
1023 elf_version(EV_CURRENT); 1618 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 3a802c300fc5..2d2dd0532b5a 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -308,6 +308,21 @@ int file__read_maps(int fd __maybe_unused, bool exe __maybe_unused,
308 return -1; 308 return -1;
309} 309}
310 310
311int kcore_extract__create(struct kcore_extract *kce __maybe_unused)
312{
313 return -1;
314}
315
316void kcore_extract__delete(struct kcore_extract *kce __maybe_unused)
317{
318}
319
320int kcore_copy(const char *from_dir __maybe_unused,
321 const char *to_dir __maybe_unused)
322{
323 return -1;
324}
325
311void symbol__elf_init(void) 326void symbol__elf_init(void)
312{ 327{
313} 328}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 7eb0362f4ffd..c0c36965fff0 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -51,6 +51,7 @@ static enum dso_binary_type binary_type_symtab[] = {
51 DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 51 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
52 DSO_BINARY_TYPE__GUEST_KMODULE, 52 DSO_BINARY_TYPE__GUEST_KMODULE,
53 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 53 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
54 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
54 DSO_BINARY_TYPE__NOT_FOUND, 55 DSO_BINARY_TYPE__NOT_FOUND,
55}; 56};
56 57
@@ -159,10 +160,12 @@ again:
159 160
160 if (choose_best_symbol(curr, next) == SYMBOL_A) { 161 if (choose_best_symbol(curr, next) == SYMBOL_A) {
161 rb_erase(&next->rb_node, symbols); 162 rb_erase(&next->rb_node, symbols);
163 symbol__delete(next);
162 goto again; 164 goto again;
163 } else { 165 } else {
164 nd = rb_next(&curr->rb_node); 166 nd = rb_next(&curr->rb_node);
165 rb_erase(&curr->rb_node, symbols); 167 rb_erase(&curr->rb_node, symbols);
168 symbol__delete(curr);
166 } 169 }
167 } 170 }
168} 171}
@@ -499,6 +502,64 @@ out_failure:
499 return -1; 502 return -1;
500} 503}
501 504
505int modules__parse(const char *filename, void *arg,
506 int (*process_module)(void *arg, const char *name,
507 u64 start))
508{
509 char *line = NULL;
510 size_t n;
511 FILE *file;
512 int err = 0;
513
514 file = fopen(filename, "r");
515 if (file == NULL)
516 return -1;
517
518 while (1) {
519 char name[PATH_MAX];
520 u64 start;
521 char *sep;
522 ssize_t line_len;
523
524 line_len = getline(&line, &n, file);
525 if (line_len < 0) {
526 if (feof(file))
527 break;
528 err = -1;
529 goto out;
530 }
531
532 if (!line) {
533 err = -1;
534 goto out;
535 }
536
537 line[--line_len] = '\0'; /* \n */
538
539 sep = strrchr(line, 'x');
540 if (sep == NULL)
541 continue;
542
543 hex2u64(sep + 1, &start);
544
545 sep = strchr(line, ' ');
546 if (sep == NULL)
547 continue;
548
549 *sep = '\0';
550
551 scnprintf(name, sizeof(name), "[%s]", line);
552
553 err = process_module(arg, name, start);
554 if (err)
555 break;
556 }
557out:
558 free(line);
559 fclose(file);
560 return err;
561}
562
502struct process_kallsyms_args { 563struct process_kallsyms_args {
503 struct map *map; 564 struct map *map;
504 struct dso *dso; 565 struct dso *dso;
@@ -739,51 +800,242 @@ bool symbol__restricted_filename(const char *filename,
739 return restricted; 800 return restricted;
740} 801}
741 802
742struct kcore_mapfn_data { 803struct module_info {
743 struct dso *dso; 804 struct rb_node rb_node;
744 enum map_type type; 805 char *name;
745 struct list_head maps; 806 u64 start;
746}; 807};
747 808
748static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 809static void add_module(struct module_info *mi, struct rb_root *modules)
749{ 810{
750 struct kcore_mapfn_data *md = data; 811 struct rb_node **p = &modules->rb_node;
751 struct map *map; 812 struct rb_node *parent = NULL;
813 struct module_info *m;
752 814
753 map = map__new2(start, md->dso, md->type); 815 while (*p != NULL) {
754 if (map == NULL) 816 parent = *p;
817 m = rb_entry(parent, struct module_info, rb_node);
818 if (strcmp(mi->name, m->name) < 0)
819 p = &(*p)->rb_left;
820 else
821 p = &(*p)->rb_right;
822 }
823 rb_link_node(&mi->rb_node, parent, p);
824 rb_insert_color(&mi->rb_node, modules);
825}
826
827static void delete_modules(struct rb_root *modules)
828{
829 struct module_info *mi;
830 struct rb_node *next = rb_first(modules);
831
832 while (next) {
833 mi = rb_entry(next, struct module_info, rb_node);
834 next = rb_next(&mi->rb_node);
835 rb_erase(&mi->rb_node, modules);
836 free(mi->name);
837 free(mi);
838 }
839}
840
841static struct module_info *find_module(const char *name,
842 struct rb_root *modules)
843{
844 struct rb_node *n = modules->rb_node;
845
846 while (n) {
847 struct module_info *m;
848 int cmp;
849
850 m = rb_entry(n, struct module_info, rb_node);
851 cmp = strcmp(name, m->name);
852 if (cmp < 0)
853 n = n->rb_left;
854 else if (cmp > 0)
855 n = n->rb_right;
856 else
857 return m;
858 }
859
860 return NULL;
861}
862
863static int __read_proc_modules(void *arg, const char *name, u64 start)
864{
865 struct rb_root *modules = arg;
866 struct module_info *mi;
867
868 mi = zalloc(sizeof(struct module_info));
869 if (!mi)
755 return -ENOMEM; 870 return -ENOMEM;
756 871
757 map->end = map->start + len; 872 mi->name = strdup(name);
758 map->pgoff = pgoff; 873 mi->start = start;
759 874
760 list_add(&map->node, &md->maps); 875 if (!mi->name) {
876 free(mi);
877 return -ENOMEM;
878 }
879
880 add_module(mi, modules);
881
882 return 0;
883}
884
885static int read_proc_modules(const char *filename, struct rb_root *modules)
886{
887 if (symbol__restricted_filename(filename, "/proc/modules"))
888 return -1;
889
890 if (modules__parse(filename, modules, __read_proc_modules)) {
891 delete_modules(modules);
892 return -1;
893 }
761 894
762 return 0; 895 return 0;
763} 896}
764 897
898int compare_proc_modules(const char *from, const char *to)
899{
900 struct rb_root from_modules = RB_ROOT;
901 struct rb_root to_modules = RB_ROOT;
902 struct rb_node *from_node, *to_node;
903 struct module_info *from_m, *to_m;
904 int ret = -1;
905
906 if (read_proc_modules(from, &from_modules))
907 return -1;
908
909 if (read_proc_modules(to, &to_modules))
910 goto out_delete_from;
911
912 from_node = rb_first(&from_modules);
913 to_node = rb_first(&to_modules);
914 while (from_node) {
915 if (!to_node)
916 break;
917
918 from_m = rb_entry(from_node, struct module_info, rb_node);
919 to_m = rb_entry(to_node, struct module_info, rb_node);
920
921 if (from_m->start != to_m->start ||
922 strcmp(from_m->name, to_m->name))
923 break;
924
925 from_node = rb_next(from_node);
926 to_node = rb_next(to_node);
927 }
928
929 if (!from_node && !to_node)
930 ret = 0;
931
932 delete_modules(&to_modules);
933out_delete_from:
934 delete_modules(&from_modules);
935
936 return ret;
937}
938
939static int do_validate_kcore_modules(const char *filename, struct map *map,
940 struct map_groups *kmaps)
941{
942 struct rb_root modules = RB_ROOT;
943 struct map *old_map;
944 int err;
945
946 err = read_proc_modules(filename, &modules);
947 if (err)
948 return err;
949
950 old_map = map_groups__first(kmaps, map->type);
951 while (old_map) {
952 struct map *next = map_groups__next(old_map);
953 struct module_info *mi;
954
955 if (old_map == map || old_map->start == map->start) {
956 /* The kernel map */
957 old_map = next;
958 continue;
959 }
960
961 /* Module must be in memory at the same address */
962 mi = find_module(old_map->dso->short_name, &modules);
963 if (!mi || mi->start != old_map->start) {
964 err = -EINVAL;
965 goto out;
966 }
967
968 old_map = next;
969 }
970out:
971 delete_modules(&modules);
972 return err;
973}
974
765/* 975/*
766 * If kallsyms is referenced by name then we look for kcore in the same 976 * If kallsyms is referenced by name then we look for filename in the same
767 * directory. 977 * directory.
768 */ 978 */
769static bool kcore_filename_from_kallsyms_filename(char *kcore_filename, 979static bool filename_from_kallsyms_filename(char *filename,
770 const char *kallsyms_filename) 980 const char *base_name,
981 const char *kallsyms_filename)
771{ 982{
772 char *name; 983 char *name;
773 984
774 strcpy(kcore_filename, kallsyms_filename); 985 strcpy(filename, kallsyms_filename);
775 name = strrchr(kcore_filename, '/'); 986 name = strrchr(filename, '/');
776 if (!name) 987 if (!name)
777 return false; 988 return false;
778 989
779 if (!strcmp(name, "/kallsyms")) { 990 name += 1;
780 strcpy(name, "/kcore"); 991
992 if (!strcmp(name, "kallsyms")) {
993 strcpy(name, base_name);
781 return true; 994 return true;
782 } 995 }
783 996
784 return false; 997 return false;
785} 998}
786 999
1000static int validate_kcore_modules(const char *kallsyms_filename,
1001 struct map *map)
1002{
1003 struct map_groups *kmaps = map__kmap(map)->kmaps;
1004 char modules_filename[PATH_MAX];
1005
1006 if (!filename_from_kallsyms_filename(modules_filename, "modules",
1007 kallsyms_filename))
1008 return -EINVAL;
1009
1010 if (do_validate_kcore_modules(modules_filename, map, kmaps))
1011 return -EINVAL;
1012
1013 return 0;
1014}
1015
1016struct kcore_mapfn_data {
1017 struct dso *dso;
1018 enum map_type type;
1019 struct list_head maps;
1020};
1021
1022static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
1023{
1024 struct kcore_mapfn_data *md = data;
1025 struct map *map;
1026
1027 map = map__new2(start, md->dso, md->type);
1028 if (map == NULL)
1029 return -ENOMEM;
1030
1031 map->end = map->start + len;
1032 map->pgoff = pgoff;
1033
1034 list_add(&map->node, &md->maps);
1035
1036 return 0;
1037}
1038
787static int dso__load_kcore(struct dso *dso, struct map *map, 1039static int dso__load_kcore(struct dso *dso, struct map *map,
788 const char *kallsyms_filename) 1040 const char *kallsyms_filename)
789{ 1041{
@@ -800,8 +1052,12 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
800 if (map != machine->vmlinux_maps[map->type]) 1052 if (map != machine->vmlinux_maps[map->type])
801 return -EINVAL; 1053 return -EINVAL;
802 1054
803 if (!kcore_filename_from_kallsyms_filename(kcore_filename, 1055 if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
804 kallsyms_filename)) 1056 kallsyms_filename))
1057 return -EINVAL;
1058
1059 /* All modules must be present at their original addresses */
1060 if (validate_kcore_modules(kallsyms_filename, map))
805 return -EINVAL; 1061 return -EINVAL;
806 1062
807 md.dso = dso; 1063 md.dso = dso;
@@ -1188,6 +1444,105 @@ out:
1188 return err; 1444 return err;
1189} 1445}
1190 1446
1447static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
1448{
1449 char kallsyms_filename[PATH_MAX];
1450 struct dirent *dent;
1451 int ret = -1;
1452 DIR *d;
1453
1454 d = opendir(dir);
1455 if (!d)
1456 return -1;
1457
1458 while (1) {
1459 dent = readdir(d);
1460 if (!dent)
1461 break;
1462 if (dent->d_type != DT_DIR)
1463 continue;
1464 scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
1465 "%s/%s/kallsyms", dir, dent->d_name);
1466 if (!validate_kcore_modules(kallsyms_filename, map)) {
1467 strlcpy(dir, kallsyms_filename, dir_sz);
1468 ret = 0;
1469 break;
1470 }
1471 }
1472
1473 closedir(d);
1474
1475 return ret;
1476}
1477
1478static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1479{
1480 u8 host_build_id[BUILD_ID_SIZE];
1481 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1482 bool is_host = false;
1483 char path[PATH_MAX];
1484
1485 if (!dso->has_build_id) {
1486 /*
1487 * Last resort, if we don't have a build-id and couldn't find
1488 * any vmlinux file, try the running kernel kallsyms table.
1489 */
1490 goto proc_kallsyms;
1491 }
1492
1493 if (sysfs__read_build_id("/sys/kernel/notes", host_build_id,
1494 sizeof(host_build_id)) == 0)
1495 is_host = dso__build_id_equal(dso, host_build_id);
1496
1497 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
1498
1499 /* Use /proc/kallsyms if possible */
1500 if (is_host) {
1501 DIR *d;
1502 int fd;
1503
1504 /* If no cached kcore go with /proc/kallsyms */
1505 scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s",
1506 buildid_dir, sbuild_id);
1507 d = opendir(path);
1508 if (!d)
1509 goto proc_kallsyms;
1510 closedir(d);
1511
1512 /*
1513 * Do not check the build-id cache, until we know we cannot use
1514 * /proc/kcore.
1515 */
1516 fd = open("/proc/kcore", O_RDONLY);
1517 if (fd != -1) {
1518 close(fd);
1519 /* If module maps match go with /proc/kallsyms */
1520 if (!validate_kcore_modules("/proc/kallsyms", map))
1521 goto proc_kallsyms;
1522 }
1523
1524 /* Find kallsyms in build-id cache with kcore */
1525 if (!find_matching_kcore(map, path, sizeof(path)))
1526 return strdup(path);
1527
1528 goto proc_kallsyms;
1529 }
1530
1531 scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
1532 buildid_dir, sbuild_id);
1533
1534 if (access(path, F_OK)) {
1535 pr_err("No kallsyms or vmlinux with build-id %s was found\n",
1536 sbuild_id);
1537 return NULL;
1538 }
1539
1540 return strdup(path);
1541
1542proc_kallsyms:
1543 return strdup("/proc/kallsyms");
1544}
1545
1191static int dso__load_kernel_sym(struct dso *dso, struct map *map, 1546static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1192 symbol_filter_t filter) 1547 symbol_filter_t filter)
1193{ 1548{
@@ -1214,7 +1569,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1214 goto do_kallsyms; 1569 goto do_kallsyms;
1215 } 1570 }
1216 1571
1217 if (symbol_conf.vmlinux_name != NULL) { 1572 if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
1218 err = dso__load_vmlinux(dso, map, 1573 err = dso__load_vmlinux(dso, map,
1219 symbol_conf.vmlinux_name, filter); 1574 symbol_conf.vmlinux_name, filter);
1220 if (err > 0) { 1575 if (err > 0) {
@@ -1226,7 +1581,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1226 return err; 1581 return err;
1227 } 1582 }
1228 1583
1229 if (vmlinux_path != NULL) { 1584 if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
1230 err = dso__load_vmlinux_path(dso, map, filter); 1585 err = dso__load_vmlinux_path(dso, map, filter);
1231 if (err > 0) 1586 if (err > 0)
1232 return err; 1587 return err;
@@ -1236,51 +1591,11 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1236 if (symbol_conf.symfs[0] != 0) 1591 if (symbol_conf.symfs[0] != 0)
1237 return -1; 1592 return -1;
1238 1593
1239 /* 1594 kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
1240 * Say the kernel DSO was created when processing the build-id header table, 1595 if (!kallsyms_allocated_filename)
1241 * we have a build-id, so check if it is the same as the running kernel, 1596 return -1;
1242 * using it if it is.
1243 */
1244 if (dso->has_build_id) {
1245 u8 kallsyms_build_id[BUILD_ID_SIZE];
1246 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1247
1248 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1249 sizeof(kallsyms_build_id)) == 0) {
1250 if (dso__build_id_equal(dso, kallsyms_build_id)) {
1251 kallsyms_filename = "/proc/kallsyms";
1252 goto do_kallsyms;
1253 }
1254 }
1255 /*
1256 * Now look if we have it on the build-id cache in
1257 * $HOME/.debug/[kernel.kallsyms].
1258 */
1259 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
1260 sbuild_id);
1261
1262 if (asprintf(&kallsyms_allocated_filename,
1263 "%s/.debug/[kernel.kallsyms]/%s",
1264 getenv("HOME"), sbuild_id) == -1) {
1265 pr_err("Not enough memory for kallsyms file lookup\n");
1266 return -1;
1267 }
1268
1269 kallsyms_filename = kallsyms_allocated_filename;
1270 1597
1271 if (access(kallsyms_filename, F_OK)) { 1598 kallsyms_filename = kallsyms_allocated_filename;
1272 pr_err("No kallsyms or vmlinux with build-id %s "
1273 "was found\n", sbuild_id);
1274 free(kallsyms_allocated_filename);
1275 return -1;
1276 }
1277 } else {
1278 /*
1279 * Last resort, if we don't have a build-id and couldn't find
1280 * any vmlinux file, try the running kernel kallsyms table.
1281 */
1282 kallsyms_filename = "/proc/kallsyms";
1283 }
1284 1599
1285do_kallsyms: 1600do_kallsyms:
1286 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 1601 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index fd5b70ea2981..07de8fea2f48 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -13,7 +13,7 @@
13#include <libgen.h> 13#include <libgen.h>
14#include "build-id.h" 14#include "build-id.h"
15 15
16#ifdef LIBELF_SUPPORT 16#ifdef HAVE_LIBELF_SUPPORT
17#include <libelf.h> 17#include <libelf.h>
18#include <gelf.h> 18#include <gelf.h>
19#endif 19#endif
@@ -21,7 +21,7 @@
21 21
22#include "dso.h" 22#include "dso.h"
23 23
24#ifdef HAVE_CPLUS_DEMANGLE 24#ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
25extern char *cplus_demangle(const char *, int); 25extern char *cplus_demangle(const char *, int);
26 26
27static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i) 27static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i)
@@ -46,7 +46,7 @@ static inline char *bfd_demangle(void __maybe_unused *v,
46 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; 46 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
47 * for newer versions we can use mmap to reduce memory usage: 47 * for newer versions we can use mmap to reduce memory usage:
48 */ 48 */
49#ifdef LIBELF_MMAP 49#ifdef HAVE_LIBELF_MMAP_SUPPORT
50# define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP 50# define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP
51#else 51#else
52# define PERF_ELF_C_READ_MMAP ELF_C_READ 52# define PERF_ELF_C_READ_MMAP ELF_C_READ
@@ -85,6 +85,7 @@ struct symbol_conf {
85 unsigned short priv_size; 85 unsigned short priv_size;
86 unsigned short nr_events; 86 unsigned short nr_events;
87 bool try_vmlinux_path, 87 bool try_vmlinux_path,
88 ignore_vmlinux,
88 show_kernel_path, 89 show_kernel_path,
89 use_modules, 90 use_modules,
90 sort_by_name, 91 sort_by_name,
@@ -178,7 +179,7 @@ struct symsrc {
178 int fd; 179 int fd;
179 enum dso_binary_type type; 180 enum dso_binary_type type;
180 181
181#ifdef LIBELF_SUPPORT 182#ifdef HAVE_LIBELF_SUPPORT
182 Elf *elf; 183 Elf *elf;
183 GElf_Ehdr ehdr; 184 GElf_Ehdr ehdr;
184 185
@@ -222,6 +223,9 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size);
222int kallsyms__parse(const char *filename, void *arg, 223int kallsyms__parse(const char *filename, void *arg,
223 int (*process_symbol)(void *arg, const char *name, 224 int (*process_symbol)(void *arg, const char *name,
224 char type, u64 start)); 225 char type, u64 start));
226int modules__parse(const char *filename, void *arg,
227 int (*process_module)(void *arg, const char *name,
228 u64 start));
225int filename__read_debuglink(const char *filename, char *debuglink, 229int filename__read_debuglink(const char *filename, char *debuglink,
226 size_t size); 230 size_t size);
227 231
@@ -252,4 +256,21 @@ typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
252int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data, 256int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
253 bool *is_64_bit); 257 bool *is_64_bit);
254 258
259#define PERF_KCORE_EXTRACT "/tmp/perf-kcore-XXXXXX"
260
261struct kcore_extract {
262 char *kcore_filename;
263 u64 addr;
264 u64 offs;
265 u64 len;
266 char extract_filename[sizeof(PERF_KCORE_EXTRACT)];
267 int fd;
268};
269
270int kcore_extract__create(struct kcore_extract *kce);
271void kcore_extract__delete(struct kcore_extract *kce);
272
273int kcore_copy(const char *from_dir, const char *to_dir);
274int compare_proc_modules(const char *from, const char *to);
275
255#endif /* __PERF_SYMBOL */ 276#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
deleted file mode 100644
index f71e9eafe15a..000000000000
--- a/tools/perf/util/sysfs.c
+++ /dev/null
@@ -1,60 +0,0 @@
1
2#include "util.h"
3#include "sysfs.h"
4
5static const char * const sysfs_known_mountpoints[] = {
6 "/sys",
7 0,
8};
9
10static int sysfs_found;
11char sysfs_mountpoint[PATH_MAX + 1];
12
13static int sysfs_valid_mountpoint(const char *sysfs)
14{
15 struct statfs st_fs;
16
17 if (statfs(sysfs, &st_fs) < 0)
18 return -ENOENT;
19 else if (st_fs.f_type != (long) SYSFS_MAGIC)
20 return -ENOENT;
21
22 return 0;
23}
24
25const char *sysfs_find_mountpoint(void)
26{
27 const char * const *ptr;
28 char type[100];
29 FILE *fp;
30
31 if (sysfs_found)
32 return (const char *) sysfs_mountpoint;
33
34 ptr = sysfs_known_mountpoints;
35 while (*ptr) {
36 if (sysfs_valid_mountpoint(*ptr) == 0) {
37 sysfs_found = 1;
38 strcpy(sysfs_mountpoint, *ptr);
39 return sysfs_mountpoint;
40 }
41 ptr++;
42 }
43
44 /* give up and parse /proc/mounts */
45 fp = fopen("/proc/mounts", "r");
46 if (fp == NULL)
47 return NULL;
48
49 while (!sysfs_found &&
50 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
51 sysfs_mountpoint, type) == 2) {
52
53 if (strcmp(type, "sysfs") == 0)
54 sysfs_found = 1;
55 }
56
57 fclose(fp);
58
59 return sysfs_found ? sysfs_mountpoint : NULL;
60}
diff --git a/tools/perf/util/sysfs.h b/tools/perf/util/sysfs.h
deleted file mode 100644
index a813b7203938..000000000000
--- a/tools/perf/util/sysfs.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef __SYSFS_H__
2#define __SYSFS_H__
3
4const char *sysfs_find_mountpoint(void);
5
6#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
index 065528b7563e..3c778a07b7cc 100644
--- a/tools/perf/util/target.c
+++ b/tools/perf/util/target.c
@@ -13,9 +13,9 @@
13#include <string.h> 13#include <string.h>
14 14
15 15
16enum perf_target_errno perf_target__validate(struct perf_target *target) 16enum target_errno target__validate(struct target *target)
17{ 17{
18 enum perf_target_errno ret = PERF_ERRNO_TARGET__SUCCESS; 18 enum target_errno ret = TARGET_ERRNO__SUCCESS;
19 19
20 if (target->pid) 20 if (target->pid)
21 target->tid = target->pid; 21 target->tid = target->pid;
@@ -23,42 +23,42 @@ enum perf_target_errno perf_target__validate(struct perf_target *target)
23 /* CPU and PID are mutually exclusive */ 23 /* CPU and PID are mutually exclusive */
24 if (target->tid && target->cpu_list) { 24 if (target->tid && target->cpu_list) {
25 target->cpu_list = NULL; 25 target->cpu_list = NULL;
26 if (ret == PERF_ERRNO_TARGET__SUCCESS) 26 if (ret == TARGET_ERRNO__SUCCESS)
27 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_CPU; 27 ret = TARGET_ERRNO__PID_OVERRIDE_CPU;
28 } 28 }
29 29
30 /* UID and PID are mutually exclusive */ 30 /* UID and PID are mutually exclusive */
31 if (target->tid && target->uid_str) { 31 if (target->tid && target->uid_str) {
32 target->uid_str = NULL; 32 target->uid_str = NULL;
33 if (ret == PERF_ERRNO_TARGET__SUCCESS) 33 if (ret == TARGET_ERRNO__SUCCESS)
34 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_UID; 34 ret = TARGET_ERRNO__PID_OVERRIDE_UID;
35 } 35 }
36 36
37 /* UID and CPU are mutually exclusive */ 37 /* UID and CPU are mutually exclusive */
38 if (target->uid_str && target->cpu_list) { 38 if (target->uid_str && target->cpu_list) {
39 target->cpu_list = NULL; 39 target->cpu_list = NULL;
40 if (ret == PERF_ERRNO_TARGET__SUCCESS) 40 if (ret == TARGET_ERRNO__SUCCESS)
41 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_CPU; 41 ret = TARGET_ERRNO__UID_OVERRIDE_CPU;
42 } 42 }
43 43
44 /* PID and SYSTEM are mutually exclusive */ 44 /* PID and SYSTEM are mutually exclusive */
45 if (target->tid && target->system_wide) { 45 if (target->tid && target->system_wide) {
46 target->system_wide = false; 46 target->system_wide = false;
47 if (ret == PERF_ERRNO_TARGET__SUCCESS) 47 if (ret == TARGET_ERRNO__SUCCESS)
48 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM; 48 ret = TARGET_ERRNO__PID_OVERRIDE_SYSTEM;
49 } 49 }
50 50
51 /* UID and SYSTEM are mutually exclusive */ 51 /* UID and SYSTEM are mutually exclusive */
52 if (target->uid_str && target->system_wide) { 52 if (target->uid_str && target->system_wide) {
53 target->system_wide = false; 53 target->system_wide = false;
54 if (ret == PERF_ERRNO_TARGET__SUCCESS) 54 if (ret == TARGET_ERRNO__SUCCESS)
55 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM; 55 ret = TARGET_ERRNO__UID_OVERRIDE_SYSTEM;
56 } 56 }
57 57
58 return ret; 58 return ret;
59} 59}
60 60
61enum perf_target_errno perf_target__parse_uid(struct perf_target *target) 61enum target_errno target__parse_uid(struct target *target)
62{ 62{
63 struct passwd pwd, *result; 63 struct passwd pwd, *result;
64 char buf[1024]; 64 char buf[1024];
@@ -66,7 +66,7 @@ enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
66 66
67 target->uid = UINT_MAX; 67 target->uid = UINT_MAX;
68 if (str == NULL) 68 if (str == NULL)
69 return PERF_ERRNO_TARGET__SUCCESS; 69 return TARGET_ERRNO__SUCCESS;
70 70
71 /* Try user name first */ 71 /* Try user name first */
72 getpwnam_r(str, &pwd, buf, sizeof(buf), &result); 72 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
@@ -79,22 +79,22 @@ enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
79 int uid = strtol(str, &endptr, 10); 79 int uid = strtol(str, &endptr, 10);
80 80
81 if (*endptr != '\0') 81 if (*endptr != '\0')
82 return PERF_ERRNO_TARGET__INVALID_UID; 82 return TARGET_ERRNO__INVALID_UID;
83 83
84 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result); 84 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
85 85
86 if (result == NULL) 86 if (result == NULL)
87 return PERF_ERRNO_TARGET__USER_NOT_FOUND; 87 return TARGET_ERRNO__USER_NOT_FOUND;
88 } 88 }
89 89
90 target->uid = result->pw_uid; 90 target->uid = result->pw_uid;
91 return PERF_ERRNO_TARGET__SUCCESS; 91 return TARGET_ERRNO__SUCCESS;
92} 92}
93 93
94/* 94/*
95 * This must have a same ordering as the enum perf_target_errno. 95 * This must have a same ordering as the enum target_errno.
96 */ 96 */
97static const char *perf_target__error_str[] = { 97static const char *target__error_str[] = {
98 "PID/TID switch overriding CPU", 98 "PID/TID switch overriding CPU",
99 "PID/TID switch overriding UID", 99 "PID/TID switch overriding UID",
100 "UID switch overriding CPU", 100 "UID switch overriding CPU",
@@ -104,7 +104,7 @@ static const char *perf_target__error_str[] = {
104 "Problems obtaining information for user %s", 104 "Problems obtaining information for user %s",
105}; 105};
106 106
107int perf_target__strerror(struct perf_target *target, int errnum, 107int target__strerror(struct target *target, int errnum,
108 char *buf, size_t buflen) 108 char *buf, size_t buflen)
109{ 109{
110 int idx; 110 int idx;
@@ -124,21 +124,19 @@ int perf_target__strerror(struct perf_target *target, int errnum,
124 return 0; 124 return 0;
125 } 125 }
126 126
127 if (errnum < __PERF_ERRNO_TARGET__START || 127 if (errnum < __TARGET_ERRNO__START || errnum >= __TARGET_ERRNO__END)
128 errnum >= __PERF_ERRNO_TARGET__END)
129 return -1; 128 return -1;
130 129
131 idx = errnum - __PERF_ERRNO_TARGET__START; 130 idx = errnum - __TARGET_ERRNO__START;
132 msg = perf_target__error_str[idx]; 131 msg = target__error_str[idx];
133 132
134 switch (errnum) { 133 switch (errnum) {
135 case PERF_ERRNO_TARGET__PID_OVERRIDE_CPU 134 case TARGET_ERRNO__PID_OVERRIDE_CPU ... TARGET_ERRNO__UID_OVERRIDE_SYSTEM:
136 ... PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM:
137 snprintf(buf, buflen, "%s", msg); 135 snprintf(buf, buflen, "%s", msg);
138 break; 136 break;
139 137
140 case PERF_ERRNO_TARGET__INVALID_UID: 138 case TARGET_ERRNO__INVALID_UID:
141 case PERF_ERRNO_TARGET__USER_NOT_FOUND: 139 case TARGET_ERRNO__USER_NOT_FOUND:
142 snprintf(buf, buflen, msg, target->uid_str); 140 snprintf(buf, buflen, msg, target->uid_str);
143 break; 141 break;
144 142
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h
index a4be8575fda5..2d0c50690892 100644
--- a/tools/perf/util/target.h
+++ b/tools/perf/util/target.h
@@ -4,7 +4,7 @@
4#include <stdbool.h> 4#include <stdbool.h>
5#include <sys/types.h> 5#include <sys/types.h>
6 6
7struct perf_target { 7struct target {
8 const char *pid; 8 const char *pid;
9 const char *tid; 9 const char *tid;
10 const char *cpu_list; 10 const char *cpu_list;
@@ -12,10 +12,11 @@ struct perf_target {
12 uid_t uid; 12 uid_t uid;
13 bool system_wide; 13 bool system_wide;
14 bool uses_mmap; 14 bool uses_mmap;
15 bool force_per_cpu;
15}; 16};
16 17
17enum perf_target_errno { 18enum target_errno {
18 PERF_ERRNO_TARGET__SUCCESS = 0, 19 TARGET_ERRNO__SUCCESS = 0,
19 20
20 /* 21 /*
21 * Choose an arbitrary negative big number not to clash with standard 22 * Choose an arbitrary negative big number not to clash with standard
@@ -24,42 +25,40 @@ enum perf_target_errno {
24 * 25 *
25 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html 26 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
26 */ 27 */
27 __PERF_ERRNO_TARGET__START = -10000, 28 __TARGET_ERRNO__START = -10000,
28 29
30 /* for target__validate() */
31 TARGET_ERRNO__PID_OVERRIDE_CPU = __TARGET_ERRNO__START,
32 TARGET_ERRNO__PID_OVERRIDE_UID,
33 TARGET_ERRNO__UID_OVERRIDE_CPU,
34 TARGET_ERRNO__PID_OVERRIDE_SYSTEM,
35 TARGET_ERRNO__UID_OVERRIDE_SYSTEM,
29 36
30 /* for perf_target__validate() */ 37 /* for target__parse_uid() */
31 PERF_ERRNO_TARGET__PID_OVERRIDE_CPU = __PERF_ERRNO_TARGET__START, 38 TARGET_ERRNO__INVALID_UID,
32 PERF_ERRNO_TARGET__PID_OVERRIDE_UID, 39 TARGET_ERRNO__USER_NOT_FOUND,
33 PERF_ERRNO_TARGET__UID_OVERRIDE_CPU,
34 PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM,
35 PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM,
36 40
37 /* for perf_target__parse_uid() */ 41 __TARGET_ERRNO__END,
38 PERF_ERRNO_TARGET__INVALID_UID,
39 PERF_ERRNO_TARGET__USER_NOT_FOUND,
40
41 __PERF_ERRNO_TARGET__END,
42}; 42};
43 43
44enum perf_target_errno perf_target__validate(struct perf_target *target); 44enum target_errno target__validate(struct target *target);
45enum perf_target_errno perf_target__parse_uid(struct perf_target *target); 45enum target_errno target__parse_uid(struct target *target);
46 46
47int perf_target__strerror(struct perf_target *target, int errnum, char *buf, 47int target__strerror(struct target *target, int errnum, char *buf, size_t buflen);
48 size_t buflen);
49 48
50static inline bool perf_target__has_task(struct perf_target *target) 49static inline bool target__has_task(struct target *target)
51{ 50{
52 return target->tid || target->pid || target->uid_str; 51 return target->tid || target->pid || target->uid_str;
53} 52}
54 53
55static inline bool perf_target__has_cpu(struct perf_target *target) 54static inline bool target__has_cpu(struct target *target)
56{ 55{
57 return target->system_wide || target->cpu_list; 56 return target->system_wide || target->cpu_list;
58} 57}
59 58
60static inline bool perf_target__none(struct perf_target *target) 59static inline bool target__none(struct target *target)
61{ 60{
62 return !perf_target__has_task(target) && !perf_target__has_cpu(target); 61 return !target__has_task(target) && !target__has_cpu(target);
63} 62}
64 63
65#endif /* _PERF_TARGET_H */ 64#endif /* _PERF_TARGET_H */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index e3d4a550a703..cd8e2f592719 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -6,86 +6,137 @@
6#include "thread.h" 6#include "thread.h"
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9#include "comm.h"
9 10
10struct thread *thread__new(pid_t pid, pid_t tid) 11struct thread *thread__new(pid_t pid, pid_t tid)
11{ 12{
12 struct thread *self = zalloc(sizeof(*self)); 13 char *comm_str;
13 14 struct comm *comm;
14 if (self != NULL) { 15 struct thread *thread = zalloc(sizeof(*thread));
15 map_groups__init(&self->mg); 16
16 self->pid_ = pid; 17 if (thread != NULL) {
17 self->tid = tid; 18 map_groups__init(&thread->mg);
18 self->ppid = -1; 19 thread->pid_ = pid;
19 self->comm = malloc(32); 20 thread->tid = tid;
20 if (self->comm) 21 thread->ppid = -1;
21 snprintf(self->comm, 32, ":%d", self->tid); 22 INIT_LIST_HEAD(&thread->comm_list);
23
24 comm_str = malloc(32);
25 if (!comm_str)
26 goto err_thread;
27
28 snprintf(comm_str, 32, ":%d", tid);
29 comm = comm__new(comm_str, 0);
30 free(comm_str);
31 if (!comm)
32 goto err_thread;
33
34 list_add(&comm->list, &thread->comm_list);
35 }
36
37 return thread;
38
39err_thread:
40 free(thread);
41 return NULL;
42}
43
44void thread__delete(struct thread *thread)
45{
46 struct comm *comm, *tmp;
47
48 map_groups__exit(&thread->mg);
49 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
50 list_del(&comm->list);
51 comm__free(comm);
22 } 52 }
23 53
24 return self; 54 free(thread);
25} 55}
26 56
27void thread__delete(struct thread *self) 57struct comm *thread__comm(const struct thread *thread)
28{ 58{
29 map_groups__exit(&self->mg); 59 if (list_empty(&thread->comm_list))
30 free(self->comm); 60 return NULL;
31 free(self); 61
62 return list_first_entry(&thread->comm_list, struct comm, list);
32} 63}
33 64
34int thread__set_comm(struct thread *self, const char *comm) 65/* CHECKME: time should always be 0 if event aren't ordered */
66int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
35{ 67{
36 int err; 68 struct comm *new, *curr = thread__comm(thread);
37 69
38 if (self->comm) 70 /* Override latest entry if it had no specific time coverage */
39 free(self->comm); 71 if (!curr->start) {
40 self->comm = strdup(comm); 72 comm__override(curr, str, timestamp);
41 err = self->comm == NULL ? -ENOMEM : 0; 73 return 0;
42 if (!err) {
43 self->comm_set = true;
44 } 74 }
45 return err; 75
76 new = comm__new(str, timestamp);
77 if (!new)
78 return -ENOMEM;
79
80 list_add(&new->list, &thread->comm_list);
81 thread->comm_set = true;
82
83 return 0;
84}
85
86const char *thread__comm_str(const struct thread *thread)
87{
88 const struct comm *comm = thread__comm(thread);
89
90 if (!comm)
91 return NULL;
92
93 return comm__str(comm);
46} 94}
47 95
48int thread__comm_len(struct thread *self) 96/* CHECKME: it should probably better return the max comm len from its comm list */
97int thread__comm_len(struct thread *thread)
49{ 98{
50 if (!self->comm_len) { 99 if (!thread->comm_len) {
51 if (!self->comm) 100 const char *comm = thread__comm_str(thread);
101 if (!comm)
52 return 0; 102 return 0;
53 self->comm_len = strlen(self->comm); 103 thread->comm_len = strlen(comm);
54 } 104 }
55 105
56 return self->comm_len; 106 return thread->comm_len;
57} 107}
58 108
59size_t thread__fprintf(struct thread *thread, FILE *fp) 109size_t thread__fprintf(struct thread *thread, FILE *fp)
60{ 110{
61 return fprintf(fp, "Thread %d %s\n", thread->tid, thread->comm) + 111 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
62 map_groups__fprintf(&thread->mg, verbose, fp); 112 map_groups__fprintf(&thread->mg, verbose, fp);
63} 113}
64 114
65void thread__insert_map(struct thread *self, struct map *map) 115void thread__insert_map(struct thread *thread, struct map *map)
66{ 116{
67 map_groups__fixup_overlappings(&self->mg, map, verbose, stderr); 117 map_groups__fixup_overlappings(&thread->mg, map, verbose, stderr);
68 map_groups__insert(&self->mg, map); 118 map_groups__insert(&thread->mg, map);
69} 119}
70 120
71int thread__fork(struct thread *self, struct thread *parent) 121int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
72{ 122{
73 int i; 123 int i, err;
74 124
75 if (parent->comm_set) { 125 if (parent->comm_set) {
76 if (self->comm) 126 const char *comm = thread__comm_str(parent);
77 free(self->comm); 127 if (!comm)
78 self->comm = strdup(parent->comm);
79 if (!self->comm)
80 return -ENOMEM; 128 return -ENOMEM;
81 self->comm_set = true; 129 err = thread__set_comm(thread, comm, timestamp);
130 if (!err)
131 return err;
132 thread->comm_set = true;
82 } 133 }
83 134
84 for (i = 0; i < MAP__NR_TYPES; ++i) 135 for (i = 0; i < MAP__NR_TYPES; ++i)
85 if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 136 if (map_groups__clone(&thread->mg, &parent->mg, i) < 0)
86 return -ENOMEM; 137 return -ENOMEM;
87 138
88 self->ppid = parent->tid; 139 thread->ppid = parent->tid;
89 140
90 return 0; 141 return 0;
91} 142}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 4ebbb40d46d4..897c1b2a750a 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -2,6 +2,7 @@
2#define __PERF_THREAD_H 2#define __PERF_THREAD_H
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <linux/list.h>
5#include <unistd.h> 6#include <unistd.h>
6#include <sys/types.h> 7#include <sys/types.h>
7#include "symbol.h" 8#include "symbol.h"
@@ -18,31 +19,34 @@ struct thread {
18 char shortname[3]; 19 char shortname[3];
19 bool comm_set; 20 bool comm_set;
20 bool dead; /* if set thread has exited */ 21 bool dead; /* if set thread has exited */
21 char *comm; 22 struct list_head comm_list;
22 int comm_len; 23 int comm_len;
23 24
24 void *priv; 25 void *priv;
25}; 26};
26 27
27struct machine; 28struct machine;
29struct comm;
28 30
29struct thread *thread__new(pid_t pid, pid_t tid); 31struct thread *thread__new(pid_t pid, pid_t tid);
30void thread__delete(struct thread *self); 32void thread__delete(struct thread *thread);
31static inline void thread__exited(struct thread *thread) 33static inline void thread__exited(struct thread *thread)
32{ 34{
33 thread->dead = true; 35 thread->dead = true;
34} 36}
35 37
36int thread__set_comm(struct thread *self, const char *comm); 38int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp);
37int thread__comm_len(struct thread *self); 39int thread__comm_len(struct thread *thread);
38void thread__insert_map(struct thread *self, struct map *map); 40struct comm *thread__comm(const struct thread *thread);
39int thread__fork(struct thread *self, struct thread *parent); 41const char *thread__comm_str(const struct thread *thread);
42void thread__insert_map(struct thread *thread, struct map *map);
43int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
40size_t thread__fprintf(struct thread *thread, FILE *fp); 44size_t thread__fprintf(struct thread *thread, FILE *fp);
41 45
42static inline struct map *thread__find_map(struct thread *self, 46static inline struct map *thread__find_map(struct thread *thread,
43 enum map_type type, u64 addr) 47 enum map_type type, u64 addr)
44{ 48{
45 return self ? map_groups__find(&self->mg, type, addr) : NULL; 49 return thread ? map_groups__find(&thread->mg, type, addr) : NULL;
46} 50}
47 51
48void thread__find_addr_map(struct thread *thread, struct machine *machine, 52void thread__find_addr_map(struct thread *thread, struct machine *machine,
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index f857b51b6bde..ce793c7dd23c 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -27,7 +27,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
27 float ksamples_per_sec; 27 float ksamples_per_sec;
28 float esamples_percent; 28 float esamples_percent;
29 struct perf_record_opts *opts = &top->record_opts; 29 struct perf_record_opts *opts = &top->record_opts;
30 struct perf_target *target = &opts->target; 30 struct target *target = &opts->target;
31 size_t ret = 0; 31 size_t ret = 0;
32 32
33 if (top->samples) { 33 if (top->samples) {
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index b554ffc462b6..88cfeaff600b 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -24,6 +24,7 @@ struct perf_top {
24 u64 exact_samples; 24 u64 exact_samples;
25 u64 guest_us_samples, guest_kernel_samples; 25 u64 guest_us_samples, guest_kernel_samples;
26 int print_entries, count_filter, delay_secs; 26 int print_entries, count_filter, delay_secs;
27 int max_stack;
27 bool hide_kernel_symbols, hide_user_symbols, zero; 28 bool hide_kernel_symbols, hide_user_symbols, zero;
28 bool use_tui, use_stdio; 29 bool use_tui, use_stdio;
29 bool kptr_restrict_warned; 30 bool kptr_restrict_warned;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index e9e1c03f927d..6681f71f2f95 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -120,42 +120,6 @@ raw_field_value(struct event_format *event, const char *name, void *data)
120 return val; 120 return val;
121} 121}
122 122
123void *raw_field_ptr(struct event_format *event, const char *name, void *data)
124{
125 struct format_field *field;
126
127 field = pevent_find_any_field(event, name);
128 if (!field)
129 return NULL;
130
131 if (field->flags & FIELD_IS_DYNAMIC) {
132 int offset;
133
134 offset = *(int *)(data + field->offset);
135 offset &= 0xffff;
136
137 return data + offset;
138 }
139
140 return data + field->offset;
141}
142
143int trace_parse_common_type(struct pevent *pevent, void *data)
144{
145 struct pevent_record record;
146
147 record.data = data;
148 return pevent_data_type(pevent, &record);
149}
150
151int trace_parse_common_pid(struct pevent *pevent, void *data)
152{
153 struct pevent_record record;
154
155 record.data = data;
156 return pevent_data_pid(pevent, &record);
157}
158
159unsigned long long read_size(struct event_format *event, void *ptr, int size) 123unsigned long long read_size(struct event_format *event, void *ptr, int size)
160{ 124{
161 return pevent_read_number(event->pevent, ptr, size); 125 return pevent_read_number(event->pevent, ptr, size);
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index fafe1a40444a..04df63114109 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -11,8 +11,6 @@ union perf_event;
11struct perf_tool; 11struct perf_tool;
12struct thread; 12struct thread;
13 13
14extern struct pevent *perf_pevent;
15
16int bigendian(void); 14int bigendian(void);
17 15
18struct pevent *read_trace_init(int file_bigendian, int host_bigendian); 16struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
@@ -23,26 +21,19 @@ int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size);
23int parse_event_file(struct pevent *pevent, 21int parse_event_file(struct pevent *pevent,
24 char *buf, unsigned long size, char *sys); 22 char *buf, unsigned long size, char *sys);
25 23
26struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu);
27
28unsigned long long 24unsigned long long
29raw_field_value(struct event_format *event, const char *name, void *data); 25raw_field_value(struct event_format *event, const char *name, void *data);
30void *raw_field_ptr(struct event_format *event, const char *name, void *data);
31 26
32void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); 27void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
33void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); 28void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
34 29
35ssize_t trace_report(int fd, struct pevent **pevent, bool repipe); 30ssize_t trace_report(int fd, struct pevent **pevent, bool repipe);
36 31
37int trace_parse_common_type(struct pevent *pevent, void *data);
38int trace_parse_common_pid(struct pevent *pevent, void *data);
39
40struct event_format *trace_find_next_event(struct pevent *pevent, 32struct event_format *trace_find_next_event(struct pevent *pevent,
41 struct event_format *event); 33 struct event_format *event);
42unsigned long long read_size(struct event_format *event, void *ptr, int size); 34unsigned long long read_size(struct event_format *event, void *ptr, int size);
43unsigned long long eval_flag(const char *flag); 35unsigned long long eval_flag(const char *flag);
44 36
45struct pevent_record *trace_read_data(struct pevent *pevent, int cpu);
46int read_tracing_data(int fd, struct list_head *pattrs); 37int read_tracing_data(int fd, struct list_head *pattrs);
47 38
48struct tracing_data { 39struct tracing_data {
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 2f891f7e70bf..0efd5393de85 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -39,6 +39,15 @@ UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
39 39
40#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) 40#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
41 41
42extern int
43UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
44 unw_word_t ip,
45 unw_word_t segbase,
46 const char *obj_name, unw_word_t start,
47 unw_word_t end);
48
49#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
50
42#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ 51#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */
43#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ 52#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */
44 53
@@ -245,8 +254,9 @@ static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
245 return 0; 254 return 0;
246} 255}
247 256
248static int read_unwind_spec(struct dso *dso, struct machine *machine, 257static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
249 u64 *table_data, u64 *segbase, u64 *fde_count) 258 u64 *table_data, u64 *segbase,
259 u64 *fde_count)
250{ 260{
251 int ret = -EINVAL, fd; 261 int ret = -EINVAL, fd;
252 u64 offset; 262 u64 offset;
@@ -255,6 +265,7 @@ static int read_unwind_spec(struct dso *dso, struct machine *machine,
255 if (fd < 0) 265 if (fd < 0)
256 return -EINVAL; 266 return -EINVAL;
257 267
268 /* Check the .eh_frame section for unwinding info */
258 offset = elf_section_offset(fd, ".eh_frame_hdr"); 269 offset = elf_section_offset(fd, ".eh_frame_hdr");
259 close(fd); 270 close(fd);
260 271
@@ -263,10 +274,29 @@ static int read_unwind_spec(struct dso *dso, struct machine *machine,
263 table_data, segbase, 274 table_data, segbase,
264 fde_count); 275 fde_count);
265 276
266 /* TODO .debug_frame check if eh_frame_hdr fails */
267 return ret; 277 return ret;
268} 278}
269 279
280#ifndef NO_LIBUNWIND_DEBUG_FRAME
281static int read_unwind_spec_debug_frame(struct dso *dso,
282 struct machine *machine, u64 *offset)
283{
284 int fd = dso__data_fd(dso, machine);
285
286 if (fd < 0)
287 return -EINVAL;
288
289 /* Check the .debug_frame section for unwinding info */
290 *offset = elf_section_offset(fd, ".debug_frame");
291 close(fd);
292
293 if (*offset)
294 return 0;
295
296 return -EINVAL;
297}
298#endif
299
270static struct map *find_map(unw_word_t ip, struct unwind_info *ui) 300static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
271{ 301{
272 struct addr_location al; 302 struct addr_location al;
@@ -291,20 +321,33 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
291 321
292 pr_debug("unwind: find_proc_info dso %s\n", map->dso->name); 322 pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
293 323
294 if (read_unwind_spec(map->dso, ui->machine, 324 /* Check the .eh_frame section for unwinding info */
295 &table_data, &segbase, &fde_count)) 325 if (!read_unwind_spec_eh_frame(map->dso, ui->machine,
296 return -EINVAL; 326 &table_data, &segbase, &fde_count)) {
327 memset(&di, 0, sizeof(di));
328 di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
329 di.start_ip = map->start;
330 di.end_ip = map->end;
331 di.u.rti.segbase = map->start + segbase;
332 di.u.rti.table_data = map->start + table_data;
333 di.u.rti.table_len = fde_count * sizeof(struct table_entry)
334 / sizeof(unw_word_t);
335 return dwarf_search_unwind_table(as, ip, &di, pi,
336 need_unwind_info, arg);
337 }
338
339#ifndef NO_LIBUNWIND_DEBUG_FRAME
340 /* Check the .debug_frame section for unwinding info */
341 if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
342 memset(&di, 0, sizeof(di));
343 dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name,
344 map->start, map->end);
345 return dwarf_search_unwind_table(as, ip, &di, pi,
346 need_unwind_info, arg);
347 }
348#endif
297 349
298 memset(&di, 0, sizeof(di)); 350 return -EINVAL;
299 di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
300 di.start_ip = map->start;
301 di.end_ip = map->end;
302 di.u.rti.segbase = map->start + segbase;
303 di.u.rti.table_data = map->start + table_data;
304 di.u.rti.table_len = fde_count * sizeof(struct table_entry)
305 / sizeof(unw_word_t);
306 return dwarf_search_unwind_table(as, ip, &di, pi,
307 need_unwind_info, arg);
308} 351}
309 352
310static int access_fpreg(unw_addr_space_t __maybe_unused as, 353static int access_fpreg(unw_addr_space_t __maybe_unused as,
@@ -516,7 +559,7 @@ static unw_accessors_t accessors = {
516}; 559};
517 560
518static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, 561static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
519 void *arg) 562 void *arg, int max_stack)
520{ 563{
521 unw_addr_space_t addr_space; 564 unw_addr_space_t addr_space;
522 unw_cursor_t c; 565 unw_cursor_t c;
@@ -532,7 +575,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
532 if (ret) 575 if (ret)
533 display_error(ret); 576 display_error(ret);
534 577
535 while (!ret && (unw_step(&c) > 0)) { 578 while (!ret && (unw_step(&c) > 0) && max_stack--) {
536 unw_word_t ip; 579 unw_word_t ip;
537 580
538 unw_get_reg(&c, UNW_REG_IP, &ip); 581 unw_get_reg(&c, UNW_REG_IP, &ip);
@@ -545,7 +588,8 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
545 588
546int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 589int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
547 struct machine *machine, struct thread *thread, 590 struct machine *machine, struct thread *thread,
548 u64 sample_uregs, struct perf_sample *data) 591 u64 sample_uregs, struct perf_sample *data,
592 int max_stack)
549{ 593{
550 unw_word_t ip; 594 unw_word_t ip;
551 struct unwind_info ui = { 595 struct unwind_info ui = {
@@ -567,5 +611,5 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
567 if (ret) 611 if (ret)
568 return -ENOMEM; 612 return -ENOMEM;
569 613
570 return get_entries(&ui, cb, arg); 614 return get_entries(&ui, cb, arg, max_stack);
571} 615}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index cb6bc503a792..d5966f49e22c 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -13,12 +13,12 @@ struct unwind_entry {
13 13
14typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); 14typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
15 15
16#ifdef LIBUNWIND_SUPPORT 16#ifdef HAVE_LIBUNWIND_SUPPORT
17int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 17int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
18 struct machine *machine, 18 struct machine *machine,
19 struct thread *thread, 19 struct thread *thread,
20 u64 sample_uregs, 20 u64 sample_uregs,
21 struct perf_sample *data); 21 struct perf_sample *data, int max_stack);
22int unwind__arch_reg_id(int regnum); 22int unwind__arch_reg_id(int regnum);
23#else 23#else
24static inline int 24static inline int
@@ -27,9 +27,10 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
27 struct machine *machine __maybe_unused, 27 struct machine *machine __maybe_unused,
28 struct thread *thread __maybe_unused, 28 struct thread *thread __maybe_unused,
29 u64 sample_uregs __maybe_unused, 29 u64 sample_uregs __maybe_unused,
30 struct perf_sample *data __maybe_unused) 30 struct perf_sample *data __maybe_unused,
31 int max_stack __maybe_unused)
31{ 32{
32 return 0; 33 return 0;
33} 34}
34#endif /* LIBUNWIND_SUPPORT */ 35#endif /* HAVE_LIBUNWIND_SUPPORT */
35#endif /* __UNWIND_H */ 36#endif /* __UNWIND_H */
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 6d17b18e915d..28a0a89c1f73 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -1,7 +1,7 @@
1#include "../perf.h" 1#include "../perf.h"
2#include "util.h" 2#include "util.h"
3#include <sys/mman.h> 3#include <sys/mman.h>
4#ifdef BACKTRACE_SUPPORT 4#ifdef HAVE_BACKTRACE_SUPPORT
5#include <execinfo.h> 5#include <execinfo.h>
6#endif 6#endif
7#include <stdio.h> 7#include <stdio.h>
@@ -55,17 +55,20 @@ int mkdir_p(char *path, mode_t mode)
55 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; 55 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
56} 56}
57 57
58static int slow_copyfile(const char *from, const char *to) 58static int slow_copyfile(const char *from, const char *to, mode_t mode)
59{ 59{
60 int err = 0; 60 int err = -1;
61 char *line = NULL; 61 char *line = NULL;
62 size_t n; 62 size_t n;
63 FILE *from_fp = fopen(from, "r"), *to_fp; 63 FILE *from_fp = fopen(from, "r"), *to_fp;
64 mode_t old_umask;
64 65
65 if (from_fp == NULL) 66 if (from_fp == NULL)
66 goto out; 67 goto out;
67 68
69 old_umask = umask(mode ^ 0777);
68 to_fp = fopen(to, "w"); 70 to_fp = fopen(to, "w");
71 umask(old_umask);
69 if (to_fp == NULL) 72 if (to_fp == NULL)
70 goto out_fclose_from; 73 goto out_fclose_from;
71 74
@@ -82,7 +85,7 @@ out:
82 return err; 85 return err;
83} 86}
84 87
85int copyfile(const char *from, const char *to) 88int copyfile_mode(const char *from, const char *to, mode_t mode)
86{ 89{
87 int fromfd, tofd; 90 int fromfd, tofd;
88 struct stat st; 91 struct stat st;
@@ -93,13 +96,13 @@ int copyfile(const char *from, const char *to)
93 goto out; 96 goto out;
94 97
95 if (st.st_size == 0) /* /proc? do it slowly... */ 98 if (st.st_size == 0) /* /proc? do it slowly... */
96 return slow_copyfile(from, to); 99 return slow_copyfile(from, to, mode);
97 100
98 fromfd = open(from, O_RDONLY); 101 fromfd = open(from, O_RDONLY);
99 if (fromfd < 0) 102 if (fromfd < 0)
100 goto out; 103 goto out;
101 104
102 tofd = creat(to, 0755); 105 tofd = creat(to, mode);
103 if (tofd < 0) 106 if (tofd < 0)
104 goto out_close_from; 107 goto out_close_from;
105 108
@@ -121,6 +124,11 @@ out:
121 return err; 124 return err;
122} 125}
123 126
127int copyfile(const char *from, const char *to)
128{
129 return copyfile_mode(from, to, 0755);
130}
131
124unsigned long convert_unit(unsigned long value, char *unit) 132unsigned long convert_unit(unsigned long value, char *unit)
125{ 133{
126 *unit = ' '; 134 *unit = ' ';
@@ -204,7 +212,7 @@ int hex2u64(const char *ptr, u64 *long_val)
204} 212}
205 213
206/* Obtain a backtrace and print it to stdout. */ 214/* Obtain a backtrace and print it to stdout. */
207#ifdef BACKTRACE_SUPPORT 215#ifdef HAVE_BACKTRACE_SUPPORT
208void dump_stack(void) 216void dump_stack(void)
209{ 217{
210 void *array[16]; 218 void *array[16];
@@ -361,3 +369,47 @@ int parse_nsec_time(const char *str, u64 *ptime)
361 *ptime = time_sec * NSEC_PER_SEC + time_nsec; 369 *ptime = time_sec * NSEC_PER_SEC + time_nsec;
362 return 0; 370 return 0;
363} 371}
372
373unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
374{
375 struct parse_tag *i = tags;
376
377 while (i->tag) {
378 char *s;
379
380 s = strchr(str, i->tag);
381 if (s) {
382 unsigned long int value;
383 char *endptr;
384
385 value = strtoul(str, &endptr, 10);
386 if (s != endptr)
387 break;
388
389 if (value > ULONG_MAX / i->mult)
390 break;
391 value *= i->mult;
392 return value;
393 }
394 i++;
395 }
396
397 return (unsigned long) -1;
398}
399
400int filename__read_int(const char *filename, int *value)
401{
402 char line[64];
403 int fd = open(filename, O_RDONLY), err = -1;
404
405 if (fd < 0)
406 return -1;
407
408 if (read(fd, line, sizeof(line)) > 0) {
409 *value = atoi(line);
410 err = 0;
411 }
412
413 close(fd);
414 return err;
415}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index a53535949043..c8f362daba87 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -128,6 +128,8 @@ void put_tracing_file(char *file);
128#endif 128#endif
129#endif 129#endif
130 130
131#define PERF_GTK_DSO "libperf-gtk.so"
132
131/* General helper functions */ 133/* General helper functions */
132extern void usage(const char *err) NORETURN; 134extern void usage(const char *err) NORETURN;
133extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); 135extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
@@ -241,6 +243,7 @@ static inline int sane_case(int x, int high)
241 243
242int mkdir_p(char *path, mode_t mode); 244int mkdir_p(char *path, mode_t mode);
243int copyfile(const char *from, const char *to); 245int copyfile(const char *from, const char *to);
246int copyfile_mode(const char *from, const char *to, mode_t mode);
244 247
245s64 perf_atoll(const char *str); 248s64 perf_atoll(const char *str);
246char **argv_split(const char *str, int *argcp); 249char **argv_split(const char *str, int *argcp);
@@ -270,6 +273,13 @@ bool is_power_of_2(unsigned long n)
270 return (n != 0 && ((n & (n - 1)) == 0)); 273 return (n != 0 && ((n & (n - 1)) == 0));
271} 274}
272 275
276static inline unsigned next_pow2(unsigned x)
277{
278 if (!x)
279 return 1;
280 return 1ULL << (32 - __builtin_clz(x - 1));
281}
282
273size_t hex_width(u64 v); 283size_t hex_width(u64 v);
274int hex2u64(const char *ptr, u64 *val); 284int hex2u64(const char *ptr, u64 *val);
275 285
@@ -281,4 +291,20 @@ void dump_stack(void);
281extern unsigned int page_size; 291extern unsigned int page_size;
282 292
283void get_term_dimensions(struct winsize *ws); 293void get_term_dimensions(struct winsize *ws);
294
295struct parse_tag {
296 char tag;
297 int mult;
298};
299
300unsigned long parse_tag_value(const char *str, struct parse_tag *tags);
301
302#define SRCLINE_UNKNOWN ((char *) "??:0")
303
304struct dso;
305
306char *get_srcline(struct dso *dso, unsigned long addr);
307void free_srcline(char *srcline);
308
309int filename__read_int(const char *filename, int *value);
284#endif /* GIT_COMPAT_UTIL_H */ 310#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/power/cpupower/man/cpupower-idle-info.1 b/tools/power/cpupower/man/cpupower-idle-info.1
index 4178effd9e99..7b3646adb92f 100644
--- a/tools/power/cpupower/man/cpupower-idle-info.1
+++ b/tools/power/cpupower/man/cpupower-idle-info.1
@@ -87,4 +87,5 @@ Thomas Renninger <trenn@suse.de>
87.fi 87.fi
88.SH "SEE ALSO" 88.SH "SEE ALSO"
89.LP 89.LP
90cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1) 90cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1),
91cpupower\-idle\-set(1)
diff --git a/tools/power/cpupower/man/cpupower-idle-set.1 b/tools/power/cpupower/man/cpupower-idle-set.1
new file mode 100644
index 000000000000..6b1607272a5b
--- /dev/null
+++ b/tools/power/cpupower/man/cpupower-idle-set.1
@@ -0,0 +1,71 @@
1.TH "CPUPOWER-IDLE-SET" "1" "0.1" "" "cpupower Manual"
2.SH "NAME"
3.LP
4cpupower idle\-set \- Utility to set cpu idle state specific kernel options
5.SH "SYNTAX"
6.LP
7cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP]
8.SH "DESCRIPTION"
9.LP
10The cpupower idle\-set subcommand allows to set cpu idle, also called cpu
11sleep state, specific options offered by the kernel. One example is disabling
12sleep states. This can be handy for power vs performance tuning.
13.SH "OPTIONS"
14.LP
15.TP
16\fB\-d\fR \fB\-\-disable\fR
17Disable a specific processor sleep state.
18.TP
19\fB\-e\fR \fB\-\-enable\fR
20Enable a specific processor sleep state.
21
22.SH "REMARKS"
23.LP
24Cpuidle Governors Policy on Disabling Sleep States
25
26.RS 4
27Depending on the used cpuidle governor, implementing the kernel policy
28how to choose sleep states, subsequent sleep states on this core, might get
29disabled as well.
30
31There are two cpuidle governors ladder and menu. While the ladder
32governor is always available, if CONFIG_CPU_IDLE is selected, the
33menu governor additionally requires CONFIG_NO_HZ.
34
35The behavior and the effect of the disable variable depends on the
36implementation of a particular governor. In the ladder governor, for
37example, it is not coherent, i.e. if one is disabling a light state,
38then all deeper states are disabled as well. Likewise, if one enables a
39deep state but a lighter state still is disabled, then this has no effect.
40.RE
41.LP
42Disabling the Lightest Sleep State may not have any Affect
43
44.RS 4
45If criteria are not met to enter deeper sleep states and the lightest sleep
46state is chosen when idle, the kernel may still enter this sleep state,
47irrespective of whether it is disabled or not. This is also reflected in
48the usage count of the disabled sleep state when using the cpupower idle-info
49command.
50.RE
51.LP
52Selecting specific CPU Cores
53
54.RS 4
55By default processor sleep states of all CPU cores are set. Please refer
56to the cpupower(1) manpage in the \-\-cpu option section how to disable
57C-states of specific cores.
58.RE
59.SH "FILES"
60.nf
61\fI/sys/devices/system/cpu/cpu*/cpuidle/state*\fP
62\fI/sys/devices/system/cpu/cpuidle/*\fP
63.fi
64.SH "AUTHORS"
65.nf
66Thomas Renninger <trenn@suse.de>
67.fi
68.SH "SEE ALSO"
69.LP
70cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1),
71cpupower\-idle\-info(1)
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 5cdc600e8152..851c7a16ca49 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -278,7 +278,7 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu,
278int sysfs_is_idlestate_disabled(unsigned int cpu, 278int sysfs_is_idlestate_disabled(unsigned int cpu,
279 unsigned int idlestate) 279 unsigned int idlestate)
280{ 280{
281 if (sysfs_get_idlestate_count(cpu) < idlestate) 281 if (sysfs_get_idlestate_count(cpu) <= idlestate)
282 return -1; 282 return -1;
283 283
284 if (!sysfs_idlestate_file_exists(cpu, idlestate, 284 if (!sysfs_idlestate_file_exists(cpu, idlestate,
@@ -303,7 +303,7 @@ int sysfs_idlestate_disable(unsigned int cpu,
303 char value[SYSFS_PATH_MAX]; 303 char value[SYSFS_PATH_MAX];
304 int bytes_written; 304 int bytes_written;
305 305
306 if (sysfs_get_idlestate_count(cpu) < idlestate) 306 if (sysfs_get_idlestate_count(cpu) <= idlestate)
307 return -1; 307 return -1;
308 308
309 if (!sysfs_idlestate_file_exists(cpu, idlestate, 309 if (!sysfs_idlestate_file_exists(cpu, idlestate,
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index fe702076ca46..9d77f13c2d25 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -2,7 +2,7 @@
2 * turbostat -- show CPU frequency and C-state residency 2 * turbostat -- show CPU frequency and C-state residency
3 * on modern Intel turbo-capable processors. 3 * on modern Intel turbo-capable processors.
4 * 4 *
5 * Copyright (c) 2012 Intel Corporation. 5 * Copyright (c) 2013 Intel Corporation.
6 * Len Brown <len.brown@intel.com> 6 * Len Brown <len.brown@intel.com>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify it 8 * This program is free software; you can redistribute it and/or modify it
@@ -47,6 +47,8 @@ unsigned int skip_c1;
47unsigned int do_nhm_cstates; 47unsigned int do_nhm_cstates;
48unsigned int do_snb_cstates; 48unsigned int do_snb_cstates;
49unsigned int do_c8_c9_c10; 49unsigned int do_c8_c9_c10;
50unsigned int do_slm_cstates;
51unsigned int use_c1_residency_msr;
50unsigned int has_aperf; 52unsigned int has_aperf;
51unsigned int has_epb; 53unsigned int has_epb;
52unsigned int units = 1000000000; /* Ghz etc */ 54unsigned int units = 1000000000; /* Ghz etc */
@@ -81,6 +83,8 @@ double rapl_joule_counter_range;
81#define RAPL_DRAM (1 << 3) 83#define RAPL_DRAM (1 << 3)
82#define RAPL_PKG_PERF_STATUS (1 << 4) 84#define RAPL_PKG_PERF_STATUS (1 << 4)
83#define RAPL_DRAM_PERF_STATUS (1 << 5) 85#define RAPL_DRAM_PERF_STATUS (1 << 5)
86#define RAPL_PKG_POWER_INFO (1 << 6)
87#define RAPL_CORE_POLICY (1 << 7)
84#define TJMAX_DEFAULT 100 88#define TJMAX_DEFAULT 100
85 89
86#define MAX(a, b) ((a) > (b) ? (a) : (b)) 90#define MAX(a, b) ((a) > (b) ? (a) : (b))
@@ -96,7 +100,7 @@ struct thread_data {
96 unsigned long long tsc; 100 unsigned long long tsc;
97 unsigned long long aperf; 101 unsigned long long aperf;
98 unsigned long long mperf; 102 unsigned long long mperf;
99 unsigned long long c1; /* derived */ 103 unsigned long long c1;
100 unsigned long long extra_msr64; 104 unsigned long long extra_msr64;
101 unsigned long long extra_delta64; 105 unsigned long long extra_delta64;
102 unsigned long long extra_msr32; 106 unsigned long long extra_msr32;
@@ -266,7 +270,7 @@ void print_header(void)
266 outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset64); 270 outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset64);
267 if (do_nhm_cstates) 271 if (do_nhm_cstates)
268 outp += sprintf(outp, " %%c1"); 272 outp += sprintf(outp, " %%c1");
269 if (do_nhm_cstates) 273 if (do_nhm_cstates && !do_slm_cstates)
270 outp += sprintf(outp, " %%c3"); 274 outp += sprintf(outp, " %%c3");
271 if (do_nhm_cstates) 275 if (do_nhm_cstates)
272 outp += sprintf(outp, " %%c6"); 276 outp += sprintf(outp, " %%c6");
@@ -280,9 +284,9 @@ void print_header(void)
280 284
281 if (do_snb_cstates) 285 if (do_snb_cstates)
282 outp += sprintf(outp, " %%pc2"); 286 outp += sprintf(outp, " %%pc2");
283 if (do_nhm_cstates) 287 if (do_nhm_cstates && !do_slm_cstates)
284 outp += sprintf(outp, " %%pc3"); 288 outp += sprintf(outp, " %%pc3");
285 if (do_nhm_cstates) 289 if (do_nhm_cstates && !do_slm_cstates)
286 outp += sprintf(outp, " %%pc6"); 290 outp += sprintf(outp, " %%pc6");
287 if (do_snb_cstates) 291 if (do_snb_cstates)
288 outp += sprintf(outp, " %%pc7"); 292 outp += sprintf(outp, " %%pc7");
@@ -480,7 +484,7 @@ int format_counters(struct thread_data *t, struct core_data *c,
480 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) 484 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
481 goto done; 485 goto done;
482 486
483 if (do_nhm_cstates) 487 if (do_nhm_cstates && !do_slm_cstates)
484 outp += sprintf(outp, " %6.2f", 100.0 * c->c3/t->tsc); 488 outp += sprintf(outp, " %6.2f", 100.0 * c->c3/t->tsc);
485 if (do_nhm_cstates) 489 if (do_nhm_cstates)
486 outp += sprintf(outp, " %6.2f", 100.0 * c->c6/t->tsc); 490 outp += sprintf(outp, " %6.2f", 100.0 * c->c6/t->tsc);
@@ -499,9 +503,9 @@ int format_counters(struct thread_data *t, struct core_data *c,
499 503
500 if (do_snb_cstates) 504 if (do_snb_cstates)
501 outp += sprintf(outp, " %6.2f", 100.0 * p->pc2/t->tsc); 505 outp += sprintf(outp, " %6.2f", 100.0 * p->pc2/t->tsc);
502 if (do_nhm_cstates) 506 if (do_nhm_cstates && !do_slm_cstates)
503 outp += sprintf(outp, " %6.2f", 100.0 * p->pc3/t->tsc); 507 outp += sprintf(outp, " %6.2f", 100.0 * p->pc3/t->tsc);
504 if (do_nhm_cstates) 508 if (do_nhm_cstates && !do_slm_cstates)
505 outp += sprintf(outp, " %6.2f", 100.0 * p->pc6/t->tsc); 509 outp += sprintf(outp, " %6.2f", 100.0 * p->pc6/t->tsc);
506 if (do_snb_cstates) 510 if (do_snb_cstates)
507 outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc); 511 outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc);
@@ -648,17 +652,24 @@ delta_thread(struct thread_data *new, struct thread_data *old,
648 } 652 }
649 653
650 654
651 /* 655 if (use_c1_residency_msr) {
652 * As counter collection is not atomic, 656 /*
653 * it is possible for mperf's non-halted cycles + idle states 657 * Some models have a dedicated C1 residency MSR,
654 * to exceed TSC's all cycles: show c1 = 0% in that case. 658 * which should be more accurate than the derivation below.
655 */ 659 */
656 if ((old->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > old->tsc) 660 } else {
657 old->c1 = 0; 661 /*
658 else { 662 * As counter collection is not atomic,
659 /* normal case, derive c1 */ 663 * it is possible for mperf's non-halted cycles + idle states
660 old->c1 = old->tsc - old->mperf - core_delta->c3 664 * to exceed TSC's all cycles: show c1 = 0% in that case.
665 */
666 if ((old->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > old->tsc)
667 old->c1 = 0;
668 else {
669 /* normal case, derive c1 */
670 old->c1 = old->tsc - old->mperf - core_delta->c3
661 - core_delta->c6 - core_delta->c7; 671 - core_delta->c6 - core_delta->c7;
672 }
662 } 673 }
663 674
664 if (old->mperf == 0) { 675 if (old->mperf == 0) {
@@ -872,13 +883,21 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
872 if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64)) 883 if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64))
873 return -5; 884 return -5;
874 885
886 if (use_c1_residency_msr) {
887 if (get_msr(cpu, MSR_CORE_C1_RES, &t->c1))
888 return -6;
889 }
890
875 /* collect core counters only for 1st thread in core */ 891 /* collect core counters only for 1st thread in core */
876 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) 892 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
877 return 0; 893 return 0;
878 894
879 if (do_nhm_cstates) { 895 if (do_nhm_cstates && !do_slm_cstates) {
880 if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3)) 896 if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3))
881 return -6; 897 return -6;
898 }
899
900 if (do_nhm_cstates) {
882 if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6)) 901 if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6))
883 return -7; 902 return -7;
884 } 903 }
@@ -898,7 +917,7 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
898 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) 917 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
899 return 0; 918 return 0;
900 919
901 if (do_nhm_cstates) { 920 if (do_nhm_cstates && !do_slm_cstates) {
902 if (get_msr(cpu, MSR_PKG_C3_RESIDENCY, &p->pc3)) 921 if (get_msr(cpu, MSR_PKG_C3_RESIDENCY, &p->pc3))
903 return -9; 922 return -9;
904 if (get_msr(cpu, MSR_PKG_C6_RESIDENCY, &p->pc6)) 923 if (get_msr(cpu, MSR_PKG_C6_RESIDENCY, &p->pc6))
@@ -977,7 +996,7 @@ void print_verbose_header(void)
977 ratio, bclk, ratio * bclk); 996 ratio, bclk, ratio * bclk);
978 997
979 get_msr(0, MSR_IA32_POWER_CTL, &msr); 998 get_msr(0, MSR_IA32_POWER_CTL, &msr);
980 fprintf(stderr, "cpu0: MSR_IA32_POWER_CTL: 0x%08llx (C1E: %sabled)\n", 999 fprintf(stderr, "cpu0: MSR_IA32_POWER_CTL: 0x%08llx (C1E auto-promotion: %sabled)\n",
981 msr, msr & 0x2 ? "EN" : "DIS"); 1000 msr, msr & 0x2 ? "EN" : "DIS");
982 1001
983 if (!do_ivt_turbo_ratio_limit) 1002 if (!do_ivt_turbo_ratio_limit)
@@ -1046,25 +1065,28 @@ print_nhm_turbo_ratio_limits:
1046 1065
1047 switch(msr & 0x7) { 1066 switch(msr & 0x7) {
1048 case 0: 1067 case 0:
1049 fprintf(stderr, "pc0"); 1068 fprintf(stderr, do_slm_cstates ? "no pkg states" : "pc0");
1050 break; 1069 break;
1051 case 1: 1070 case 1:
1052 fprintf(stderr, do_snb_cstates ? "pc2" : "pc0"); 1071 fprintf(stderr, do_slm_cstates ? "no pkg states" : do_snb_cstates ? "pc2" : "pc0");
1053 break; 1072 break;
1054 case 2: 1073 case 2:
1055 fprintf(stderr, do_snb_cstates ? "pc6-noret" : "pc3"); 1074 fprintf(stderr, do_slm_cstates ? "invalid" : do_snb_cstates ? "pc6-noret" : "pc3");
1056 break; 1075 break;
1057 case 3: 1076 case 3:
1058 fprintf(stderr, "pc6"); 1077 fprintf(stderr, do_slm_cstates ? "invalid" : "pc6");
1059 break; 1078 break;
1060 case 4: 1079 case 4:
1061 fprintf(stderr, "pc7"); 1080 fprintf(stderr, do_slm_cstates ? "pc4" : "pc7");
1062 break; 1081 break;
1063 case 5: 1082 case 5:
1064 fprintf(stderr, do_snb_cstates ? "pc7s" : "invalid"); 1083 fprintf(stderr, do_slm_cstates ? "invalid" : do_snb_cstates ? "pc7s" : "invalid");
1084 break;
1085 case 6:
1086 fprintf(stderr, do_slm_cstates ? "pc6" : "invalid");
1065 break; 1087 break;
1066 case 7: 1088 case 7:
1067 fprintf(stderr, "unlimited"); 1089 fprintf(stderr, do_slm_cstates ? "pc7" : "unlimited");
1068 break; 1090 break;
1069 default: 1091 default:
1070 fprintf(stderr, "invalid"); 1092 fprintf(stderr, "invalid");
@@ -1460,6 +1482,8 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
1460 case 0x3F: /* HSW */ 1482 case 0x3F: /* HSW */
1461 case 0x45: /* HSW */ 1483 case 0x45: /* HSW */
1462 case 0x46: /* HSW */ 1484 case 0x46: /* HSW */
1485 case 0x37: /* BYT */
1486 case 0x4D: /* AVN */
1463 return 1; 1487 return 1;
1464 case 0x2E: /* Nehalem-EX Xeon - Beckton */ 1488 case 0x2E: /* Nehalem-EX Xeon - Beckton */
1465 case 0x2F: /* Westmere-EX Xeon - Eagleton */ 1489 case 0x2F: /* Westmere-EX Xeon - Eagleton */
@@ -1532,14 +1556,33 @@ int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1532#define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */ 1556#define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */
1533#define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */ 1557#define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */
1534 1558
1559double get_tdp(model)
1560{
1561 unsigned long long msr;
1562
1563 if (do_rapl & RAPL_PKG_POWER_INFO)
1564 if (!get_msr(0, MSR_PKG_POWER_INFO, &msr))
1565 return ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units;
1566
1567 switch (model) {
1568 case 0x37:
1569 case 0x4D:
1570 return 30.0;
1571 default:
1572 return 135.0;
1573 }
1574}
1575
1576
1535/* 1577/*
1536 * rapl_probe() 1578 * rapl_probe()
1537 * 1579 *
1538 * sets do_rapl 1580 * sets do_rapl, rapl_power_units, rapl_energy_units, rapl_time_units
1539 */ 1581 */
1540void rapl_probe(unsigned int family, unsigned int model) 1582void rapl_probe(unsigned int family, unsigned int model)
1541{ 1583{
1542 unsigned long long msr; 1584 unsigned long long msr;
1585 unsigned int time_unit;
1543 double tdp; 1586 double tdp;
1544 1587
1545 if (!genuine_intel) 1588 if (!genuine_intel)
@@ -1555,11 +1598,15 @@ void rapl_probe(unsigned int family, unsigned int model)
1555 case 0x3F: /* HSW */ 1598 case 0x3F: /* HSW */
1556 case 0x45: /* HSW */ 1599 case 0x45: /* HSW */
1557 case 0x46: /* HSW */ 1600 case 0x46: /* HSW */
1558 do_rapl = RAPL_PKG | RAPL_CORES | RAPL_GFX; 1601 do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_GFX | RAPL_PKG_POWER_INFO;
1559 break; 1602 break;
1560 case 0x2D: 1603 case 0x2D:
1561 case 0x3E: 1604 case 0x3E:
1562 do_rapl = RAPL_PKG | RAPL_CORES | RAPL_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS; 1605 do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS | RAPL_PKG_POWER_INFO;
1606 break;
1607 case 0x37: /* BYT */
1608 case 0x4D: /* AVN */
1609 do_rapl = RAPL_PKG | RAPL_CORES ;
1563 break; 1610 break;
1564 default: 1611 default:
1565 return; 1612 return;
@@ -1570,19 +1617,22 @@ void rapl_probe(unsigned int family, unsigned int model)
1570 return; 1617 return;
1571 1618
1572 rapl_power_units = 1.0 / (1 << (msr & 0xF)); 1619 rapl_power_units = 1.0 / (1 << (msr & 0xF));
1573 rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F)); 1620 if (model == 0x37)
1574 rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF)); 1621 rapl_energy_units = 1.0 * (1 << (msr >> 8 & 0x1F)) / 1000000;
1622 else
1623 rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F));
1575 1624
1576 /* get TDP to determine energy counter range */ 1625 time_unit = msr >> 16 & 0xF;
1577 if (get_msr(0, MSR_PKG_POWER_INFO, &msr)) 1626 if (time_unit == 0)
1578 return; 1627 time_unit = 0xA;
1579 1628
1580 tdp = ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units; 1629 rapl_time_units = 1.0 / (1 << (time_unit));
1581 1630
1582 rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp; 1631 tdp = get_tdp(model);
1583 1632
1633 rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp;
1584 if (verbose) 1634 if (verbose)
1585 fprintf(stderr, "RAPL: %.0f sec. Joule Counter Range\n", rapl_joule_counter_range); 1635 fprintf(stderr, "RAPL: %.0f sec. Joule Counter Range, at %.0f Watts\n", rapl_joule_counter_range, tdp);
1586 1636
1587 return; 1637 return;
1588} 1638}
@@ -1668,7 +1718,6 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1668{ 1718{
1669 unsigned long long msr; 1719 unsigned long long msr;
1670 int cpu; 1720 int cpu;
1671 double local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units;
1672 1721
1673 if (!do_rapl) 1722 if (!do_rapl)
1674 return 0; 1723 return 0;
@@ -1686,23 +1735,13 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1686 if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr)) 1735 if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr))
1687 return -1; 1736 return -1;
1688 1737
1689 local_rapl_power_units = 1.0 / (1 << (msr & 0xF));
1690 local_rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F));
1691 local_rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF));
1692
1693 if (local_rapl_power_units != rapl_power_units)
1694 fprintf(stderr, "cpu%d, ERROR: Power units mis-match\n", cpu);
1695 if (local_rapl_energy_units != rapl_energy_units)
1696 fprintf(stderr, "cpu%d, ERROR: Energy units mis-match\n", cpu);
1697 if (local_rapl_time_units != rapl_time_units)
1698 fprintf(stderr, "cpu%d, ERROR: Time units mis-match\n", cpu);
1699
1700 if (verbose) { 1738 if (verbose) {
1701 fprintf(stderr, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx " 1739 fprintf(stderr, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx "
1702 "(%f Watts, %f Joules, %f sec.)\n", cpu, msr, 1740 "(%f Watts, %f Joules, %f sec.)\n", cpu, msr,
1703 local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units); 1741 rapl_power_units, rapl_energy_units, rapl_time_units);
1704 } 1742 }
1705 if (do_rapl & RAPL_PKG) { 1743 if (do_rapl & RAPL_PKG_POWER_INFO) {
1744
1706 if (get_msr(cpu, MSR_PKG_POWER_INFO, &msr)) 1745 if (get_msr(cpu, MSR_PKG_POWER_INFO, &msr))
1707 return -5; 1746 return -5;
1708 1747
@@ -1714,6 +1753,9 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1714 ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units, 1753 ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1715 ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units); 1754 ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units);
1716 1755
1756 }
1757 if (do_rapl & RAPL_PKG) {
1758
1717 if (get_msr(cpu, MSR_PKG_POWER_LIMIT, &msr)) 1759 if (get_msr(cpu, MSR_PKG_POWER_LIMIT, &msr))
1718 return -9; 1760 return -9;
1719 1761
@@ -1749,12 +1791,16 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1749 1791
1750 print_power_limit_msr(cpu, msr, "DRAM Limit"); 1792 print_power_limit_msr(cpu, msr, "DRAM Limit");
1751 } 1793 }
1752 if (do_rapl & RAPL_CORES) { 1794 if (do_rapl & RAPL_CORE_POLICY) {
1753 if (verbose) { 1795 if (verbose) {
1754 if (get_msr(cpu, MSR_PP0_POLICY, &msr)) 1796 if (get_msr(cpu, MSR_PP0_POLICY, &msr))
1755 return -7; 1797 return -7;
1756 1798
1757 fprintf(stderr, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF); 1799 fprintf(stderr, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF);
1800 }
1801 }
1802 if (do_rapl & RAPL_CORES) {
1803 if (verbose) {
1758 1804
1759 if (get_msr(cpu, MSR_PP0_POWER_LIMIT, &msr)) 1805 if (get_msr(cpu, MSR_PP0_POWER_LIMIT, &msr))
1760 return -9; 1806 return -9;
@@ -1813,10 +1859,48 @@ int has_c8_c9_c10(unsigned int family, unsigned int model)
1813} 1859}
1814 1860
1815 1861
1862int is_slm(unsigned int family, unsigned int model)
1863{
1864 if (!genuine_intel)
1865 return 0;
1866 switch (model) {
1867 case 0x37: /* BYT */
1868 case 0x4D: /* AVN */
1869 return 1;
1870 }
1871 return 0;
1872}
1873
1874#define SLM_BCLK_FREQS 5
1875double slm_freq_table[SLM_BCLK_FREQS] = { 83.3, 100.0, 133.3, 116.7, 80.0};
1876
1877double slm_bclk(void)
1878{
1879 unsigned long long msr = 3;
1880 unsigned int i;
1881 double freq;
1882
1883 if (get_msr(0, MSR_FSB_FREQ, &msr))
1884 fprintf(stderr, "SLM BCLK: unknown\n");
1885
1886 i = msr & 0xf;
1887 if (i >= SLM_BCLK_FREQS) {
1888 fprintf(stderr, "SLM BCLK[%d] invalid\n", i);
1889 msr = 3;
1890 }
1891 freq = slm_freq_table[i];
1892
1893 fprintf(stderr, "SLM BCLK: %.1f Mhz\n", freq);
1894
1895 return freq;
1896}
1897
1816double discover_bclk(unsigned int family, unsigned int model) 1898double discover_bclk(unsigned int family, unsigned int model)
1817{ 1899{
1818 if (is_snb(family, model)) 1900 if (is_snb(family, model))
1819 return 100.00; 1901 return 100.00;
1902 else if (is_slm(family, model))
1903 return slm_bclk();
1820 else 1904 else
1821 return 133.33; 1905 return 133.33;
1822} 1906}
@@ -1873,7 +1957,7 @@ int set_temperature_target(struct thread_data *t, struct core_data *c, struct pk
1873 fprintf(stderr, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n", 1957 fprintf(stderr, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n",
1874 cpu, msr, target_c_local); 1958 cpu, msr, target_c_local);
1875 1959
1876 if (target_c_local < 85 || target_c_local > 120) 1960 if (target_c_local < 85 || target_c_local > 127)
1877 goto guess; 1961 goto guess;
1878 1962
1879 tcc_activation_temp = target_c_local; 1963 tcc_activation_temp = target_c_local;
@@ -1970,6 +2054,7 @@ void check_cpuid()
1970 do_smi = do_nhm_cstates; 2054 do_smi = do_nhm_cstates;
1971 do_snb_cstates = is_snb(family, model); 2055 do_snb_cstates = is_snb(family, model);
1972 do_c8_c9_c10 = has_c8_c9_c10(family, model); 2056 do_c8_c9_c10 = has_c8_c9_c10(family, model);
2057 do_slm_cstates = is_slm(family, model);
1973 bclk = discover_bclk(family, model); 2058 bclk = discover_bclk(family, model);
1974 2059
1975 do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); 2060 do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model);
@@ -2331,7 +2416,7 @@ int main(int argc, char **argv)
2331 cmdline(argc, argv); 2416 cmdline(argc, argv);
2332 2417
2333 if (verbose) 2418 if (verbose)
2334 fprintf(stderr, "turbostat v3.4 April 17, 2013" 2419 fprintf(stderr, "turbostat v3.5 April 26, 2013"
2335 " - Len Brown <lenb@kernel.org>\n"); 2420 " - Len Brown <lenb@kernel.org>\n");
2336 2421
2337 turbostat_init(); 2422 turbostat_init();
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index 0d0506d55c71..ee76544deecb 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -59,21 +59,22 @@ QUIET_SUBDIR0 = +$(MAKE) $(COMMAND_O) -C # space to separate -C and subdir
59QUIET_SUBDIR1 = 59QUIET_SUBDIR1 =
60 60
61ifneq ($(findstring $(MAKEFLAGS),s),s) 61ifneq ($(findstring $(MAKEFLAGS),s),s)
62ifneq ($(V),1) 62 ifneq ($(V),1)
63 QUIET_CC = @echo ' ' CC $@; 63 QUIET_CC = @echo ' CC '$@;
64 QUIET_AR = @echo ' ' AR $@; 64 QUIET_AR = @echo ' AR '$@;
65 QUIET_LINK = @echo ' ' LINK $@; 65 QUIET_LINK = @echo ' LINK '$@;
66 QUIET_MKDIR = @echo ' ' MKDIR $@; 66 QUIET_MKDIR = @echo ' MKDIR '$@;
67 QUIET_GEN = @echo ' ' GEN $@; 67 QUIET_GEN = @echo ' GEN '$@;
68 QUIET_SUBDIR0 = +@subdir= 68 QUIET_SUBDIR0 = +@subdir=
69 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ 69 QUIET_SUBDIR1 = ;$(NO_SUBDIR) \
70 echo ' SUBDIR '$$subdir; \
70 $(MAKE) $(PRINT_DIR) -C $$subdir 71 $(MAKE) $(PRINT_DIR) -C $$subdir
71 QUIET_FLEX = @echo ' ' FLEX $@; 72 QUIET_FLEX = @echo ' FLEX '$@;
72 QUIET_BISON = @echo ' ' BISON $@; 73 QUIET_BISON = @echo ' BISON '$@;
73 74
74 descend = \ 75 descend = \
75 +@echo ' ' DESCEND $(1); \ 76 +@echo ' DESCEND '$(1); \
76 mkdir -p $(OUTPUT)$(1) && \ 77 mkdir -p $(OUTPUT)$(1) && \
77 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) 78 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
78endif 79 endif
79endif 80endif
diff --git a/tools/testing/ktest/examples/crosstests.conf b/tools/testing/ktest/examples/crosstests.conf
index 46736604c26c..a1203148dfa1 100644
--- a/tools/testing/ktest/examples/crosstests.conf
+++ b/tools/testing/ktest/examples/crosstests.conf
@@ -133,12 +133,6 @@ CROSS = frv-linux
133ARCH = frv 133ARCH = frv
134GCC_VER = 4.5.1 134GCC_VER = 4.5.1
135 135
136# h8300 - failed make defconfig??
137TEST_START IF ${RUN} == h8300 || ${DO_FAILED}
138CROSS = h8300-elf
139ARCH = h8300
140GCC_VER = 4.5.1
141
142# m68k fails with error? 136# m68k fails with error?
143TEST_START IF ${RUN} == m68k || ${DO_DEFAULT} 137TEST_START IF ${RUN} == m68k || ${DO_DEFAULT}
144CROSS = m68k-linux 138CROSS = m68k-linux
diff --git a/tools/testing/selftests/timers/posix_timers.c b/tools/testing/selftests/timers/posix_timers.c
index 4fa655d68a81..41bd85559d4b 100644
--- a/tools/testing/selftests/timers/posix_timers.c
+++ b/tools/testing/selftests/timers/posix_timers.c
@@ -151,7 +151,7 @@ static int check_timer_create(int which)
151 fflush(stdout); 151 fflush(stdout);
152 152
153 done = 0; 153 done = 0;
154 timer_create(which, NULL, &id); 154 err = timer_create(which, NULL, &id);
155 if (err < 0) { 155 if (err < 0) {
156 perror("Can't create timer\n"); 156 perror("Can't create timer\n");
157 return -1; 157 return -1;
diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile
new file mode 100644
index 000000000000..447321104ec0
--- /dev/null
+++ b/tools/thermal/tmon/Makefile
@@ -0,0 +1,47 @@
1VERSION = 1.0
2
3BINDIR=usr/bin
4WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
5CFLAGS= -O1 ${WARNFLAGS} -fstack-protector
6CC=gcc
7
8CFLAGS+=-D VERSION=\"$(VERSION)\"
9LDFLAGS+=
10TARGET=tmon
11
12INSTALL_PROGRAM=install -m 755 -p
13DEL_FILE=rm -f
14
15INSTALL_CONFIGFILE=install -m 644 -p
16CONFIG_FILE=
17CONFIG_PATH=
18
19
20OBJS = tmon.o tui.o sysfs.o pid.o
21OBJS +=
22
23tmon: $(OBJS) Makefile tmon.h
24 $(CC) ${CFLAGS} $(LDFLAGS) $(OBJS) -o $(TARGET) -lm -lpanel -lncursesw -lpthread
25
26valgrind: tmon
27 sudo valgrind -v --track-origins=yes --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./$(TARGET) 1> /dev/null
28
29install:
30 - mkdir -p $(INSTALL_ROOT)/$(BINDIR)
31 - $(INSTALL_PROGRAM) "$(TARGET)" "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)"
32 - mkdir -p $(INSTALL_ROOT)/$(CONFIG_PATH)
33 - $(INSTALL_CONFIGFILE) "$(CONFIG_FILE)" "$(INSTALL_ROOT)/$(CONFIG_PATH)"
34
35uninstall:
36 $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)"
37 $(CONFIG_FILE) "$(CONFIG_PATH)"
38
39
40clean:
41 find . -name "*.o" | xargs $(DEL_FILE)
42 rm -f $(TARGET)
43
44dist:
45 git tag v$(VERSION)
46 git archive --format=tar --prefix="$(TARGET)-$(VERSION)/" v$(VERSION) | \
47 gzip > $(TARGET)-$(VERSION).tar.gz
diff --git a/tools/thermal/tmon/README b/tools/thermal/tmon/README
new file mode 100644
index 000000000000..457949897a8e
--- /dev/null
+++ b/tools/thermal/tmon/README
@@ -0,0 +1,50 @@
1TMON - A Monitoring and Testing Tool for Linux kernel thermal subsystem
2
3Why TMON?
4==========
5Increasingly, Linux is running on thermally constrained devices. The simple
6thermal relationship between processor and fan has become past for modern
7computers.
8
9As hardware vendors cope with the thermal constraints on their products, more
10and more sensors are added, new cooling capabilities are introduced. The
11complexity of the thermal relationship can grow exponentially among cooling
12devices, zones, sensors, and trip points. They can also change dynamically.
13
14To expose such relationship to the userspace, Linux generic thermal layer
15introduced sysfs entry at /sys/class/thermal with a matrix of symbolic
16links, trip point bindings, and device instances. To traverse such
17matrix by hand is not a trivial task. Testing is also difficult in that
18thermal conditions are often exception cases that hard to reach in
19normal operations.
20
21TMON is conceived as a tool to help visualize, tune, and test the
22complex thermal subsystem.
23
24Files
25=====
26 tmon.c : main function for set up and configurations.
27 tui.c : handles ncurses based user interface
28 sysfs.c : access to the generic thermal sysfs
29 pid.c : a proportional-integral-derivative (PID) controller
30 that can be used for thermal relationship training.
31
32Requirements
33============
34Depends on ncurses
35
36Build
37=========
38$ make
39$ sudo ./tmon -h
40Usage: tmon [OPTION...]
41 -c, --control cooling device in control
42 -d, --daemon run as daemon, no TUI
43 -l, --log log data to /var/tmp/tmon.log
44 -h, --help show this help message
45 -t, --time-interval set time interval for sampling
46 -v, --version show version
47 -g, --debug debug message in syslog
48
491. For monitoring only:
50$ sudo ./tmon
diff --git a/tools/thermal/tmon/pid.c b/tools/thermal/tmon/pid.c
new file mode 100644
index 000000000000..fd7e9e9d6f4a
--- /dev/null
+++ b/tools/thermal/tmon/pid.c
@@ -0,0 +1,131 @@
1/*
2 * pid.c PID controller for testing cooling devices
3 *
4 *
5 *
6 * Copyright (C) 2012 Intel Corporation. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 or later as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * Author Name Jacob Pan <jacob.jun.pan@linux.intel.com>
18 *
19 */
20
21#include <unistd.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <stdint.h>
26#include <sys/types.h>
27#include <dirent.h>
28#include <libintl.h>
29#include <ctype.h>
30#include <assert.h>
31#include <time.h>
32#include <limits.h>
33#include <math.h>
34#include <sys/stat.h>
35#include <syslog.h>
36
37#include "tmon.h"
38
39/**************************************************************************
40 * PID (Proportional-Integral-Derivative) controller is commonly used in
41 * linear control system, consider the the process.
42 * G(s) = U(s)/E(s)
43 * kp = proportional gain
44 * ki = integral gain
45 * kd = derivative gain
46 * Ts
47 * We use type C Alan Bradley equation which takes set point off the
48 * output dependency in P and D term.
49 *
50 * y[k] = y[k-1] - kp*(x[k] - x[k-1]) + Ki*Ts*e[k] - Kd*(x[k]
51 * - 2*x[k-1]+x[k-2])/Ts
52 *
53 *
54 ***********************************************************************/
55struct pid_params p_param;
56/* cached data from previous loop */
57static double xk_1, xk_2; /* input temperature x[k-#] */
58
59/*
60 * TODO: make PID parameters tuned automatically,
61 * 1. use CPU burn to produce open loop unit step response
62 * 2. calculate PID based on Ziegler-Nichols rule
63 *
64 * add a flag for tuning PID
65 */
66int init_thermal_controller(void)
67{
68 int ret = 0;
69
70 /* init pid params */
71 p_param.ts = ticktime;
72 /* TODO: get it from TUI tuning tab */
73 p_param.kp = .36;
74 p_param.ki = 5.0;
75 p_param.kd = 0.19;
76
77 p_param.t_target = target_temp_user;
78
79 return ret;
80}
81
82void controller_reset(void)
83{
84 /* TODO: relax control data when not over thermal limit */
85 syslog(LOG_DEBUG, "TC inactive, relax p-state\n");
86 p_param.y_k = 0.0;
87 xk_1 = 0.0;
88 xk_2 = 0.0;
89 set_ctrl_state(0);
90}
91
92/* To be called at time interval Ts. Type C PID controller.
93 * y[k] = y[k-1] - kp*(x[k] - x[k-1]) + Ki*Ts*e[k] - Kd*(x[k]
94 * - 2*x[k-1]+x[k-2])/Ts
95 * TODO: add low pass filter for D term
96 */
97#define GUARD_BAND (2)
98void controller_handler(const double xk, double *yk)
99{
100 double ek;
101 double p_term, i_term, d_term;
102
103 ek = p_param.t_target - xk; /* error */
104 if (ek >= 3.0) {
105 syslog(LOG_DEBUG, "PID: %3.1f Below set point %3.1f, stop\n",
106 xk, p_param.t_target);
107 controller_reset();
108 *yk = 0.0;
109 return;
110 }
111 /* compute intermediate PID terms */
112 p_term = -p_param.kp * (xk - xk_1);
113 i_term = p_param.kp * p_param.ki * p_param.ts * ek;
114 d_term = -p_param.kp * p_param.kd * (xk - 2 * xk_1 + xk_2) / p_param.ts;
115 /* compute output */
116 *yk += p_term + i_term + d_term;
117 /* update sample data */
118 xk_1 = xk;
119 xk_2 = xk_1;
120
121 /* clamp output adjustment range */
122 if (*yk < -LIMIT_HIGH)
123 *yk = -LIMIT_HIGH;
124 else if (*yk > -LIMIT_LOW)
125 *yk = -LIMIT_LOW;
126
127 p_param.y_k = *yk;
128
129 set_ctrl_state(lround(fabs(p_param.y_k)));
130
131}
diff --git a/tools/thermal/tmon/sysfs.c b/tools/thermal/tmon/sysfs.c
new file mode 100644
index 000000000000..dfe454855cd2
--- /dev/null
+++ b/tools/thermal/tmon/sysfs.c
@@ -0,0 +1,596 @@
1/*
2 * sysfs.c sysfs ABI access functions for TMON program
3 *
4 * Copyright (C) 2013 Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 or later as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * Author: Jacob Pan <jacob.jun.pan@linux.intel.com>
16 *
17 */
18#include <unistd.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <stdint.h>
23#include <dirent.h>
24#include <libintl.h>
25#include <ctype.h>
26#include <time.h>
27#include <syslog.h>
28#include <sys/time.h>
29#include <errno.h>
30
31#include "tmon.h"
32
33struct tmon_platform_data ptdata;
34const char *trip_type_name[] = {
35 "critical",
36 "hot",
37 "passive",
38 "active",
39};
40
41int sysfs_set_ulong(char *path, char *filename, unsigned long val)
42{
43 FILE *fd;
44 int ret = -1;
45 char filepath[256];
46
47 snprintf(filepath, 256, "%s/%s", path, filename);
48
49 fd = fopen(filepath, "w");
50 if (!fd) {
51 syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath);
52 return ret;
53 }
54 ret = fprintf(fd, "%lu", val);
55 fclose(fd);
56
57 return 0;
58}
59
60/* history of thermal data, used for control algo */
61#define NR_THERMAL_RECORDS 3
62struct thermal_data_record trec[NR_THERMAL_RECORDS];
63int cur_thermal_record; /* index to the trec array */
64
65static int sysfs_get_ulong(char *path, char *filename, unsigned long *p_ulong)
66{
67 FILE *fd;
68 int ret = -1;
69 char filepath[256];
70
71 snprintf(filepath, 256, "%s/%s", path, filename);
72
73 fd = fopen(filepath, "r");
74 if (!fd) {
75 syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath);
76 return ret;
77 }
78 ret = fscanf(fd, "%lu", p_ulong);
79 fclose(fd);
80
81 return 0;
82}
83
84static int sysfs_get_string(char *path, char *filename, char *str)
85{
86 FILE *fd;
87 int ret = -1;
88 char filepath[256];
89
90 snprintf(filepath, 256, "%s/%s", path, filename);
91
92 fd = fopen(filepath, "r");
93 if (!fd) {
94 syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath);
95 return ret;
96 }
97 ret = fscanf(fd, "%256s", str);
98 fclose(fd);
99
100 return ret;
101}
102
103/* get states of the cooling device instance */
104static int probe_cdev(struct cdev_info *cdi, char *path)
105{
106 sysfs_get_string(path, "type", cdi->type);
107 sysfs_get_ulong(path, "max_state", &cdi->max_state);
108 sysfs_get_ulong(path, "cur_state", &cdi->cur_state);
109
110 syslog(LOG_INFO, "%s: %s: type %s, max %lu, curr %lu inst %d\n",
111 __func__, path,
112 cdi->type, cdi->max_state, cdi->cur_state, cdi->instance);
113
114 return 0;
115}
116
117static int str_to_trip_type(char *name)
118{
119 int i;
120
121 for (i = 0; i < NR_THERMAL_TRIP_TYPE; i++) {
122 if (!strcmp(name, trip_type_name[i]))
123 return i;
124 }
125
126 return -ENOENT;
127}
128
129/* scan and fill in trip point info for a thermal zone and trip point id */
130static int get_trip_point_data(char *tz_path, int tzid, int tpid)
131{
132 char filename[256];
133 char temp_str[256];
134 int trip_type;
135
136 if (tpid >= MAX_NR_TRIP)
137 return -EINVAL;
138 /* check trip point type */
139 snprintf(filename, sizeof(filename), "trip_point_%d_type", tpid);
140 sysfs_get_string(tz_path, filename, temp_str);
141 trip_type = str_to_trip_type(temp_str);
142 if (trip_type < 0) {
143 syslog(LOG_ERR, "%s:%s no matching type\n", __func__, temp_str);
144 return -ENOENT;
145 }
146 ptdata.tzi[tzid].tp[tpid].type = trip_type;
147 syslog(LOG_INFO, "%s:tz:%d tp:%d:type:%s type id %d\n", __func__, tzid,
148 tpid, temp_str, trip_type);
149
150 /* TODO: check attribute */
151
152 return 0;
153}
154
155/* return instance id for file format such as trip_point_4_temp */
156static int get_instance_id(char *name, int pos, int skip)
157{
158 char *ch;
159 int i = 0;
160
161 ch = strtok(name, "_");
162 while (ch != NULL) {
163 ++i;
164 syslog(LOG_INFO, "%s:%s:%s:%d", __func__, name, ch, i);
165 ch = strtok(NULL, "_");
166 if (pos == i)
167 return atol(ch + skip);
168 }
169
170 return -1;
171}
172
173/* Find trip point info of a thermal zone */
174static int find_tzone_tp(char *tz_name, char *d_name, struct tz_info *tzi,
175 int tz_id)
176{
177 int tp_id;
178 unsigned long temp_ulong;
179
180 if (strstr(d_name, "trip_point") &&
181 strstr(d_name, "temp")) {
182 /* check if trip point temp is non-zero
183 * ignore 0/invalid trip points
184 */
185 sysfs_get_ulong(tz_name, d_name, &temp_ulong);
186 if (temp_ulong < MAX_TEMP_KC) {
187 tzi->nr_trip_pts++;
188 /* found a valid trip point */
189 tp_id = get_instance_id(d_name, 2, 0);
190 syslog(LOG_DEBUG, "tzone %s trip %d temp %lu tpnode %s",
191 tz_name, tp_id, temp_ulong, d_name);
192 if (tp_id < 0 || tp_id >= MAX_NR_TRIP) {
193 syslog(LOG_ERR, "Failed to find TP inst %s\n",
194 d_name);
195 return -1;
196 }
197 get_trip_point_data(tz_name, tz_id, tp_id);
198 tzi->tp[tp_id].temp = temp_ulong;
199 }
200 }
201
202 return 0;
203}
204
205/* check cooling devices for binding info. */
206static int find_tzone_cdev(struct dirent *nl, char *tz_name,
207 struct tz_info *tzi, int tz_id, int cid)
208{
209 unsigned long trip_instance = 0;
210 char cdev_name_linked[256];
211 char cdev_name[256];
212 char cdev_trip_name[256];
213 int cdev_id;
214
215 if (nl->d_type == DT_LNK) {
216 syslog(LOG_DEBUG, "TZ%d: cdev: %s cid %d\n", tz_id, nl->d_name,
217 cid);
218 tzi->nr_cdev++;
219 if (tzi->nr_cdev > ptdata.nr_cooling_dev) {
220 syslog(LOG_ERR, "Err: Too many cdev? %d\n",
221 tzi->nr_cdev);
222 return -EINVAL;
223 }
224 /* find the link to real cooling device record binding */
225 snprintf(cdev_name, 256, "%s/%s", tz_name, nl->d_name);
226 memset(cdev_name_linked, 0, sizeof(cdev_name_linked));
227 if (readlink(cdev_name, cdev_name_linked,
228 sizeof(cdev_name_linked) - 1) != -1) {
229 cdev_id = get_instance_id(cdev_name_linked, 1,
230 sizeof("device") - 1);
231 syslog(LOG_DEBUG, "cdev %s linked to %s : %d\n",
232 cdev_name, cdev_name_linked, cdev_id);
233 tzi->cdev_binding |= (1 << cdev_id);
234
235 /* find the trip point in which the cdev is binded to
236 * in this tzone
237 */
238 snprintf(cdev_trip_name, 256, "%s%s", nl->d_name,
239 "_trip_point");
240 sysfs_get_ulong(tz_name, cdev_trip_name,
241 &trip_instance);
242 /* validate trip point range, e.g. trip could return -1
243 * when passive is enabled
244 */
245 if (trip_instance > MAX_NR_TRIP)
246 trip_instance = 0;
247 tzi->trip_binding[cdev_id] |= 1 << trip_instance;
248 syslog(LOG_DEBUG, "cdev %s -> trip:%lu: 0x%lx %d\n",
249 cdev_name, trip_instance,
250 tzi->trip_binding[cdev_id],
251 cdev_id);
252
253
254 }
255 return 0;
256 }
257
258 return -ENODEV;
259}
260
261
262
263/*****************************************************************************
264 * Before calling scan_tzones, thermal sysfs must be probed to determine
265 * the number of thermal zones and cooling devices.
266 * We loop through each thermal zone and fill in tz_info struct, i.e.
267 * ptdata.tzi[]
268root@jacob-chiefriver:~# tree -d /sys/class/thermal/thermal_zone0
269/sys/class/thermal/thermal_zone0
270|-- cdev0 -> ../cooling_device4
271|-- cdev1 -> ../cooling_device3
272|-- cdev10 -> ../cooling_device7
273|-- cdev11 -> ../cooling_device6
274|-- cdev12 -> ../cooling_device5
275|-- cdev2 -> ../cooling_device2
276|-- cdev3 -> ../cooling_device1
277|-- cdev4 -> ../cooling_device0
278|-- cdev5 -> ../cooling_device12
279|-- cdev6 -> ../cooling_device11
280|-- cdev7 -> ../cooling_device10
281|-- cdev8 -> ../cooling_device9
282|-- cdev9 -> ../cooling_device8
283|-- device -> ../../../LNXSYSTM:00/device:62/LNXTHERM:00
284|-- power
285`-- subsystem -> ../../../../class/thermal
286*****************************************************************************/
287static int scan_tzones(void)
288{
289 DIR *dir;
290 struct dirent **namelist;
291 char tz_name[256];
292 int i, j, n, k = 0;
293
294 if (!ptdata.nr_tz_sensor)
295 return -1;
296
297 for (i = 0; i <= ptdata.max_tz_instance; i++) {
298 memset(tz_name, 0, sizeof(tz_name));
299 snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, i);
300
301 dir = opendir(tz_name);
302 if (!dir) {
303 syslog(LOG_INFO, "Thermal zone %s skipped\n", tz_name);
304 continue;
305 }
306 /* keep track of valid tzones */
307 n = scandir(tz_name, &namelist, 0, alphasort);
308 if (n < 0)
309 syslog(LOG_ERR, "scandir failed in %s", tz_name);
310 else {
311 sysfs_get_string(tz_name, "type", ptdata.tzi[k].type);
312 ptdata.tzi[k].instance = i;
313 /* detect trip points and cdev attached to this tzone */
314 j = 0; /* index for cdev */
315 ptdata.tzi[k].nr_cdev = 0;
316 ptdata.tzi[k].nr_trip_pts = 0;
317 while (n--) {
318 char *temp_str;
319
320 if (find_tzone_tp(tz_name, namelist[n]->d_name,
321 &ptdata.tzi[k], k))
322 break;
323 temp_str = strstr(namelist[n]->d_name, "cdev");
324 if (!temp_str) {
325 free(namelist[n]);
326 continue;
327 }
328 if (!find_tzone_cdev(namelist[n], tz_name,
329 &ptdata.tzi[k], i, j))
330 j++; /* increment cdev index */
331 free(namelist[n]);
332 }
333 free(namelist);
334 }
335 /*TODO: reverse trip points */
336 closedir(dir);
337 syslog(LOG_INFO, "TZ %d has %d cdev\n", i,
338 ptdata.tzi[k].nr_cdev);
339 k++;
340 }
341
342 return 0;
343}
344
345static int scan_cdevs(void)
346{
347 DIR *dir;
348 struct dirent **namelist;
349 char cdev_name[256];
350 int i, n, k = 0;
351
352 if (!ptdata.nr_cooling_dev) {
353 fprintf(stderr, "No cooling devices found\n");
354 return 0;
355 }
356 for (i = 0; i <= ptdata.max_cdev_instance; i++) {
357 memset(cdev_name, 0, sizeof(cdev_name));
358 snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV, i);
359
360 dir = opendir(cdev_name);
361 if (!dir) {
362 syslog(LOG_INFO, "Cooling dev %s skipped\n", cdev_name);
363 /* there is a gap in cooling device id, check again
364 * for the same index.
365 */
366 continue;
367 }
368
369 n = scandir(cdev_name, &namelist, 0, alphasort);
370 if (n < 0)
371 syslog(LOG_ERR, "scandir failed in %s", cdev_name);
372 else {
373 sysfs_get_string(cdev_name, "type", ptdata.cdi[k].type);
374 ptdata.cdi[k].instance = i;
375 if (strstr(ptdata.cdi[k].type, ctrl_cdev)) {
376 ptdata.cdi[k].flag |= CDEV_FLAG_IN_CONTROL;
377 syslog(LOG_DEBUG, "control cdev id %d\n", i);
378 }
379 while (n--)
380 free(namelist[n]);
381 free(namelist);
382 }
383 closedir(dir);
384 k++;
385 }
386 return 0;
387}
388
389
390int probe_thermal_sysfs(void)
391{
392 DIR *dir;
393 struct dirent **namelist;
394 int n;
395
396 dir = opendir(THERMAL_SYSFS);
397 if (!dir) {
398 fprintf(stderr, "\nNo thermal sysfs, exit\n");
399 return -1;
400 }
401 n = scandir(THERMAL_SYSFS, &namelist, 0, alphasort);
402 if (n < 0)
403 syslog(LOG_ERR, "scandir failed in thermal sysfs");
404 else {
405 /* detect number of thermal zones and cooling devices */
406 while (n--) {
407 int inst;
408
409 if (strstr(namelist[n]->d_name, CDEV)) {
410 inst = get_instance_id(namelist[n]->d_name, 1,
411 sizeof("device") - 1);
412 /* keep track of the max cooling device since
413 * there may be gaps.
414 */
415 if (inst > ptdata.max_cdev_instance)
416 ptdata.max_cdev_instance = inst;
417
418 syslog(LOG_DEBUG, "found cdev: %s %d %d\n",
419 namelist[n]->d_name,
420 ptdata.nr_cooling_dev,
421 ptdata.max_cdev_instance);
422 ptdata.nr_cooling_dev++;
423 } else if (strstr(namelist[n]->d_name, TZONE)) {
424 inst = get_instance_id(namelist[n]->d_name, 1,
425 sizeof("zone") - 1);
426 if (inst > ptdata.max_tz_instance)
427 ptdata.max_tz_instance = inst;
428
429 syslog(LOG_DEBUG, "found tzone: %s %d %d\n",
430 namelist[n]->d_name,
431 ptdata.nr_tz_sensor,
432 ptdata.max_tz_instance);
433 ptdata.nr_tz_sensor++;
434 }
435 free(namelist[n]);
436 }
437 free(namelist);
438 }
439 syslog(LOG_INFO, "found %d tzone(s), %d cdev(s), target zone %d\n",
440 ptdata.nr_tz_sensor, ptdata.nr_cooling_dev,
441 target_thermal_zone);
442 closedir(dir);
443
444 if (!ptdata.nr_tz_sensor) {
445 fprintf(stderr, "\nNo thermal zones found, exit\n\n");
446 return -1;
447 }
448
449 ptdata.tzi = calloc(sizeof(struct tz_info), ptdata.max_tz_instance+1);
450 if (!ptdata.tzi) {
451 fprintf(stderr, "Err: allocate tz_info\n");
452 return -1;
453 }
454
455 /* we still show thermal zone information if there is no cdev */
456 if (ptdata.nr_cooling_dev) {
457 ptdata.cdi = calloc(sizeof(struct cdev_info),
458 ptdata.max_cdev_instance + 1);
459 if (!ptdata.cdi) {
460 free(ptdata.tzi);
461 fprintf(stderr, "Err: allocate cdev_info\n");
462 return -1;
463 }
464 }
465
466 /* now probe tzones */
467 if (scan_tzones())
468 return -1;
469 if (scan_cdevs())
470 return -1;
471 return 0;
472}
473
474/* convert sysfs zone instance to zone array index */
475int zone_instance_to_index(int zone_inst)
476{
477 int i;
478
479 for (i = 0; i < ptdata.nr_tz_sensor; i++)
480 if (ptdata.tzi[i].instance == zone_inst)
481 return i;
482 return -ENOENT;
483}
484
485/* read temperature of all thermal zones */
486int update_thermal_data()
487{
488 int i;
489 char tz_name[256];
490 static unsigned long samples;
491
492 if (!ptdata.nr_tz_sensor) {
493 syslog(LOG_ERR, "No thermal zones found!\n");
494 return -1;
495 }
496
497 /* circular buffer for keeping historic data */
498 if (cur_thermal_record >= NR_THERMAL_RECORDS)
499 cur_thermal_record = 0;
500 gettimeofday(&trec[cur_thermal_record].tv, NULL);
501 if (tmon_log) {
502 fprintf(tmon_log, "%lu ", ++samples);
503 fprintf(tmon_log, "%3.1f ", p_param.t_target);
504 }
505 for (i = 0; i < ptdata.nr_tz_sensor; i++) {
506 memset(tz_name, 0, sizeof(tz_name));
507 snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE,
508 ptdata.tzi[i].instance);
509 sysfs_get_ulong(tz_name, "temp",
510 &trec[cur_thermal_record].temp[i]);
511 if (tmon_log)
512 fprintf(tmon_log, "%lu ",
513 trec[cur_thermal_record].temp[i]/1000);
514 }
515 for (i = 0; i < ptdata.nr_cooling_dev; i++) {
516 char cdev_name[256];
517 unsigned long val;
518
519 snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV,
520 ptdata.cdi[i].instance);
521 probe_cdev(&ptdata.cdi[i], cdev_name);
522 val = ptdata.cdi[i].cur_state;
523 if (val > 1000000)
524 val = 0;
525 if (tmon_log)
526 fprintf(tmon_log, "%lu ", val);
527 }
528
529 if (tmon_log) {
530 fprintf(tmon_log, "\n");
531 fflush(tmon_log);
532 }
533
534 return 0;
535}
536
537void set_ctrl_state(unsigned long state)
538{
539 char ctrl_cdev_path[256];
540 int i;
541 unsigned long cdev_state;
542
543 if (no_control)
544 return;
545 /* set all ctrl cdev to the same state */
546 for (i = 0; i < ptdata.nr_cooling_dev; i++) {
547 if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) {
548 if (ptdata.cdi[i].max_state < 10) {
549 strcpy(ctrl_cdev, "None.");
550 return;
551 }
552 /* scale to percentage of max_state */
553 cdev_state = state * ptdata.cdi[i].max_state/100;
554 syslog(LOG_DEBUG,
555 "ctrl cdev %d set state %lu scaled to %lu\n",
556 ptdata.cdi[i].instance, state, cdev_state);
557 snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS,
558 CDEV, ptdata.cdi[i].instance);
559 syslog(LOG_DEBUG, "ctrl cdev path %s", ctrl_cdev_path);
560 sysfs_set_ulong(ctrl_cdev_path, "cur_state",
561 cdev_state);
562 }
563 }
564}
565
566void get_ctrl_state(unsigned long *state)
567{
568 char ctrl_cdev_path[256];
569 int ctrl_cdev_id = -1;
570 int i;
571
572 /* TODO: take average of all ctrl types. also consider change based on
573 * uevent. Take the first reading for now.
574 */
575 for (i = 0; i < ptdata.nr_cooling_dev; i++) {
576 if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) {
577 ctrl_cdev_id = ptdata.cdi[i].instance;
578 syslog(LOG_INFO, "ctrl cdev %d get state\n",
579 ptdata.cdi[i].instance);
580 break;
581 }
582 }
583 if (ctrl_cdev_id == -1) {
584 *state = 0;
585 return;
586 }
587 snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS,
588 CDEV, ctrl_cdev_id);
589 sysfs_get_ulong(ctrl_cdev_path, "cur_state", state);
590}
591
592void free_thermal_data(void)
593{
594 free(ptdata.tzi);
595 free(ptdata.cdi);
596}
diff --git a/tools/thermal/tmon/tmon.8 b/tools/thermal/tmon/tmon.8
new file mode 100644
index 000000000000..0be727cb9892
--- /dev/null
+++ b/tools/thermal/tmon/tmon.8
@@ -0,0 +1,142 @@
1.TH TMON 8
2.SH NAME
3\fBtmon\fP - A monitoring and testing tool for Linux kernel thermal subsystem
4
5.SH SYNOPSIS
6.ft B
7.B tmon
8.RB [ Options ]
9.br
10.SH DESCRIPTION
11\fBtmon \fP can be used to visualize thermal relationship and
12real-time thermal data; tune
13and test cooling devices and sensors; collect thermal data for offline
14analysis and plot. \fBtmon\fP must be run as root in order to control device
15states via sysfs.
16.PP
17\fBFunctions\fP
18.PP
19.nf
201. Thermal relationships:
21- show thermal zone information
22- show cooling device information
23- show trip point binding within each thermal zone
24- show trip point and cooling device instance bindings
25.PP
262. Real time data display
27- show temperature of all thermal zones w.r.t. its trip points and types
28- show states of all cooling devices
29.PP
303. Thermal relationship learning and device tuning
31- with a built-in Proportional Integral Derivative (\fBPID\fP)
32controller, user can pair a cooling device to a thermal sensor for
33testing the effectiveness and learn about the thermal distance between the two
34- allow manual control of cooling device states and target temperature
35.PP
364. Data logging in /var/tmp/tmon.log
37- contains thermal configuration data, i.e. cooling device, thermal
38 zones, and trip points. Can be used for data collection in remote
39 debugging.
40- log real-time thermal data into space separated format that can be
41 directly consumed by plotting tools such as Rscript.
42
43.SS Options
44.PP
45The \fB-c --control\fP option sets a cooling device type to control temperature
46of a thermal zone
47.PP
48The \fB-d --daemon\fP option runs \fBtmon \fP as daemon without user interface
49.PP
50The \fB-g --debug\fP option allow debug messages to be stored in syslog
51.PP
52The \fB-h --help\fP option shows help message
53.PP
54The \fB-l --log\fP option write data to /var/tmp/tmon.log
55.PP
56The \fB-t --time-interval\fP option sets the polling interval in seconds
57.PP
58The \fB-v --version\fP option shows the version of \fBtmon \fP
59.PP
60The \fB-z --zone\fP option sets the target therma zone instance to be controlled
61.PP
62
63.SH FIELD DESCRIPTIONS
64.nf
65.PP
66\fBP \fP passive cooling trip point type
67\fBA \fP active cooling trip point type (fan)
68\fBC \fP critical trip point type
69\fBA \fP hot trip point type
70\fBkp \fP proportional gain of \fBPID\fP controller
71\fBki \fP integral gain of \fBPID\fP controller
72\fBkd \fP derivative gain of \fBPID\fP controller
73
74.SH REQUIREMENT
75Build depends on ncurses
76.PP
77Runtime depends on window size large enough to show the number of
78devices found on the system.
79
80.PP
81
82.SH INTERACTIVE COMMANDS
83.pp
84.nf
85\fBCtrl-C, q/Q\fP stops \fBtmon\fP
86\fBTAB\fP shows tuning pop up panel, choose a letter to modify
87
88.SH EXAMPLES
89Without any parameters, tmon is in monitoring only mode and refresh
90screen every 1 second.
91.PP
921. For monitoring only:
93.nf
94$ sudo ./tmon
95
962. Use Processor cooling device to control thermal zone 0 at default 65C.
97$ sudo ./tmon -c Processor -z 0
98
993. Use intel_powerclamp(idle injection) cooling device to control thermal zone 1
100$ sudo ./tmon -c intel_powerclamp -z 1
101
1024. Turn on debug and collect data log at /var/tmp/tmon.log
103$ sudo ./tmon -g -l
104
105For example, the log below shows PID controller was adjusting current states
106for all cooling devices with "Processor" type such that thermal zone 0
107can stay below 65 dC.
108
109#---------- THERMAL DATA LOG STARTED -----------
110Samples TargetTemp acpitz0 acpitz1 Fan0 Fan1 Fan2 Fan3 Fan4 Fan5
111Fan6 Fan7 Fan8 Fan9 Processor10 Processor11 Processor12 Processor13
112LCD14 intel_powerclamp15 1 65.0 65 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 2
11365.0 66 65 0 0 0 0 0 0 0 0 0 0 4 4 4 4 6 0 3 65.0 60 54 0 0 0 0 0 0 0 0
1140 0 4 4 4 4 6 0 4 65.0 53 53 0 0 0 0 0 0 0 0 0 0 4 4 4 4 6 0
1155 65.0 52 52 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0
1166 65.0 53 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0
1177 65.0 68 70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0
1188 65.0 68 68 0 0 0 0 0 0 0 0 0 0 5 5 5 5 6 0
1199 65.0 68 68 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 0
12010 65.0 67 67 0 0 0 0 0 0 0 0 0 0 7 7 7 7 6 0
12111 65.0 67 67 0 0 0 0 0 0 0 0 0 0 8 8 8 8 6 0
12212 65.0 67 67 0 0 0 0 0 0 0 0 0 0 8 8 8 8 6 0
12313 65.0 67 67 0 0 0 0 0 0 0 0 0 0 9 9 9 9 6 0
12414 65.0 66 66 0 0 0 0 0 0 0 0 0 0 10 10 10 10 6 0
12515 65.0 66 67 0 0 0 0 0 0 0 0 0 0 10 10 10 10 6 0
12616 65.0 66 66 0 0 0 0 0 0 0 0 0 0 11 11 11 11 6 0
12717 65.0 66 66 0 0 0 0 0 0 0 0 0 0 11 11 11 11 6 0
12818 65.0 64 61 0 0 0 0 0 0 0 0 0 0 11 11 11 11 6 0
12919 65.0 60 59 0 0 0 0 0 0 0 0 0 0 12 12 12 12 6 0
130
131Data can be read directly into an array by an example R-script below:
132
133#!/usr/bin/Rscript
134tdata <- read.table("/var/tmp/tmon.log", header=T, comment.char="#")
135attach(tdata)
136jpeg("tmon.jpg")
137X11()
138g_range <- range(0, intel_powerclamp15, TargetTemp, acpitz0)
139plot( Samples, intel_powerclamp15, col="blue", ylim=g_range, axes=FALSE, ann=FALSE)
140par(new=TRUE)
141lines(TargetTemp, type="o", pch=22, lty=2, col="red")
142dev.off()
diff --git a/tools/thermal/tmon/tmon.c b/tools/thermal/tmon/tmon.c
new file mode 100644
index 000000000000..b30f531173e4
--- /dev/null
+++ b/tools/thermal/tmon/tmon.c
@@ -0,0 +1,352 @@
1/*
2 * tmon.c Thermal Monitor (TMON) main function and entry point
3 *
4 * Copyright (C) 2012 Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 or later as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * Author: Jacob Pan <jacob.jun.pan@linux.intel.com>
16 *
17 */
18
19#include <getopt.h>
20#include <unistd.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <ncurses.h>
27#include <ctype.h>
28#include <time.h>
29#include <signal.h>
30#include <limits.h>
31#include <sys/time.h>
32#include <pthread.h>
33#include <math.h>
34#include <stdarg.h>
35#include <syslog.h>
36
37#include "tmon.h"
38
39unsigned long ticktime = 1; /* seconds */
40unsigned long no_control = 1; /* monitoring only or use cooling device for
41 * temperature control.
42 */
43double time_elapsed = 0.0;
44unsigned long target_temp_user = 65; /* can be select by tui later */
45int dialogue_on;
46int tmon_exit;
47static short daemon_mode;
48static int logging; /* for recording thermal data to a file */
49static int debug_on;
50FILE *tmon_log;
51/*cooling device used for the PID controller */
52char ctrl_cdev[CDEV_NAME_SIZE] = "None";
53int target_thermal_zone; /* user selected target zone instance */
54static void start_daemon_mode(void);
55
56pthread_t event_tid;
57pthread_mutex_t input_lock;
58void usage()
59{
60 printf("Usage: tmon [OPTION...]\n");
61 printf(" -c, --control cooling device in control\n");
62 printf(" -d, --daemon run as daemon, no TUI\n");
63 printf(" -g, --debug debug message in syslog\n");
64 printf(" -h, --help show this help message\n");
65 printf(" -l, --log log data to /var/tmp/tmon.log\n");
66 printf(" -t, --time-interval sampling time interval, > 1 sec.\n");
67 printf(" -v, --version show version\n");
68 printf(" -z, --zone target thermal zone id\n");
69
70 exit(0);
71}
72
73void version()
74{
75 printf("TMON version %s\n", VERSION);
76 exit(EXIT_SUCCESS);
77}
78
79static void tmon_cleanup(void)
80{
81
82 syslog(LOG_INFO, "TMON exit cleanup\n");
83 fflush(stdout);
84 refresh();
85 if (tmon_log)
86 fclose(tmon_log);
87 if (event_tid) {
88 pthread_mutex_lock(&input_lock);
89 pthread_cancel(event_tid);
90 pthread_mutex_unlock(&input_lock);
91 pthread_mutex_destroy(&input_lock);
92 }
93 closelog();
94 /* relax control knobs, undo throttling */
95 set_ctrl_state(0);
96
97 keypad(stdscr, FALSE);
98 echo();
99 nocbreak();
100 close_windows();
101 endwin();
102 free_thermal_data();
103
104 exit(1);
105}
106
107
108static void tmon_sig_handler(int sig)
109{
110 syslog(LOG_INFO, "TMON caught signal %d\n", sig);
111 refresh();
112 switch (sig) {
113 case SIGTERM:
114 printf("sigterm, exit and clean up\n");
115 fflush(stdout);
116 break;
117 case SIGKILL:
118 printf("sigkill, exit and clean up\n");
119 fflush(stdout);
120 break;
121 case SIGINT:
122 printf("ctrl-c, exit and clean up\n");
123 fflush(stdout);
124 break;
125 default:
126 break;
127 }
128 tmon_exit = true;
129}
130
131
132static void start_syslog(void)
133{
134 if (debug_on)
135 setlogmask(LOG_UPTO(LOG_DEBUG));
136 else
137 setlogmask(LOG_UPTO(LOG_ERR));
138 openlog("tmon.log", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL0);
139 syslog(LOG_NOTICE, "TMON started by User %d", getuid());
140}
141
142static void prepare_logging(void)
143{
144 int i;
145
146 if (!logging)
147 return;
148 /* open local data log file */
149 tmon_log = fopen(TMON_LOG_FILE, "w+");
150 if (!tmon_log) {
151 syslog(LOG_ERR, "failed to open log file %s\n", TMON_LOG_FILE);
152 return;
153 }
154
155 fprintf(tmon_log, "#----------- THERMAL SYSTEM CONFIG -------------\n");
156 for (i = 0; i < ptdata.nr_tz_sensor; i++) {
157 char binding_str[33]; /* size of long + 1 */
158 int j;
159
160 memset(binding_str, 0, sizeof(binding_str));
161 for (j = 0; j < 32; j++)
162 binding_str[j] = (ptdata.tzi[i].cdev_binding & 1<<j) ?
163 '1' : '0';
164
165 fprintf(tmon_log, "#thermal zone %s%02d cdevs binding: %32s\n",
166 ptdata.tzi[i].type,
167 ptdata.tzi[i].instance,
168 binding_str);
169 for (j = 0; j < ptdata.tzi[i].nr_trip_pts; j++) {
170 fprintf(tmon_log, "#\tTP%02d type:%s, temp:%lu\n", j,
171 trip_type_name[ptdata.tzi[i].tp[j].type],
172 ptdata.tzi[i].tp[j].temp);
173 }
174
175 }
176
177 for (i = 0; i < ptdata.nr_cooling_dev; i++)
178 fprintf(tmon_log, "#cooling devices%02d: %s\n",
179 i, ptdata.cdi[i].type);
180
181 fprintf(tmon_log, "#---------- THERMAL DATA LOG STARTED -----------\n");
182 fprintf(tmon_log, "Samples TargetTemp ");
183 for (i = 0; i < ptdata.nr_tz_sensor; i++) {
184 fprintf(tmon_log, "%s%d ", ptdata.tzi[i].type,
185 ptdata.tzi[i].instance);
186 }
187 for (i = 0; i < ptdata.nr_cooling_dev; i++)
188 fprintf(tmon_log, "%s%d ", ptdata.cdi[i].type,
189 ptdata.cdi[i].instance);
190
191 fprintf(tmon_log, "\n");
192}
193
194static struct option opts[] = {
195 { "control", 1, NULL, 'c' },
196 { "daemon", 0, NULL, 'd' },
197 { "time-interval", 1, NULL, 't' },
198 { "log", 0, NULL, 'l' },
199 { "help", 0, NULL, 'h' },
200 { "version", 0, NULL, 'v' },
201 { "debug", 0, NULL, 'g' },
202 { 0, 0, NULL, 0 }
203};
204
205
206int main(int argc, char **argv)
207{
208 int err = 0;
209 int id2 = 0, c;
210 double yk = 0.0; /* controller output */
211 int target_tz_index;
212
213 if (geteuid() != 0) {
214 printf("TMON needs to be run as root\n");
215 exit(EXIT_FAILURE);
216 }
217
218 while ((c = getopt_long(argc, argv, "c:dlht:vgz:", opts, &id2)) != -1) {
219 switch (c) {
220 case 'c':
221 no_control = 0;
222 strncpy(ctrl_cdev, optarg, CDEV_NAME_SIZE);
223 break;
224 case 'd':
225 start_daemon_mode();
226 printf("Run TMON in daemon mode\n");
227 break;
228 case 't':
229 ticktime = strtod(optarg, NULL);
230 if (ticktime < 1)
231 ticktime = 1;
232 break;
233 case 'l':
234 printf("Logging data to /var/tmp/tmon.log\n");
235 logging = 1;
236 break;
237 case 'h':
238 usage();
239 break;
240 case 'v':
241 version();
242 break;
243 case 'g':
244 debug_on = 1;
245 break;
246 case 'z':
247 target_thermal_zone = strtod(optarg, NULL);
248 break;
249 default:
250 break;
251 }
252 }
253 if (pthread_mutex_init(&input_lock, NULL) != 0) {
254 fprintf(stderr, "\n mutex init failed, exit\n");
255 return 1;
256 }
257 start_syslog();
258 if (signal(SIGINT, tmon_sig_handler) == SIG_ERR)
259 syslog(LOG_DEBUG, "Cannot handle SIGINT\n");
260 if (signal(SIGTERM, tmon_sig_handler) == SIG_ERR)
261 syslog(LOG_DEBUG, "Cannot handle SIGINT\n");
262
263 if (probe_thermal_sysfs()) {
264 pthread_mutex_destroy(&input_lock);
265 closelog();
266 return -1;
267 }
268 initialize_curses();
269 setup_windows();
270 signal(SIGWINCH, resize_handler);
271 show_title_bar();
272 show_sensors_w();
273 show_cooling_device();
274 update_thermal_data();
275 show_data_w();
276 prepare_logging();
277 init_thermal_controller();
278
279 nodelay(stdscr, TRUE);
280 err = pthread_create(&event_tid, NULL, &handle_tui_events, NULL);
281 if (err != 0) {
282 printf("\ncan't create thread :[%s]", strerror(err));
283 tmon_cleanup();
284 exit(EXIT_FAILURE);
285 }
286
287 /* validate range of user selected target zone, default to the first
288 * instance if out of range
289 */
290 target_tz_index = zone_instance_to_index(target_thermal_zone);
291 if (target_tz_index < 0) {
292 target_thermal_zone = ptdata.tzi[0].instance;
293 syslog(LOG_ERR, "target zone is not found, default to %d\n",
294 target_thermal_zone);
295 }
296 while (1) {
297 sleep(ticktime);
298 show_title_bar();
299 show_sensors_w();
300 update_thermal_data();
301 if (!dialogue_on) {
302 show_data_w();
303 show_cooling_device();
304 }
305 cur_thermal_record++;
306 time_elapsed += ticktime;
307 controller_handler(trec[0].temp[target_tz_index] / 1000,
308 &yk);
309 trec[0].pid_out_pct = yk;
310 if (!dialogue_on)
311 show_control_w();
312 if (tmon_exit)
313 break;
314 }
315 tmon_cleanup();
316 return 0;
317}
318
319static void start_daemon_mode()
320{
321 daemon_mode = 1;
322 /* fork */
323 pid_t sid, pid = fork();
324 if (pid < 0) {
325 exit(EXIT_FAILURE);
326 } else if (pid > 0)
327 /* kill parent */
328 exit(EXIT_SUCCESS);
329
330 /* disable TUI, it may not be necessary, but saves some resource */
331 disable_tui();
332
333 /* change the file mode mask */
334 umask(0);
335
336 /* new SID for the daemon process */
337 sid = setsid();
338 if (sid < 0)
339 exit(EXIT_FAILURE);
340
341 /* change working directory */
342 if ((chdir("/")) < 0)
343 exit(EXIT_FAILURE);
344
345
346 sleep(10);
347
348 close(STDIN_FILENO);
349 close(STDOUT_FILENO);
350 close(STDERR_FILENO);
351
352}
diff --git a/tools/thermal/tmon/tmon.h b/tools/thermal/tmon/tmon.h
new file mode 100644
index 000000000000..9e3c49c547ac
--- /dev/null
+++ b/tools/thermal/tmon/tmon.h
@@ -0,0 +1,204 @@
1/*
2 * tmon.h contains data structures and constants used by TMON
3 *
4 * Copyright (C) 2012 Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 or later as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * Author Name Jacob Pan <jacob.jun.pan@linux.intel.com>
16 *
17 */
18
19#ifndef TMON_H
20#define TMON_H
21
22#define MAX_DISP_TEMP 125
23#define MAX_CTRL_TEMP 105
24#define MIN_CTRL_TEMP 40
25#define MAX_NR_TZONE 16
26#define MAX_NR_CDEV 32
27#define MAX_NR_TRIP 16
28#define MAX_NR_CDEV_TRIP 12 /* number of cooling devices that can bind
29 * to a thermal zone trip.
30 */
31#define MAX_TEMP_KC 140000
32/* starting char position to draw sensor data, such as tz names
33 * trip point list, etc.
34 */
35#define DATA_LEFT_ALIGN 10
36#define NR_LINES_TZDATA 1
37#define TMON_LOG_FILE "/var/tmp/tmon.log"
38
39extern unsigned long ticktime;
40extern double time_elapsed;
41extern unsigned long target_temp_user;
42extern int dialogue_on;
43extern char ctrl_cdev[];
44extern pthread_mutex_t input_lock;
45extern int tmon_exit;
46extern int target_thermal_zone;
47/* use fixed size record to simplify data processing and transfer
48 * TBD: more info to be added, e.g. programmable trip point data.
49*/
50struct thermal_data_record {
51 struct timeval tv;
52 unsigned long temp[MAX_NR_TZONE];
53 double pid_out_pct;
54};
55
56struct cdev_info {
57 char type[64];
58 int instance;
59 unsigned long max_state;
60 unsigned long cur_state;
61 unsigned long flag;
62};
63
64enum trip_type {
65 THERMAL_TRIP_CRITICAL,
66 THERMAL_TRIP_HOT,
67 THERMAL_TRIP_PASSIVE,
68 THERMAL_TRIP_ACTIVE,
69 NR_THERMAL_TRIP_TYPE,
70};
71
72struct trip_point {
73 enum trip_type type;
74 unsigned long temp;
75 unsigned long hysteresis;
76 int attribute; /* programmability etc. */
77};
78
79/* thermal zone configuration information, binding with cooling devices could
80 * change at runtime.
81 */
82struct tz_info {
83 char type[256]; /* e.g. acpitz */
84 int instance;
85 int passive; /* active zone has passive node to force passive mode */
86 int nr_cdev; /* number of cooling device binded */
87 int nr_trip_pts;
88 struct trip_point tp[MAX_NR_TRIP];
89 unsigned long cdev_binding; /* bitmap for attached cdevs */
90 /* cdev bind trip points, allow one cdev bind to multiple trips */
91 unsigned long trip_binding[MAX_NR_CDEV];
92};
93
94struct tmon_platform_data {
95 int nr_tz_sensor;
96 int nr_cooling_dev;
97 /* keep track of instance ids since there might be gaps */
98 int max_tz_instance;
99 int max_cdev_instance;
100 struct tz_info *tzi;
101 struct cdev_info *cdi;
102};
103
104struct control_ops {
105 void (*set_ratio)(unsigned long ratio);
106 unsigned long (*get_ratio)(unsigned long ratio);
107
108};
109
110enum cdev_types {
111 CDEV_TYPE_PROC,
112 CDEV_TYPE_FAN,
113 CDEV_TYPE_MEM,
114 CDEV_TYPE_NR,
115};
116
117/* REVISIT: the idea is to group sensors if possible, e.g. on intel mid
118 * we have "skin0", "skin1", "sys", "msicdie"
119 * on DPTF enabled systems, we might have PCH, TSKN, TAMB, etc.
120 */
121enum tzone_types {
122 TZONE_TYPE_ACPI,
123 TZONE_TYPE_PCH,
124 TZONE_TYPE_NR,
125};
126
127/* limit the output of PID controller adjustment */
128#define LIMIT_HIGH (95)
129#define LIMIT_LOW (2)
130
131struct pid_params {
132 double kp; /* Controller gain from Dialog Box */
133 double ki; /* Time-constant for I action from Dialog Box */
134 double kd; /* Time-constant for D action from Dialog Box */
135 double ts;
136 double k_lpf;
137
138 double t_target;
139 double y_k;
140};
141
142extern int init_thermal_controller(void);
143extern void controller_handler(const double xk, double *yk);
144
145extern struct tmon_platform_data ptdata;
146extern struct pid_params p_param;
147
148extern FILE *tmon_log;
149extern int cur_thermal_record; /* index to the trec array */
150extern struct thermal_data_record trec[];
151extern const char *trip_type_name[];
152extern unsigned long no_control;
153
154extern void initialize_curses(void);
155extern void show_controller_stats(char *line);
156extern void show_title_bar(void);
157extern void setup_windows(void);
158extern void disable_tui(void);
159extern void show_sensors_w(void);
160extern void show_data_w(void);
161extern void write_status_bar(int x, char *line);
162extern void show_control_w();
163
164extern void show_cooling_device(void);
165extern void show_dialogue(void);
166extern int update_thermal_data(void);
167
168extern int probe_thermal_sysfs(void);
169extern void free_thermal_data(void);
170extern void resize_handler(int sig);
171extern void set_ctrl_state(unsigned long state);
172extern void get_ctrl_state(unsigned long *state);
173extern void *handle_tui_events(void *arg);
174extern int sysfs_set_ulong(char *path, char *filename, unsigned long val);
175extern int zone_instance_to_index(int zone_inst);
176extern void close_windows(void);
177
178#define PT_COLOR_DEFAULT 1
179#define PT_COLOR_HEADER_BAR 2
180#define PT_COLOR_ERROR 3
181#define PT_COLOR_RED 4
182#define PT_COLOR_YELLOW 5
183#define PT_COLOR_GREEN 6
184#define PT_COLOR_BRIGHT 7
185#define PT_COLOR_BLUE 8
186
187/* each thermal zone uses 12 chars, 8 for name, 2 for instance, 2 space
188 * also used to list trip points in forms of AAAC, which represents
189 * A: Active
190 * C: Critical
191 */
192#define TZONE_RECORD_SIZE 12
193#define TZ_LEFT_ALIGN 32
194#define CDEV_NAME_SIZE 20
195#define CDEV_FLAG_IN_CONTROL (1 << 0)
196
197/* dialogue box starts */
198#define DIAG_X 48
199#define DIAG_Y 8
200#define THERMAL_SYSFS "/sys/class/thermal"
201#define CDEV "cooling_device"
202#define TZONE "thermal_zone"
203#define TDATA_LEFT 16
204#endif /* TMON_H */
diff --git a/tools/thermal/tmon/tui.c b/tools/thermal/tmon/tui.c
new file mode 100644
index 000000000000..89f8ef0e15c8
--- /dev/null
+++ b/tools/thermal/tmon/tui.c
@@ -0,0 +1,638 @@
1/*
2 * tui.c ncurses text user interface for TMON program
3 *
4 * Copyright (C) 2013 Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 or later as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * Author: Jacob Pan <jacob.jun.pan@linux.intel.com>
16 *
17 */
18
19#include <unistd.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <stdint.h>
24#include <ncurses.h>
25#include <time.h>
26#include <syslog.h>
27#include <panel.h>
28#include <pthread.h>
29#include <signal.h>
30
31#include "tmon.h"
32
33static PANEL *data_panel;
34static PANEL *dialogue_panel;
35static PANEL *top;
36
37static WINDOW *title_bar_window;
38static WINDOW *tz_sensor_window;
39static WINDOW *cooling_device_window;
40static WINDOW *control_window;
41static WINDOW *status_bar_window;
42static WINDOW *thermal_data_window;
43static WINDOW *dialogue_window;
44
45char status_bar_slots[10][40];
46static void draw_hbar(WINDOW *win, int y, int start, int len,
47 unsigned long pattern, bool end);
48
49static int maxx, maxy;
50static int maxwidth = 200;
51
52#define TITLE_BAR_HIGHT 1
53#define SENSOR_WIN_HIGHT 4 /* one row for tz name, one for trip points */
54
55
56/* daemon mode flag (set by startup parameter -d) */
57static int tui_disabled;
58
59static void close_panel(PANEL *p)
60{
61 if (p) {
62 del_panel(p);
63 p = NULL;
64 }
65}
66
67static void close_window(WINDOW *win)
68{
69 if (win) {
70 delwin(win);
71 win = NULL;
72 }
73}
74
75void close_windows(void)
76{
77 if (tui_disabled)
78 return;
79 /* must delete panels before their attached windows */
80 if (dialogue_window)
81 close_panel(dialogue_panel);
82 if (cooling_device_window)
83 close_panel(data_panel);
84
85 close_window(title_bar_window);
86 close_window(tz_sensor_window);
87 close_window(status_bar_window);
88 close_window(cooling_device_window);
89 close_window(control_window);
90 close_window(thermal_data_window);
91 close_window(dialogue_window);
92
93}
94
95void write_status_bar(int x, char *line)
96{
97 mvwprintw(status_bar_window, 0, x, "%s", line);
98 wrefresh(status_bar_window);
99}
100
101void setup_windows(void)
102{
103 int y_begin = 1;
104
105 if (tui_disabled)
106 return;
107
108 getmaxyx(stdscr, maxy, maxx);
109 resizeterm(maxy, maxx);
110
111 title_bar_window = subwin(stdscr, TITLE_BAR_HIGHT, maxx, 0, 0);
112 y_begin += TITLE_BAR_HIGHT;
113
114 tz_sensor_window = subwin(stdscr, SENSOR_WIN_HIGHT, maxx, y_begin, 0);
115 y_begin += SENSOR_WIN_HIGHT;
116
117 cooling_device_window = subwin(stdscr, ptdata.nr_cooling_dev + 3, maxx,
118 y_begin, 0);
119 y_begin += ptdata.nr_cooling_dev + 3; /* 2 lines for border */
120 /* two lines to show borders, one line per tz show trip point position
121 * and value.
122 * dialogue window is a pop-up, when needed it lays on top of cdev win
123 */
124
125 dialogue_window = subwin(stdscr, ptdata.nr_cooling_dev+5, maxx-50,
126 DIAG_Y, DIAG_X);
127
128 thermal_data_window = subwin(stdscr, ptdata.nr_tz_sensor *
129 NR_LINES_TZDATA + 3, maxx, y_begin, 0);
130 y_begin += ptdata.nr_tz_sensor * NR_LINES_TZDATA + 3;
131 control_window = subwin(stdscr, 4, maxx, y_begin, 0);
132
133 scrollok(cooling_device_window, TRUE);
134 maxwidth = maxx - 18;
135 status_bar_window = subwin(stdscr, 1, maxx, maxy-1, 0);
136
137 strcpy(status_bar_slots[0], " Ctrl-c - Quit ");
138 strcpy(status_bar_slots[1], " TAB - Tuning ");
139 wmove(status_bar_window, 1, 30);
140
141 /* prepare panels for dialogue, if panel already created then we must
142 * be doing resizing, so just replace windows with new ones, old ones
143 * should have been deleted by close_window
144 */
145 data_panel = new_panel(cooling_device_window);
146 if (!data_panel)
147 syslog(LOG_DEBUG, "No data panel\n");
148 else {
149 if (dialogue_window) {
150 dialogue_panel = new_panel(dialogue_window);
151 if (!dialogue_panel)
152 syslog(LOG_DEBUG, "No dialogue panel\n");
153 else {
154 /* Set up the user pointer to the next panel*/
155 set_panel_userptr(data_panel, dialogue_panel);
156 set_panel_userptr(dialogue_panel, data_panel);
157 top = data_panel;
158 }
159 } else
160 syslog(LOG_INFO, "no dialogue win, term too small\n");
161 }
162 doupdate();
163 werase(stdscr);
164 refresh();
165}
166
167void resize_handler(int sig)
168{
169 /* start over when term gets resized, but first we clean up */
170 close_windows();
171 endwin();
172 refresh();
173 clear();
174 getmaxyx(stdscr, maxy, maxx); /* get the new screen size */
175 setup_windows();
176 /* rate limit */
177 sleep(1);
178 syslog(LOG_DEBUG, "SIG %d, term resized to %d x %d\n",
179 sig, maxy, maxx);
180 signal(SIGWINCH, resize_handler);
181}
182
183const char cdev_title[] = " COOLING DEVICES ";
184void show_cooling_device(void)
185{
186 int i, j, x, y = 0;
187
188 if (tui_disabled || !cooling_device_window)
189 return;
190
191 werase(cooling_device_window);
192 wattron(cooling_device_window, A_BOLD);
193 mvwprintw(cooling_device_window, 1, 1,
194 "ID Cooling Dev Cur Max Thermal Zone Binding");
195 wattroff(cooling_device_window, A_BOLD);
196 for (j = 0; j < ptdata.nr_cooling_dev; j++) {
197 /* draw cooling device list on the left in the order of
198 * cooling device instances. skip unused idr.
199 */
200 mvwprintw(cooling_device_window, j + 2, 1,
201 "%02d %12.12s%6d %6d",
202 ptdata.cdi[j].instance,
203 ptdata.cdi[j].type,
204 ptdata.cdi[j].cur_state,
205 ptdata.cdi[j].max_state);
206 }
207
208 /* show cdev binding, y is the global cooling device instance */
209 for (i = 0; i < ptdata.nr_tz_sensor; i++) {
210 int tz_inst = ptdata.tzi[i].instance;
211 for (j = 0; j < ptdata.nr_cooling_dev; j++) {
212 int cdev_inst;
213 y = j;
214 x = tz_inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN;
215
216 draw_hbar(cooling_device_window, y+2, x,
217 TZONE_RECORD_SIZE-1, ACS_VLINE, false);
218
219 /* draw a column of spaces to separate thermal zones */
220 mvwprintw(cooling_device_window, y+2, x-1, " ");
221 if (ptdata.tzi[i].cdev_binding) {
222 cdev_inst = ptdata.cdi[j].instance;
223 unsigned long trip_binding =
224 ptdata.tzi[i].trip_binding[cdev_inst];
225 int k = 0; /* per zone trip point id that
226 * binded to this cdev, one to
227 * many possible based on the
228 * binding bitmask.
229 */
230 syslog(LOG_DEBUG,
231 "bind tz%d cdev%d tp%lx %d cdev%lx\n",
232 i, j, trip_binding, y,
233 ptdata.tzi[i].cdev_binding);
234 /* draw each trip binding for the cdev */
235 while (trip_binding >>= 1) {
236 k++;
237 if (!(trip_binding & 1))
238 continue;
239 /* draw '*' to show binding */
240 mvwprintw(cooling_device_window,
241 y + 2,
242 x + ptdata.tzi[i].nr_trip_pts -
243 k - 1, "*");
244 }
245 }
246 }
247 }
248 /* draw border after data so that border will not be messed up
249 * even there is not enough space for all the data to be shown
250 */
251 wborder(cooling_device_window, 0, 0, 0, 0, 0, 0, 0, 0);
252 wattron(cooling_device_window, A_BOLD);
253 mvwprintw(cooling_device_window, 0, maxx/2 - sizeof(cdev_title),
254 cdev_title);
255 wattroff(cooling_device_window, A_BOLD);
256
257 wrefresh(cooling_device_window);
258}
259
260const char DIAG_TITLE[] = "[ TUNABLES ]";
261#define DIAG_DEV_ROWS 5
262void show_dialogue(void)
263{
264 int j, x = 0, y = 0;
265 WINDOW *w = dialogue_window;
266
267 if (tui_disabled || !w)
268 return;
269
270 werase(w);
271 box(w, 0, 0);
272 mvwprintw(w, 0, maxx/4, DIAG_TITLE);
273 /* list all the available tunables */
274 for (j = 0; j <= ptdata.nr_cooling_dev; j++) {
275 y = j % DIAG_DEV_ROWS;
276 if (y == 0 && j != 0)
277 x += 20;
278 if (j == ptdata.nr_cooling_dev)
279 /* save last choice for target temp */
280 mvwprintw(w, y+1, x+1, "%C-%.12s", 'A'+j, "Set Temp");
281 else
282 mvwprintw(w, y+1, x+1, "%C-%.10s-%2d", 'A'+j,
283 ptdata.cdi[j].type, ptdata.cdi[j].instance);
284 }
285 wattron(w, A_BOLD);
286 mvwprintw(w, DIAG_DEV_ROWS+1, 1, "Enter Choice [A-Z]?");
287 wattroff(w, A_BOLD);
288 /* y size of dialogue win is nr cdev + 5, so print legend
289 * at the bottom line
290 */
291 mvwprintw(w, ptdata.nr_cooling_dev+3, 1,
292 "Legend: A=Active, P=Passive, C=Critical");
293
294 wrefresh(dialogue_window);
295}
296
297void write_dialogue_win(char *buf, int y, int x)
298{
299 WINDOW *w = dialogue_window;
300
301 mvwprintw(w, y, x, "%s", buf);
302}
303
304const char control_title[] = " CONTROLS ";
305void show_control_w(void)
306{
307 unsigned long state;
308
309 get_ctrl_state(&state);
310
311 if (tui_disabled || !control_window)
312 return;
313
314 werase(control_window);
315 mvwprintw(control_window, 1, 1,
316 "PID gain: kp=%2.2f ki=%2.2f kd=%2.2f Output %2.2f",
317 p_param.kp, p_param.ki, p_param.kd, p_param.y_k);
318
319 mvwprintw(control_window, 2, 1,
320 "Target Temp: %2.1fC, Zone: %d, Control Device: %.12s",
321 p_param.t_target, target_thermal_zone, ctrl_cdev);
322
323 /* draw border last such that everything is within boundary */
324 wborder(control_window, 0, 0, 0, 0, 0, 0, 0, 0);
325 wattron(control_window, A_BOLD);
326 mvwprintw(control_window, 0, maxx/2 - sizeof(control_title),
327 control_title);
328 wattroff(control_window, A_BOLD);
329
330 wrefresh(control_window);
331}
332
333void initialize_curses(void)
334{
335 if (tui_disabled)
336 return;
337
338 initscr();
339 start_color();
340 keypad(stdscr, TRUE); /* enable keyboard mapping */
341 nonl(); /* tell curses not to do NL->CR/NL on output */
342 cbreak(); /* take input chars one at a time */
343 noecho(); /* dont echo input */
344 curs_set(0); /* turn off cursor */
345 use_default_colors();
346
347 init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
348 init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE);
349 init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED);
350 init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED);
351 init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW);
352 init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN);
353 init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE);
354 init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK);
355
356}
357
358void show_title_bar(void)
359{
360 int i;
361 int x = 0;
362
363 if (tui_disabled || !title_bar_window)
364 return;
365
366 wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR));
367 wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR));
368 werase(title_bar_window);
369
370 mvwprintw(title_bar_window, 0, 0,
371 " TMON v%s", VERSION);
372
373 wrefresh(title_bar_window);
374
375 werase(status_bar_window);
376
377 for (i = 0; i < 10; i++) {
378 if (strlen(status_bar_slots[i]) == 0)
379 continue;
380 wattron(status_bar_window, A_REVERSE);
381 mvwprintw(status_bar_window, 0, x, "%s", status_bar_slots[i]);
382 wattroff(status_bar_window, A_REVERSE);
383 x += strlen(status_bar_slots[i]) + 1;
384 }
385 wrefresh(status_bar_window);
386}
387
388static void handle_input_val(int ch)
389{
390 char buf[32];
391 int val;
392 char path[256];
393 WINDOW *w = dialogue_window;
394
395 echo();
396 keypad(w, TRUE);
397 wgetnstr(w, buf, 31);
398 val = atoi(buf);
399
400 if (ch == ptdata.nr_cooling_dev) {
401 snprintf(buf, 31, "Invalid Temp %d! %d-%d", val,
402 MIN_CTRL_TEMP, MAX_CTRL_TEMP);
403 if (val < MIN_CTRL_TEMP || val > MAX_CTRL_TEMP)
404 write_status_bar(40, buf);
405 else {
406 p_param.t_target = val;
407 snprintf(buf, 31, "Set New Target Temp %d", val);
408 write_status_bar(40, buf);
409 }
410 } else {
411 snprintf(path, 256, "%s/%s%d", THERMAL_SYSFS,
412 CDEV, ptdata.cdi[ch].instance);
413 sysfs_set_ulong(path, "cur_state", val);
414 }
415 noecho();
416 dialogue_on = 0;
417 show_data_w();
418 show_control_w();
419
420 top = (PANEL *)panel_userptr(top);
421 top_panel(top);
422}
423
424static void handle_input_choice(int ch)
425{
426 char buf[48];
427 int base = 0;
428 int cdev_id = 0;
429
430 if ((ch >= 'A' && ch <= 'A' + ptdata.nr_cooling_dev) ||
431 (ch >= 'a' && ch <= 'a' + ptdata.nr_cooling_dev)) {
432 base = (ch < 'a') ? 'A' : 'a';
433 cdev_id = ch - base;
434 if (ptdata.nr_cooling_dev == cdev_id)
435 snprintf(buf, sizeof(buf), "New Target Temp:");
436 else
437 snprintf(buf, sizeof(buf), "New Value for %.10s-%2d: ",
438 ptdata.cdi[cdev_id].type,
439 ptdata.cdi[cdev_id].instance);
440 write_dialogue_win(buf, DIAG_DEV_ROWS+2, 2);
441 handle_input_val(cdev_id);
442 } else {
443 snprintf(buf, sizeof(buf), "Invalid selection %d", ch);
444 write_dialogue_win(buf, 8, 2);
445 }
446}
447
448void *handle_tui_events(void *arg)
449{
450 int ch;
451
452 keypad(cooling_device_window, TRUE);
453 while ((ch = wgetch(cooling_device_window)) != EOF) {
454 if (tmon_exit)
455 break;
456 /* when term size is too small, no dialogue panels are set.
457 * we need to filter out such cases.
458 */
459 if (!data_panel || !dialogue_panel ||
460 !cooling_device_window ||
461 !dialogue_window) {
462
463 continue;
464 }
465 pthread_mutex_lock(&input_lock);
466 if (dialogue_on) {
467 handle_input_choice(ch);
468 /* top panel filter */
469 if (ch == 'q' || ch == 'Q')
470 ch = 0;
471 }
472 switch (ch) {
473 case KEY_LEFT:
474 box(cooling_device_window, 10, 0);
475 break;
476 case 9: /* TAB */
477 top = (PANEL *)panel_userptr(top);
478 top_panel(top);
479 if (top == dialogue_panel) {
480 dialogue_on = 1;
481 show_dialogue();
482 } else {
483 dialogue_on = 0;
484 /* force refresh */
485 show_data_w();
486 show_control_w();
487 }
488 break;
489 case 'q':
490 case 'Q':
491 tmon_exit = 1;
492 break;
493 }
494 update_panels();
495 doupdate();
496 pthread_mutex_unlock(&input_lock);
497 }
498
499 if (arg)
500 *(int *)arg = 0; /* make gcc happy */
501
502 return NULL;
503}
504
505/* draw a horizontal bar in given pattern */
506static void draw_hbar(WINDOW *win, int y, int start, int len, unsigned long ptn,
507 bool end)
508{
509 mvwaddch(win, y, start, ptn);
510 whline(win, ptn, len);
511 if (end)
512 mvwaddch(win, y, MAX_DISP_TEMP+TDATA_LEFT, ']');
513}
514
515static char trip_type_to_char(int type)
516{
517 switch (type) {
518 case THERMAL_TRIP_CRITICAL: return 'C';
519 case THERMAL_TRIP_HOT: return 'H';
520 case THERMAL_TRIP_PASSIVE: return 'P';
521 case THERMAL_TRIP_ACTIVE: return 'A';
522 default:
523 return '?';
524 }
525}
526
527/* fill a string with trip point type and value in one line
528 * e.g. P(56) C(106)
529 * maintain the distance one degree per char
530 */
531static void draw_tp_line(int tz, int y)
532{
533 int j;
534 int x;
535
536 for (j = 0; j < ptdata.tzi[tz].nr_trip_pts; j++) {
537 x = ptdata.tzi[tz].tp[j].temp / 1000;
538 mvwprintw(thermal_data_window, y + 0, x + TDATA_LEFT,
539 "%c%d", trip_type_to_char(ptdata.tzi[tz].tp[j].type),
540 x);
541 syslog(LOG_INFO, "%s:tz %d tp %d temp = %lu\n", __func__,
542 tz, j, ptdata.tzi[tz].tp[j].temp);
543 }
544}
545
546const char data_win_title[] = " THERMAL DATA ";
547void show_data_w(void)
548{
549 int i;
550
551
552 if (tui_disabled || !thermal_data_window)
553 return;
554
555 werase(thermal_data_window);
556 wattron(thermal_data_window, A_BOLD);
557 mvwprintw(thermal_data_window, 0, maxx/2 - sizeof(data_win_title),
558 data_win_title);
559 wattroff(thermal_data_window, A_BOLD);
560 /* draw a line as ruler */
561 for (i = 10; i < MAX_DISP_TEMP; i += 10)
562 mvwprintw(thermal_data_window, 1, i+TDATA_LEFT, "%2d", i);
563
564 for (i = 0; i < ptdata.nr_tz_sensor; i++) {
565 int temp = trec[cur_thermal_record].temp[i] / 1000;
566 int y = 0;
567
568 y = i * NR_LINES_TZDATA + 2;
569 /* y at tz temp data line */
570 mvwprintw(thermal_data_window, y, 1, "%6.6s%2d:[%3d][",
571 ptdata.tzi[i].type,
572 ptdata.tzi[i].instance, temp);
573 draw_hbar(thermal_data_window, y, TDATA_LEFT, temp, ACS_RARROW,
574 true);
575 draw_tp_line(i, y);
576 }
577 wborder(thermal_data_window, 0, 0, 0, 0, 0, 0, 0, 0);
578 wrefresh(thermal_data_window);
579}
580
581const char tz_title[] = "THERMAL ZONES(SENSORS)";
582
583void show_sensors_w(void)
584{
585 int i, j;
586 char buffer[512];
587
588 if (tui_disabled || !tz_sensor_window)
589 return;
590
591 werase(tz_sensor_window);
592
593 memset(buffer, 0, sizeof(buffer));
594 wattron(tz_sensor_window, A_BOLD);
595 mvwprintw(tz_sensor_window, 1, 1, "Thermal Zones:");
596 wattroff(tz_sensor_window, A_BOLD);
597
598 mvwprintw(tz_sensor_window, 1, TZ_LEFT_ALIGN, "%s", buffer);
599 /* fill trip points for each tzone */
600 wattron(tz_sensor_window, A_BOLD);
601 mvwprintw(tz_sensor_window, 2, 1, "Trip Points:");
602 wattroff(tz_sensor_window, A_BOLD);
603
604 /* draw trip point from low to high for each tz */
605 for (i = 0; i < ptdata.nr_tz_sensor; i++) {
606 int inst = ptdata.tzi[i].instance;
607
608 mvwprintw(tz_sensor_window, 1,
609 TZ_LEFT_ALIGN+TZONE_RECORD_SIZE * inst, "%.9s%02d",
610 ptdata.tzi[i].type, ptdata.tzi[i].instance);
611 for (j = ptdata.tzi[i].nr_trip_pts - 1; j >= 0; j--) {
612 /* loop through all trip points */
613 char type;
614 int tp_pos;
615 /* reverse the order here since trips are sorted
616 * in ascending order in terms of temperature.
617 */
618 tp_pos = ptdata.tzi[i].nr_trip_pts - j - 1;
619
620 type = trip_type_to_char(ptdata.tzi[i].tp[j].type);
621 mvwaddch(tz_sensor_window, 2,
622 inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN +
623 tp_pos, type);
624 syslog(LOG_DEBUG, "draw tz %d tp %d ch:%c\n",
625 inst, j, type);
626 }
627 }
628 wborder(tz_sensor_window, 0, 0, 0, 0, 0, 0, 0, 0);
629 wattron(tz_sensor_window, A_BOLD);
630 mvwprintw(tz_sensor_window, 0, maxx/2 - sizeof(tz_title), tz_title);
631 wattroff(tz_sensor_window, A_BOLD);
632 wrefresh(tz_sensor_window);
633}
634
635void disable_tui(void)
636{
637 tui_disabled = 1;
638}
diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index da7a19558281..bdb71a26ae35 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -41,13 +41,14 @@ struct vdev_info {
41 struct vhost_memory *mem; 41 struct vhost_memory *mem;
42}; 42};
43 43
44void vq_notify(struct virtqueue *vq) 44bool vq_notify(struct virtqueue *vq)
45{ 45{
46 struct vq_info *info = vq->priv; 46 struct vq_info *info = vq->priv;
47 unsigned long long v = 1; 47 unsigned long long v = 1;
48 int r; 48 int r;
49 r = write(info->kick, &v, sizeof v); 49 r = write(info->kick, &v, sizeof v);
50 assert(r == sizeof v); 50 assert(r == sizeof v);
51 return true;
51} 52}
52 53
53void vq_callback(struct virtqueue *vq) 54void vq_callback(struct virtqueue *vq)
@@ -171,7 +172,8 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
171 GFP_ATOMIC); 172 GFP_ATOMIC);
172 if (likely(r == 0)) { 173 if (likely(r == 0)) {
173 ++started; 174 ++started;
174 virtqueue_kick(vq->vq); 175 if (unlikely(!virtqueue_kick(vq->vq))
176 r = -1;
175 } 177 }
176 } else 178 } else
177 r = -1; 179 r = -1;
diff --git a/tools/virtio/vringh_test.c b/tools/virtio/vringh_test.c
index d053ea40c001..14a4f4cab5b9 100644
--- a/tools/virtio/vringh_test.c
+++ b/tools/virtio/vringh_test.c
@@ -22,7 +22,7 @@ static u64 user_addr_offset;
22#define RINGSIZE 256 22#define RINGSIZE 256
23#define ALIGN 4096 23#define ALIGN 4096
24 24
25static void never_notify_host(struct virtqueue *vq) 25static bool never_notify_host(struct virtqueue *vq)
26{ 26{
27 abort(); 27 abort();
28} 28}
@@ -65,17 +65,22 @@ struct guest_virtio_device {
65 unsigned long notifies; 65 unsigned long notifies;
66}; 66};
67 67
68static void parallel_notify_host(struct virtqueue *vq) 68static bool parallel_notify_host(struct virtqueue *vq)
69{ 69{
70 int rc;
70 struct guest_virtio_device *gvdev; 71 struct guest_virtio_device *gvdev;
71 72
72 gvdev = container_of(vq->vdev, struct guest_virtio_device, vdev); 73 gvdev = container_of(vq->vdev, struct guest_virtio_device, vdev);
73 write(gvdev->to_host_fd, "", 1); 74 rc = write(gvdev->to_host_fd, "", 1);
75 if (rc < 0)
76 return false;
74 gvdev->notifies++; 77 gvdev->notifies++;
78 return true;
75} 79}
76 80
77static void no_notify_host(struct virtqueue *vq) 81static bool no_notify_host(struct virtqueue *vq)
78{ 82{
83 return true;
79} 84}
80 85
81#define NUM_XFERS (10000000) 86#define NUM_XFERS (10000000)
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index 71c9c2511ee7..d5e9d6d185c8 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -59,12 +59,14 @@
59#define PM_PSHIFT_BITS 6 59#define PM_PSHIFT_BITS 6
60#define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) 60#define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS)
61#define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) 61#define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET)
62#define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) 62#define __PM_PSHIFT(x) (((uint64_t) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK)
63#define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) 63#define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1)
64#define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) 64#define PM_PFRAME(x) ((x) & PM_PFRAME_MASK)
65 65
66#define __PM_SOFT_DIRTY (1LL)
66#define PM_PRESENT PM_STATUS(4LL) 67#define PM_PRESENT PM_STATUS(4LL)
67#define PM_SWAP PM_STATUS(2LL) 68#define PM_SWAP PM_STATUS(2LL)
69#define PM_SOFT_DIRTY __PM_PSHIFT(__PM_SOFT_DIRTY)
68 70
69 71
70/* 72/*
@@ -83,6 +85,7 @@
83#define KPF_OWNER_PRIVATE 37 85#define KPF_OWNER_PRIVATE 37
84#define KPF_ARCH 38 86#define KPF_ARCH 38
85#define KPF_UNCACHED 39 87#define KPF_UNCACHED 39
88#define KPF_SOFTDIRTY 40
86 89
87/* [48-] take some arbitrary free slots for expanding overloaded flags 90/* [48-] take some arbitrary free slots for expanding overloaded flags
88 * not part of kernel API 91 * not part of kernel API
@@ -132,6 +135,7 @@ static const char * const page_flag_names[] = {
132 [KPF_OWNER_PRIVATE] = "O:owner_private", 135 [KPF_OWNER_PRIVATE] = "O:owner_private",
133 [KPF_ARCH] = "h:arch", 136 [KPF_ARCH] = "h:arch",
134 [KPF_UNCACHED] = "c:uncached", 137 [KPF_UNCACHED] = "c:uncached",
138 [KPF_SOFTDIRTY] = "f:softdirty",
135 139
136 [KPF_READAHEAD] = "I:readahead", 140 [KPF_READAHEAD] = "I:readahead",
137 [KPF_SLOB_FREE] = "P:slob_free", 141 [KPF_SLOB_FREE] = "P:slob_free",
@@ -417,7 +421,7 @@ static int bit_mask_ok(uint64_t flags)
417 return 1; 421 return 1;
418} 422}
419 423
420static uint64_t expand_overloaded_flags(uint64_t flags) 424static uint64_t expand_overloaded_flags(uint64_t flags, uint64_t pme)
421{ 425{
422 /* SLOB/SLUB overload several page flags */ 426 /* SLOB/SLUB overload several page flags */
423 if (flags & BIT(SLAB)) { 427 if (flags & BIT(SLAB)) {
@@ -433,6 +437,9 @@ static uint64_t expand_overloaded_flags(uint64_t flags)
433 if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM)) 437 if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM))
434 flags ^= BIT(RECLAIM) | BIT(READAHEAD); 438 flags ^= BIT(RECLAIM) | BIT(READAHEAD);
435 439
440 if (pme & PM_SOFT_DIRTY)
441 flags |= BIT(SOFTDIRTY);
442
436 return flags; 443 return flags;
437} 444}
438 445
@@ -448,11 +455,11 @@ static uint64_t well_known_flags(uint64_t flags)
448 return flags; 455 return flags;
449} 456}
450 457
451static uint64_t kpageflags_flags(uint64_t flags) 458static uint64_t kpageflags_flags(uint64_t flags, uint64_t pme)
452{ 459{
453 flags = expand_overloaded_flags(flags); 460 if (opt_raw)
454 461 flags = expand_overloaded_flags(flags, pme);
455 if (!opt_raw) 462 else
456 flags = well_known_flags(flags); 463 flags = well_known_flags(flags);
457 464
458 return flags; 465 return flags;
@@ -545,9 +552,9 @@ static size_t hash_slot(uint64_t flags)
545} 552}
546 553
547static void add_page(unsigned long voffset, 554static void add_page(unsigned long voffset,
548 unsigned long offset, uint64_t flags) 555 unsigned long offset, uint64_t flags, uint64_t pme)
549{ 556{
550 flags = kpageflags_flags(flags); 557 flags = kpageflags_flags(flags, pme);
551 558
552 if (!bit_mask_ok(flags)) 559 if (!bit_mask_ok(flags))
553 return; 560 return;
@@ -569,7 +576,8 @@ static void add_page(unsigned long voffset,
569#define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */ 576#define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */
570static void walk_pfn(unsigned long voffset, 577static void walk_pfn(unsigned long voffset,
571 unsigned long index, 578 unsigned long index,
572 unsigned long count) 579 unsigned long count,
580 uint64_t pme)
573{ 581{
574 uint64_t buf[KPAGEFLAGS_BATCH]; 582 uint64_t buf[KPAGEFLAGS_BATCH];
575 unsigned long batch; 583 unsigned long batch;
@@ -583,7 +591,7 @@ static void walk_pfn(unsigned long voffset,
583 break; 591 break;
584 592
585 for (i = 0; i < pages; i++) 593 for (i = 0; i < pages; i++)
586 add_page(voffset + i, index + i, buf[i]); 594 add_page(voffset + i, index + i, buf[i], pme);
587 595
588 index += pages; 596 index += pages;
589 count -= pages; 597 count -= pages;
@@ -608,7 +616,7 @@ static void walk_vma(unsigned long index, unsigned long count)
608 for (i = 0; i < pages; i++) { 616 for (i = 0; i < pages; i++) {
609 pfn = pagemap_pfn(buf[i]); 617 pfn = pagemap_pfn(buf[i]);
610 if (pfn) 618 if (pfn)
611 walk_pfn(index + i, pfn, 1); 619 walk_pfn(index + i, pfn, 1, buf[i]);
612 } 620 }
613 621
614 index += pages; 622 index += pages;
@@ -659,7 +667,7 @@ static void walk_addr_ranges(void)
659 667
660 for (i = 0; i < nr_addr_ranges; i++) 668 for (i = 0; i < nr_addr_ranges; i++)
661 if (!opt_pid) 669 if (!opt_pid)
662 walk_pfn(0, opt_offset[i], opt_size[i]); 670 walk_pfn(0, opt_offset[i], opt_size[i], 0);
663 else 671 else
664 walk_task(opt_offset[i], opt_size[i]); 672 walk_task(opt_offset[i], opt_size[i]);
665 673