aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2013-11-14 20:38:05 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2013-11-14 20:38:05 -0500
commit42249094f79422fbf5ed4b54eeb48ff096809b8f (patch)
tree91e6850c8c7e8cc284cf8bb6363f8662f84011f4 /tools
parent936816161978ca716a56c5e553c68f25972b1e3a (diff)
parent2c027b7c48a888ab173ba45babb4525e278375d9 (diff)
Merge branch 'next' into for-linus
Merge first round of changes for 3.13 merge window.
Diffstat (limited to 'tools')
-rw-r--r--tools/hv/hv_kvp_daemon.c107
-rw-r--r--tools/hv/hv_vss_daemon.c59
-rw-r--r--tools/include/tools/be_byteshift.h34
-rw-r--r--tools/include/tools/le_byteshift.h34
-rw-r--r--tools/lguest/Makefile1
-rw-r--r--tools/lguest/lguest.c38
-rw-r--r--tools/lib/lk/Makefile5
-rw-r--r--tools/lib/lk/debugfs.c1
-rw-r--r--tools/lib/traceevent/Makefile20
-rw-r--r--tools/lib/traceevent/event-parse.c7
-rw-r--r--tools/lib/traceevent/event-parse.h15
-rw-r--r--tools/lib/traceevent/kbuffer-parse.c732
-rw-r--r--tools/lib/traceevent/kbuffer.h67
-rw-r--r--tools/lib/traceevent/trace-seq.c13
-rw-r--r--tools/perf/Documentation/Makefile12
-rw-r--r--tools/perf/Documentation/examples.txt4
-rw-r--r--tools/perf/Documentation/perf-archive.txt2
-rw-r--r--tools/perf/Documentation/perf-diff.txt79
-rw-r--r--tools/perf/Documentation/perf-kvm.txt46
-rw-r--r--tools/perf/Documentation/perf-list.txt6
-rw-r--r--tools/perf/Documentation/perf-record.txt8
-rw-r--r--tools/perf/Documentation/perf-report.txt17
-rw-r--r--tools/perf/Documentation/perf-stat.txt5
-rw-r--r--tools/perf/Documentation/perf-top.txt9
-rw-r--r--tools/perf/Documentation/perf-trace.txt24
-rw-r--r--tools/perf/Makefile649
-rw-r--r--tools/perf/arch/x86/Makefile2
-rw-r--r--tools/perf/arch/x86/util/tsc.c59
-rw-r--r--tools/perf/arch/x86/util/tsc.h20
-rw-r--r--tools/perf/bench/mem-memcpy.c6
-rw-r--r--tools/perf/bench/mem-memset.c2
-rw-r--r--tools/perf/builtin-annotate.c6
-rw-r--r--tools/perf/builtin-diff.c680
-rw-r--r--tools/perf/builtin-inject.c70
-rw-r--r--tools/perf/builtin-kmem.c9
-rw-r--r--tools/perf/builtin-kvm.c757
-rw-r--r--tools/perf/builtin-list.c3
-rw-r--r--tools/perf/builtin-lock.c5
-rw-r--r--tools/perf/builtin-mem.c7
-rw-r--r--tools/perf/builtin-record.c100
-rw-r--r--tools/perf/builtin-report.c199
-rw-r--r--tools/perf/builtin-sched.c162
-rw-r--r--tools/perf/builtin-script.c45
-rw-r--r--tools/perf/builtin-stat.c54
-rw-r--r--tools/perf/builtin-timechart.c180
-rw-r--r--tools/perf/builtin-top.c112
-rw-r--r--tools/perf/builtin-trace.c744
-rw-r--r--tools/perf/config/Makefile481
-rw-r--r--tools/perf/config/feature-tests.mak10
-rw-r--r--tools/perf/config/utilities.mak4
-rw-r--r--tools/perf/perf.h3
-rwxr-xr-xtools/perf/python/twatch.py2
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.xs2
-rw-r--r--tools/perf/tests/attr/base-record4
-rw-r--r--tools/perf/tests/attr/base-stat4
-rw-r--r--tools/perf/tests/attr/test-record-data5
-rw-r--r--tools/perf/tests/attr/test-record-group-sampling36
-rw-r--r--tools/perf/tests/bp_signal.c6
-rw-r--r--tools/perf/tests/bp_signal_overflow.c6
-rw-r--r--tools/perf/tests/builtin-test.c24
-rw-r--r--tools/perf/tests/code-reading.c572
-rw-r--r--tools/perf/tests/dso-data.c8
-rw-r--r--tools/perf/tests/evsel-tp-sched.c4
-rw-r--r--tools/perf/tests/hists_link.c27
-rw-r--r--tools/perf/tests/keep-tracking.c154
-rw-r--r--tools/perf/tests/make189
-rw-r--r--tools/perf/tests/mmap-basic.c2
-rw-r--r--tools/perf/tests/parse-events.c190
-rw-r--r--tools/perf/tests/parse-no-sample-id-all.c108
-rw-r--r--tools/perf/tests/perf-record.c15
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c177
-rw-r--r--tools/perf/tests/sample-parsing.c316
-rw-r--r--tools/perf/tests/tests.h13
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c49
-rw-r--r--tools/perf/ui/browsers/annotate.c20
-rw-r--r--tools/perf/ui/browsers/hists.c124
-rw-r--r--tools/perf/ui/gtk/hists.c141
-rw-r--r--tools/perf/ui/hist.c258
-rw-r--r--tools/perf/ui/setup.c1
-rw-r--r--tools/perf/ui/stdio/hist.c75
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN21
-rw-r--r--tools/perf/util/annotate.c62
-rw-r--r--tools/perf/util/build-id.c12
-rw-r--r--tools/perf/util/callchain.c15
-rw-r--r--tools/perf/util/callchain.h11
-rw-r--r--tools/perf/util/cpumap.h2
-rw-r--r--tools/perf/util/dso.c20
-rw-r--r--tools/perf/util/dso.h20
-rw-r--r--tools/perf/util/dwarf-aux.c19
-rw-r--r--tools/perf/util/dwarf-aux.h3
-rw-r--r--tools/perf/util/event.c87
-rw-r--r--tools/perf/util/event.h54
-rw-r--r--tools/perf/util/evlist.c317
-rw-r--r--tools/perf/util/evlist.h21
-rw-r--r--tools/perf/util/evsel.c603
-rw-r--r--tools/perf/util/evsel.h19
-rw-r--r--tools/perf/util/header.c220
-rw-r--r--tools/perf/util/header.h41
-rw-r--r--tools/perf/util/hist.c102
-rw-r--r--tools/perf/util/hist.h42
-rw-r--r--tools/perf/util/include/linux/string.h1
-rw-r--r--tools/perf/util/machine.c210
-rw-r--r--tools/perf/util/machine.h15
-rw-r--r--tools/perf/util/map.c76
-rw-r--r--tools/perf/util/map.h21
-rw-r--r--tools/perf/util/parse-events.c178
-rw-r--r--tools/perf/util/parse-events.h11
-rw-r--r--tools/perf/util/parse-events.l4
-rw-r--r--tools/perf/util/parse-events.y62
-rw-r--r--tools/perf/util/pmu.c87
-rw-r--r--tools/perf/util/pmu.h5
-rw-r--r--tools/perf/util/probe-finder.c89
-rw-r--r--tools/perf/util/probe-finder.h3
-rw-r--r--tools/perf/util/python.c21
-rw-r--r--tools/perf/util/record.c108
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c14
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c9
-rw-r--r--tools/perf/util/session.c318
-rw-r--r--tools/perf/util/session.h19
-rw-r--r--tools/perf/util/setup.py5
-rw-r--r--tools/perf/util/sort.c132
-rw-r--r--tools/perf/util/sort.h39
-rw-r--r--tools/perf/util/stat.c8
-rw-r--r--tools/perf/util/stat.h9
-rw-r--r--tools/perf/util/string.c24
-rw-r--r--tools/perf/util/symbol-elf.c190
-rw-r--r--tools/perf/util/symbol-minimal.c7
-rw-r--r--tools/perf/util/symbol.c286
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/thread.c13
-rw-r--r--tools/perf/util/thread.h24
-rw-r--r--tools/perf/util/tool.h11
-rw-r--r--tools/perf/util/top.c23
-rw-r--r--tools/perf/util/top.h4
-rw-r--r--tools/perf/util/trace-event-info.c96
-rw-r--r--tools/perf/util/trace-event-parse.c8
-rw-r--r--tools/perf/util/trace-event-read.c52
-rw-r--r--tools/perf/util/trace-event-scripting.c3
-rw-r--r--tools/perf/util/trace-event.h21
-rw-r--r--tools/perf/util/unwind.c2
-rw-r--r--tools/perf/util/util.c92
-rw-r--r--tools/perf/util/util.h11
-rw-r--r--tools/perf/util/vdso.c2
-rw-r--r--tools/power/cpupower/Makefile4
-rw-r--r--tools/power/cpupower/man/cpupower-monitor.110
-rw-r--r--tools/power/cpupower/utils/builtin.h1
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c24
-rw-r--r--tools/power/cpupower/utils/cpuidle-set.c118
-rw-r--r--tools/power/cpupower/utils/cpupower.c13
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c118
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.h10
-rw-r--r--tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c196
-rw-r--r--tools/power/cpupower/utils/idle_monitor/idle_monitors.def1
-rw-r--r--tools/power/cpupower/utils/idle_monitor/snb_idle.c4
-rw-r--r--tools/power/x86/turbostat/turbostat.c2
-rw-r--r--tools/scripts/Makefile.include2
-rwxr-xr-xtools/testing/ktest/ktest.pl2
-rw-r--r--tools/testing/selftests/Makefile2
-rw-r--r--tools/testing/selftests/cpu-hotplug/Makefile2
-rw-r--r--tools/testing/selftests/kcmp/.gitignore2
-rw-r--r--tools/testing/selftests/kcmp/Makefile3
-rw-r--r--tools/testing/selftests/memory-hotplug/Makefile2
-rw-r--r--tools/testing/selftests/net/psock_tpacket.c59
-rw-r--r--tools/testing/selftests/powerpc/Makefile39
-rw-r--r--tools/testing/selftests/powerpc/harness.c105
-rw-r--r--tools/testing/selftests/powerpc/pmu/Makefile23
-rw-r--r--tools/testing/selftests/powerpc/pmu/count_instructions.c135
-rw-r--r--tools/testing/selftests/powerpc/pmu/event.c105
-rw-r--r--tools/testing/selftests/powerpc/pmu/event.h39
-rw-r--r--tools/testing/selftests/powerpc/pmu/loop.S46
-rw-r--r--tools/testing/selftests/powerpc/subunit.h47
-rw-r--r--tools/testing/selftests/powerpc/utils.h34
-rw-r--r--tools/testing/selftests/timers/Makefile8
-rw-r--r--tools/testing/selftests/timers/posix_timers.c221
-rw-r--r--tools/testing/selftests/vm/.gitignore4
-rw-r--r--tools/testing/selftests/vm/Makefile7
-rw-r--r--tools/testing/selftests/vm/hugetlbfstest.c84
-rw-r--r--tools/testing/selftests/vm/run_vmtests16
-rw-r--r--tools/virtio/.gitignore3
-rw-r--r--tools/virtio/linux/module.h5
-rw-r--r--tools/virtio/linux/virtio.h3
181 files changed, 10904 insertions, 2850 deletions
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 5a1f6489d185..8fd9ec66121c 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -79,8 +79,6 @@ enum {
79 DNS 79 DNS
80}; 80};
81 81
82static char kvp_send_buffer[4096];
83static char kvp_recv_buffer[4096 * 2];
84static struct sockaddr_nl addr; 82static struct sockaddr_nl addr;
85static int in_hand_shake = 1; 83static int in_hand_shake = 1;
86 84
@@ -127,7 +125,8 @@ static void kvp_acquire_lock(int pool)
127 fl.l_pid = getpid(); 125 fl.l_pid = getpid();
128 126
129 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) { 127 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
130 syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool); 128 syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool,
129 errno, strerror(errno));
131 exit(EXIT_FAILURE); 130 exit(EXIT_FAILURE);
132 } 131 }
133} 132}
@@ -138,8 +137,8 @@ static void kvp_release_lock(int pool)
138 fl.l_pid = getpid(); 137 fl.l_pid = getpid();
139 138
140 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) { 139 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
141 perror("fcntl"); 140 syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool,
142 syslog(LOG_ERR, "Failed to release the lock pool: %d", pool); 141 errno, strerror(errno));
143 exit(EXIT_FAILURE); 142 exit(EXIT_FAILURE);
144 } 143 }
145} 144}
@@ -157,8 +156,9 @@ static void kvp_update_file(int pool)
157 156
158 filep = fopen(kvp_file_info[pool].fname, "we"); 157 filep = fopen(kvp_file_info[pool].fname, "we");
159 if (!filep) { 158 if (!filep) {
159 syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
160 errno, strerror(errno));
160 kvp_release_lock(pool); 161 kvp_release_lock(pool);
161 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
162 exit(EXIT_FAILURE); 162 exit(EXIT_FAILURE);
163 } 163 }
164 164
@@ -188,8 +188,9 @@ static void kvp_update_mem_state(int pool)
188 188
189 filep = fopen(kvp_file_info[pool].fname, "re"); 189 filep = fopen(kvp_file_info[pool].fname, "re");
190 if (!filep) { 190 if (!filep) {
191 syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
192 errno, strerror(errno));
191 kvp_release_lock(pool); 193 kvp_release_lock(pool);
192 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
193 exit(EXIT_FAILURE); 194 exit(EXIT_FAILURE);
194 } 195 }
195 for (;;) { 196 for (;;) {
@@ -240,7 +241,8 @@ static int kvp_file_init(void)
240 241
241 if (access(KVP_CONFIG_LOC, F_OK)) { 242 if (access(KVP_CONFIG_LOC, F_OK)) {
242 if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) { 243 if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) {
243 syslog(LOG_ERR, " Failed to create %s", KVP_CONFIG_LOC); 244 syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC,
245 errno, strerror(errno));
244 exit(EXIT_FAILURE); 246 exit(EXIT_FAILURE);
245 } 247 }
246 } 248 }
@@ -257,12 +259,15 @@ static int kvp_file_init(void)
257 259
258 260
259 filep = fopen(fname, "re"); 261 filep = fopen(fname, "re");
260 if (!filep) 262 if (!filep) {
263 close(fd);
261 return 1; 264 return 1;
265 }
262 266
263 record = malloc(alloc_unit * num_blocks); 267 record = malloc(alloc_unit * num_blocks);
264 if (record == NULL) { 268 if (record == NULL) {
265 fclose(filep); 269 fclose(filep);
270 close(fd);
266 return 1; 271 return 1;
267 } 272 }
268 for (;;) { 273 for (;;) {
@@ -286,6 +291,7 @@ static int kvp_file_init(void)
286 num_blocks); 291 num_blocks);
287 if (record == NULL) { 292 if (record == NULL) {
288 fclose(filep); 293 fclose(filep);
294 close(fd);
289 return 1; 295 return 1;
290 } 296 }
291 continue; 297 continue;
@@ -765,7 +771,9 @@ static void kvp_process_ipconfig_file(char *cmd,
765 break; 771 break;
766 772
767 x = strchr(p, '\n'); 773 x = strchr(p, '\n');
768 *x = '\0'; 774 if (x)
775 *x = '\0';
776
769 strcat(config_buf, p); 777 strcat(config_buf, p);
770 strcat(config_buf, ";"); 778 strcat(config_buf, ";");
771 } 779 }
@@ -1016,9 +1024,10 @@ kvp_get_ip_info(int family, char *if_name, int op,
1016 1024
1017 if (sn_offset == 0) 1025 if (sn_offset == 0)
1018 strcpy(sn_str, cidr_mask); 1026 strcpy(sn_str, cidr_mask);
1019 else 1027 else {
1028 strcat((char *)ip_buffer->sub_net, ";");
1020 strcat(sn_str, cidr_mask); 1029 strcat(sn_str, cidr_mask);
1021 strcat((char *)ip_buffer->sub_net, ";"); 1030 }
1022 sn_offset += strlen(sn_str) + 1; 1031 sn_offset += strlen(sn_str) + 1;
1023 } 1032 }
1024 1033
@@ -1274,7 +1283,8 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1274 file = fopen(if_file, "w"); 1283 file = fopen(if_file, "w");
1275 1284
1276 if (file == NULL) { 1285 if (file == NULL) {
1277 syslog(LOG_ERR, "Failed to open config file"); 1286 syslog(LOG_ERR, "Failed to open config file; error: %d %s",
1287 errno, strerror(errno));
1278 return HV_E_FAIL; 1288 return HV_E_FAIL;
1279 } 1289 }
1280 1290
@@ -1289,6 +1299,7 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1289 } 1299 }
1290 1300
1291 error = kvp_write_file(file, "HWADDR", "", mac_addr); 1301 error = kvp_write_file(file, "HWADDR", "", mac_addr);
1302 free(mac_addr);
1292 if (error) 1303 if (error)
1293 goto setval_error; 1304 goto setval_error;
1294 1305
@@ -1334,7 +1345,6 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1334 goto setval_error; 1345 goto setval_error;
1335 1346
1336setval_done: 1347setval_done:
1337 free(mac_addr);
1338 fclose(file); 1348 fclose(file);
1339 1349
1340 /* 1350 /*
@@ -1343,12 +1353,15 @@ setval_done:
1343 */ 1353 */
1344 1354
1345 snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file); 1355 snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file);
1346 system(cmd); 1356 if (system(cmd)) {
1357 syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
1358 cmd, errno, strerror(errno));
1359 return HV_E_FAIL;
1360 }
1347 return 0; 1361 return 0;
1348 1362
1349setval_error: 1363setval_error:
1350 syslog(LOG_ERR, "Failed to write config file"); 1364 syslog(LOG_ERR, "Failed to write config file");
1351 free(mac_addr);
1352 fclose(file); 1365 fclose(file);
1353 return error; 1366 return error;
1354} 1367}
@@ -1379,23 +1392,18 @@ kvp_get_domain_name(char *buffer, int length)
1379static int 1392static int
1380netlink_send(int fd, struct cn_msg *msg) 1393netlink_send(int fd, struct cn_msg *msg)
1381{ 1394{
1382 struct nlmsghdr *nlh; 1395 struct nlmsghdr nlh = { .nlmsg_type = NLMSG_DONE };
1383 unsigned int size; 1396 unsigned int size;
1384 struct msghdr message; 1397 struct msghdr message;
1385 char buffer[64];
1386 struct iovec iov[2]; 1398 struct iovec iov[2];
1387 1399
1388 size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len); 1400 size = sizeof(struct cn_msg) + msg->len;
1389 1401
1390 nlh = (struct nlmsghdr *)buffer; 1402 nlh.nlmsg_pid = getpid();
1391 nlh->nlmsg_seq = 0; 1403 nlh.nlmsg_len = NLMSG_LENGTH(size);
1392 nlh->nlmsg_pid = getpid();
1393 nlh->nlmsg_type = NLMSG_DONE;
1394 nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
1395 nlh->nlmsg_flags = 0;
1396 1404
1397 iov[0].iov_base = nlh; 1405 iov[0].iov_base = &nlh;
1398 iov[0].iov_len = sizeof(*nlh); 1406 iov[0].iov_len = sizeof(nlh);
1399 1407
1400 iov[1].iov_base = msg; 1408 iov[1].iov_base = msg;
1401 iov[1].iov_len = size; 1409 iov[1].iov_len = size;
@@ -1425,10 +1433,22 @@ int main(void)
1425 int pool; 1433 int pool;
1426 char *if_name; 1434 char *if_name;
1427 struct hv_kvp_ipaddr_value *kvp_ip_val; 1435 struct hv_kvp_ipaddr_value *kvp_ip_val;
1436 char *kvp_send_buffer;
1437 char *kvp_recv_buffer;
1438 size_t kvp_recv_buffer_len;
1428 1439
1429 daemon(1, 0); 1440 if (daemon(1, 0))
1441 return 1;
1430 openlog("KVP", 0, LOG_USER); 1442 openlog("KVP", 0, LOG_USER);
1431 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); 1443 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1444
1445 kvp_recv_buffer_len = NLMSG_HDRLEN + 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);
1448 if (!(kvp_send_buffer && kvp_recv_buffer)) {
1449 syslog(LOG_ERR, "Failed to allocate netlink buffers");
1450 exit(EXIT_FAILURE);
1451 }
1432 /* 1452 /*
1433 * Retrieve OS release information. 1453 * Retrieve OS release information.
1434 */ 1454 */
@@ -1441,7 +1461,8 @@ int main(void)
1441 1461
1442 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); 1462 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
1443 if (fd < 0) { 1463 if (fd < 0) {
1444 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); 1464 syslog(LOG_ERR, "netlink socket creation failed; error: %d %s", errno,
1465 strerror(errno));
1445 exit(EXIT_FAILURE); 1466 exit(EXIT_FAILURE);
1446 } 1467 }
1447 addr.nl_family = AF_NETLINK; 1468 addr.nl_family = AF_NETLINK;
@@ -1452,12 +1473,18 @@ int main(void)
1452 1473
1453 error = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); 1474 error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
1454 if (error < 0) { 1475 if (error < 0) {
1455 syslog(LOG_ERR, "bind failed; error:%d", error); 1476 syslog(LOG_ERR, "bind failed; error: %d %s", errno, strerror(errno));
1456 close(fd); 1477 close(fd);
1457 exit(EXIT_FAILURE); 1478 exit(EXIT_FAILURE);
1458 } 1479 }
1459 nl_group = CN_KVP_IDX; 1480 nl_group = CN_KVP_IDX;
1460 setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)); 1481
1482 if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)) < 0) {
1483 syslog(LOG_ERR, "setsockopt failed; error: %d %s", errno, strerror(errno));
1484 close(fd);
1485 exit(EXIT_FAILURE);
1486 }
1487
1461 /* 1488 /*
1462 * Register ourselves with the kernel. 1489 * Register ourselves with the kernel.
1463 */ 1490 */
@@ -1472,7 +1499,7 @@ int main(void)
1472 1499
1473 len = netlink_send(fd, message); 1500 len = netlink_send(fd, message);
1474 if (len < 0) { 1501 if (len < 0) {
1475 syslog(LOG_ERR, "netlink_send failed; error:%d", len); 1502 syslog(LOG_ERR, "netlink_send failed; error: %d %s", errno, strerror(errno));
1476 close(fd); 1503 close(fd);
1477 exit(EXIT_FAILURE); 1504 exit(EXIT_FAILURE);
1478 } 1505 }
@@ -1484,9 +1511,18 @@ int main(void)
1484 socklen_t addr_l = sizeof(addr); 1511 socklen_t addr_l = sizeof(addr);
1485 pfd.events = POLLIN; 1512 pfd.events = POLLIN;
1486 pfd.revents = 0; 1513 pfd.revents = 0;
1487 poll(&pfd, 1, -1);
1488 1514
1489 len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0, 1515 if (poll(&pfd, 1, -1) < 0) {
1516 syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno));
1517 if (errno == EINVAL) {
1518 close(fd);
1519 exit(EXIT_FAILURE);
1520 }
1521 else
1522 continue;
1523 }
1524
1525 len = recvfrom(fd, kvp_recv_buffer, kvp_recv_buffer_len, 0,
1490 addr_p, &addr_l); 1526 addr_p, &addr_l);
1491 1527
1492 if (len < 0) { 1528 if (len < 0) {
@@ -1695,7 +1731,8 @@ kvp_done:
1695 1731
1696 len = netlink_send(fd, incoming_cn_msg); 1732 len = netlink_send(fd, incoming_cn_msg);
1697 if (len < 0) { 1733 if (len < 0) {
1698 syslog(LOG_ERR, "net_link send failed; error:%d", len); 1734 syslog(LOG_ERR, "net_link send failed; error: %d %s", errno,
1735 strerror(errno));
1699 exit(EXIT_FAILURE); 1736 exit(EXIT_FAILURE);
1700 } 1737 }
1701 } 1738 }
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index fea03a3edaf4..8611962c672c 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -38,8 +38,6 @@
38#include <linux/netlink.h> 38#include <linux/netlink.h>
39#include <syslog.h> 39#include <syslog.h>
40 40
41static char vss_recv_buffer[4096];
42static char vss_send_buffer[4096];
43static struct sockaddr_nl addr; 41static struct sockaddr_nl addr;
44 42
45#ifndef SOL_NETLINK 43#ifndef SOL_NETLINK
@@ -107,23 +105,18 @@ static int vss_operate(int operation)
107 105
108static int netlink_send(int fd, struct cn_msg *msg) 106static int netlink_send(int fd, struct cn_msg *msg)
109{ 107{
110 struct nlmsghdr *nlh; 108 struct nlmsghdr nlh = { .nlmsg_type = NLMSG_DONE };
111 unsigned int size; 109 unsigned int size;
112 struct msghdr message; 110 struct msghdr message;
113 char buffer[64];
114 struct iovec iov[2]; 111 struct iovec iov[2];
115 112
116 size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len); 113 size = sizeof(struct cn_msg) + msg->len;
117 114
118 nlh = (struct nlmsghdr *)buffer; 115 nlh.nlmsg_pid = getpid();
119 nlh->nlmsg_seq = 0; 116 nlh.nlmsg_len = NLMSG_LENGTH(size);
120 nlh->nlmsg_pid = getpid();
121 nlh->nlmsg_type = NLMSG_DONE;
122 nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
123 nlh->nlmsg_flags = 0;
124 117
125 iov[0].iov_base = nlh; 118 iov[0].iov_base = &nlh;
126 iov[0].iov_len = sizeof(*nlh); 119 iov[0].iov_len = sizeof(nlh);
127 120
128 iov[1].iov_base = msg; 121 iov[1].iov_base = msg;
129 iov[1].iov_len = size; 122 iov[1].iov_len = size;
@@ -147,6 +140,9 @@ int main(void)
147 struct cn_msg *incoming_cn_msg; 140 struct cn_msg *incoming_cn_msg;
148 int op; 141 int op;
149 struct hv_vss_msg *vss_msg; 142 struct hv_vss_msg *vss_msg;
143 char *vss_send_buffer;
144 char *vss_recv_buffer;
145 size_t vss_recv_buffer_len;
150 146
151 if (daemon(1, 0)) 147 if (daemon(1, 0))
152 return 1; 148 return 1;
@@ -154,9 +150,18 @@ int main(void)
154 openlog("Hyper-V VSS", 0, LOG_USER); 150 openlog("Hyper-V VSS", 0, LOG_USER);
155 syslog(LOG_INFO, "VSS starting; pid is:%d", getpid()); 151 syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
156 152
153 vss_recv_buffer_len = NLMSG_HDRLEN + 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);
156 if (!(vss_send_buffer && vss_recv_buffer)) {
157 syslog(LOG_ERR, "Failed to allocate netlink buffers");
158 exit(EXIT_FAILURE);
159 }
160
157 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); 161 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
158 if (fd < 0) { 162 if (fd < 0) {
159 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); 163 syslog(LOG_ERR, "netlink socket creation failed; error:%d %s",
164 errno, strerror(errno));
160 exit(EXIT_FAILURE); 165 exit(EXIT_FAILURE);
161 } 166 }
162 addr.nl_family = AF_NETLINK; 167 addr.nl_family = AF_NETLINK;
@@ -167,12 +172,16 @@ int main(void)
167 172
168 error = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); 173 error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
169 if (error < 0) { 174 if (error < 0) {
170 syslog(LOG_ERR, "bind failed; error:%d", error); 175 syslog(LOG_ERR, "bind failed; error:%d %s", errno, strerror(errno));
171 close(fd); 176 close(fd);
172 exit(EXIT_FAILURE); 177 exit(EXIT_FAILURE);
173 } 178 }
174 nl_group = CN_VSS_IDX; 179 nl_group = CN_VSS_IDX;
175 setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)); 180 if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)) < 0) {
181 syslog(LOG_ERR, "setsockopt failed; error:%d %s", errno, strerror(errno));
182 close(fd);
183 exit(EXIT_FAILURE);
184 }
176 /* 185 /*
177 * Register ourselves with the kernel. 186 * Register ourselves with the kernel.
178 */ 187 */
@@ -187,7 +196,7 @@ int main(void)
187 196
188 len = netlink_send(fd, message); 197 len = netlink_send(fd, message);
189 if (len < 0) { 198 if (len < 0) {
190 syslog(LOG_ERR, "netlink_send failed; error:%d", len); 199 syslog(LOG_ERR, "netlink_send failed; error:%d %s", errno, strerror(errno));
191 close(fd); 200 close(fd);
192 exit(EXIT_FAILURE); 201 exit(EXIT_FAILURE);
193 } 202 }
@@ -199,9 +208,18 @@ int main(void)
199 socklen_t addr_l = sizeof(addr); 208 socklen_t addr_l = sizeof(addr);
200 pfd.events = POLLIN; 209 pfd.events = POLLIN;
201 pfd.revents = 0; 210 pfd.revents = 0;
202 poll(&pfd, 1, -1);
203 211
204 len = recvfrom(fd, vss_recv_buffer, sizeof(vss_recv_buffer), 0, 212 if (poll(&pfd, 1, -1) < 0) {
213 syslog(LOG_ERR, "poll failed; error:%d %s", errno, strerror(errno));
214 if (errno == EINVAL) {
215 close(fd);
216 exit(EXIT_FAILURE);
217 }
218 else
219 continue;
220 }
221
222 len = recvfrom(fd, vss_recv_buffer, vss_recv_buffer_len, 0,
205 addr_p, &addr_l); 223 addr_p, &addr_l);
206 224
207 if (len < 0) { 225 if (len < 0) {
@@ -241,7 +259,8 @@ int main(void)
241 vss_msg->error = error; 259 vss_msg->error = error;
242 len = netlink_send(fd, incoming_cn_msg); 260 len = netlink_send(fd, incoming_cn_msg);
243 if (len < 0) { 261 if (len < 0) {
244 syslog(LOG_ERR, "net_link send failed; error:%d", len); 262 syslog(LOG_ERR, "net_link send failed; error:%d %s",
263 errno, strerror(errno));
245 exit(EXIT_FAILURE); 264 exit(EXIT_FAILURE);
246 } 265 }
247 } 266 }
diff --git a/tools/include/tools/be_byteshift.h b/tools/include/tools/be_byteshift.h
index f4912e2668ba..84c17d836578 100644
--- a/tools/include/tools/be_byteshift.h
+++ b/tools/include/tools/be_byteshift.h
@@ -1,68 +1,68 @@
1#ifndef _TOOLS_BE_BYTESHIFT_H 1#ifndef _TOOLS_BE_BYTESHIFT_H
2#define _TOOLS_BE_BYTESHIFT_H 2#define _TOOLS_BE_BYTESHIFT_H
3 3
4#include <linux/types.h> 4#include <stdint.h>
5 5
6static inline __u16 __get_unaligned_be16(const __u8 *p) 6static inline uint16_t __get_unaligned_be16(const uint8_t *p)
7{ 7{
8 return p[0] << 8 | p[1]; 8 return p[0] << 8 | p[1];
9} 9}
10 10
11static inline __u32 __get_unaligned_be32(const __u8 *p) 11static inline uint32_t __get_unaligned_be32(const uint8_t *p)
12{ 12{
13 return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; 13 return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
14} 14}
15 15
16static inline __u64 __get_unaligned_be64(const __u8 *p) 16static inline uint64_t __get_unaligned_be64(const uint8_t *p)
17{ 17{
18 return (__u64)__get_unaligned_be32(p) << 32 | 18 return (uint64_t)__get_unaligned_be32(p) << 32 |
19 __get_unaligned_be32(p + 4); 19 __get_unaligned_be32(p + 4);
20} 20}
21 21
22static inline void __put_unaligned_be16(__u16 val, __u8 *p) 22static inline void __put_unaligned_be16(uint16_t val, uint8_t *p)
23{ 23{
24 *p++ = val >> 8; 24 *p++ = val >> 8;
25 *p++ = val; 25 *p++ = val;
26} 26}
27 27
28static inline void __put_unaligned_be32(__u32 val, __u8 *p) 28static inline void __put_unaligned_be32(uint32_t val, uint8_t *p)
29{ 29{
30 __put_unaligned_be16(val >> 16, p); 30 __put_unaligned_be16(val >> 16, p);
31 __put_unaligned_be16(val, p + 2); 31 __put_unaligned_be16(val, p + 2);
32} 32}
33 33
34static inline void __put_unaligned_be64(__u64 val, __u8 *p) 34static inline void __put_unaligned_be64(uint64_t val, uint8_t *p)
35{ 35{
36 __put_unaligned_be32(val >> 32, p); 36 __put_unaligned_be32(val >> 32, p);
37 __put_unaligned_be32(val, p + 4); 37 __put_unaligned_be32(val, p + 4);
38} 38}
39 39
40static inline __u16 get_unaligned_be16(const void *p) 40static inline uint16_t get_unaligned_be16(const void *p)
41{ 41{
42 return __get_unaligned_be16((const __u8 *)p); 42 return __get_unaligned_be16((const uint8_t *)p);
43} 43}
44 44
45static inline __u32 get_unaligned_be32(const void *p) 45static inline uint32_t get_unaligned_be32(const void *p)
46{ 46{
47 return __get_unaligned_be32((const __u8 *)p); 47 return __get_unaligned_be32((const uint8_t *)p);
48} 48}
49 49
50static inline __u64 get_unaligned_be64(const void *p) 50static inline uint64_t get_unaligned_be64(const void *p)
51{ 51{
52 return __get_unaligned_be64((const __u8 *)p); 52 return __get_unaligned_be64((const uint8_t *)p);
53} 53}
54 54
55static inline void put_unaligned_be16(__u16 val, void *p) 55static inline void put_unaligned_be16(uint16_t val, void *p)
56{ 56{
57 __put_unaligned_be16(val, p); 57 __put_unaligned_be16(val, p);
58} 58}
59 59
60static inline void put_unaligned_be32(__u32 val, void *p) 60static inline void put_unaligned_be32(uint32_t val, void *p)
61{ 61{
62 __put_unaligned_be32(val, p); 62 __put_unaligned_be32(val, p);
63} 63}
64 64
65static inline void put_unaligned_be64(__u64 val, void *p) 65static inline void put_unaligned_be64(uint64_t val, void *p)
66{ 66{
67 __put_unaligned_be64(val, p); 67 __put_unaligned_be64(val, p);
68} 68}
diff --git a/tools/include/tools/le_byteshift.h b/tools/include/tools/le_byteshift.h
index c99d45a68bda..8fe9f2488ec7 100644
--- a/tools/include/tools/le_byteshift.h
+++ b/tools/include/tools/le_byteshift.h
@@ -1,68 +1,68 @@
1#ifndef _TOOLS_LE_BYTESHIFT_H 1#ifndef _TOOLS_LE_BYTESHIFT_H
2#define _TOOLS_LE_BYTESHIFT_H 2#define _TOOLS_LE_BYTESHIFT_H
3 3
4#include <linux/types.h> 4#include <stdint.h>
5 5
6static inline __u16 __get_unaligned_le16(const __u8 *p) 6static inline uint16_t __get_unaligned_le16(const uint8_t *p)
7{ 7{
8 return p[0] | p[1] << 8; 8 return p[0] | p[1] << 8;
9} 9}
10 10
11static inline __u32 __get_unaligned_le32(const __u8 *p) 11static inline uint32_t __get_unaligned_le32(const uint8_t *p)
12{ 12{
13 return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; 13 return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
14} 14}
15 15
16static inline __u64 __get_unaligned_le64(const __u8 *p) 16static inline uint64_t __get_unaligned_le64(const uint8_t *p)
17{ 17{
18 return (__u64)__get_unaligned_le32(p + 4) << 32 | 18 return (uint64_t)__get_unaligned_le32(p + 4) << 32 |
19 __get_unaligned_le32(p); 19 __get_unaligned_le32(p);
20} 20}
21 21
22static inline void __put_unaligned_le16(__u16 val, __u8 *p) 22static inline void __put_unaligned_le16(uint16_t val, uint8_t *p)
23{ 23{
24 *p++ = val; 24 *p++ = val;
25 *p++ = val >> 8; 25 *p++ = val >> 8;
26} 26}
27 27
28static inline void __put_unaligned_le32(__u32 val, __u8 *p) 28static inline void __put_unaligned_le32(uint32_t val, uint8_t *p)
29{ 29{
30 __put_unaligned_le16(val >> 16, p + 2); 30 __put_unaligned_le16(val >> 16, p + 2);
31 __put_unaligned_le16(val, p); 31 __put_unaligned_le16(val, p);
32} 32}
33 33
34static inline void __put_unaligned_le64(__u64 val, __u8 *p) 34static inline void __put_unaligned_le64(uint64_t val, uint8_t *p)
35{ 35{
36 __put_unaligned_le32(val >> 32, p + 4); 36 __put_unaligned_le32(val >> 32, p + 4);
37 __put_unaligned_le32(val, p); 37 __put_unaligned_le32(val, p);
38} 38}
39 39
40static inline __u16 get_unaligned_le16(const void *p) 40static inline uint16_t get_unaligned_le16(const void *p)
41{ 41{
42 return __get_unaligned_le16((const __u8 *)p); 42 return __get_unaligned_le16((const uint8_t *)p);
43} 43}
44 44
45static inline __u32 get_unaligned_le32(const void *p) 45static inline uint32_t get_unaligned_le32(const void *p)
46{ 46{
47 return __get_unaligned_le32((const __u8 *)p); 47 return __get_unaligned_le32((const uint8_t *)p);
48} 48}
49 49
50static inline __u64 get_unaligned_le64(const void *p) 50static inline uint64_t get_unaligned_le64(const void *p)
51{ 51{
52 return __get_unaligned_le64((const __u8 *)p); 52 return __get_unaligned_le64((const uint8_t *)p);
53} 53}
54 54
55static inline void put_unaligned_le16(__u16 val, void *p) 55static inline void put_unaligned_le16(uint16_t val, void *p)
56{ 56{
57 __put_unaligned_le16(val, p); 57 __put_unaligned_le16(val, p);
58} 58}
59 59
60static inline void put_unaligned_le32(__u32 val, void *p) 60static inline void put_unaligned_le32(uint32_t val, void *p)
61{ 61{
62 __put_unaligned_le32(val, p); 62 __put_unaligned_le32(val, p);
63} 63}
64 64
65static inline void put_unaligned_le64(__u64 val, void *p) 65static inline void put_unaligned_le64(uint64_t val, void *p)
66{ 66{
67 __put_unaligned_le64(val, p); 67 __put_unaligned_le64(val, p);
68} 68}
diff --git a/tools/lguest/Makefile b/tools/lguest/Makefile
index 0ac34206f7a7..97bca4871ea3 100644
--- a/tools/lguest/Makefile
+++ b/tools/lguest/Makefile
@@ -1,5 +1,4 @@
1# This creates the demonstration utility "lguest" which runs a Linux guest. 1# This creates the demonstration utility "lguest" which runs a Linux guest.
2# Missing headers? Add "-I../../../include -I../../../arch/x86/include"
3CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE 2CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE
4 3
5all: lguest 4all: lguest
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c
index 07a03452c227..32cf2ce15d69 100644
--- a/tools/lguest/lguest.c
+++ b/tools/lguest/lguest.c
@@ -42,14 +42,10 @@
42#include <pwd.h> 42#include <pwd.h>
43#include <grp.h> 43#include <grp.h>
44 44
45#include <linux/virtio_config.h> 45#ifndef VIRTIO_F_ANY_LAYOUT
46#include <linux/virtio_net.h> 46#define VIRTIO_F_ANY_LAYOUT 27
47#include <linux/virtio_blk.h> 47#endif
48#include <linux/virtio_console.h> 48
49#include <linux/virtio_rng.h>
50#include <linux/virtio_ring.h>
51#include <asm/bootparam.h>
52#include "../../include/linux/lguest_launcher.h"
53/*L:110 49/*L:110
54 * We can ignore the 43 include files we need for this program, but I do want 50 * We can ignore the 43 include files we need for this program, but I do want
55 * to draw attention to the use of kernel-style types. 51 * to draw attention to the use of kernel-style types.
@@ -65,6 +61,15 @@ typedef uint16_t u16;
65typedef uint8_t u8; 61typedef uint8_t u8;
66/*:*/ 62/*:*/
67 63
64#include <linux/virtio_config.h>
65#include <linux/virtio_net.h>
66#include <linux/virtio_blk.h>
67#include <linux/virtio_console.h>
68#include <linux/virtio_rng.h>
69#include <linux/virtio_ring.h>
70#include <asm/bootparam.h>
71#include "../../include/linux/lguest_launcher.h"
72
68#define BRIDGE_PFX "bridge:" 73#define BRIDGE_PFX "bridge:"
69#ifndef SIOCBRADDIF 74#ifndef SIOCBRADDIF
70#define SIOCBRADDIF 0x89a2 /* add interface to bridge */ 75#define SIOCBRADDIF 0x89a2 /* add interface to bridge */
@@ -177,7 +182,8 @@ static struct termios orig_term;
177 * in precise order. 182 * in precise order.
178 */ 183 */
179#define wmb() __asm__ __volatile__("" : : : "memory") 184#define wmb() __asm__ __volatile__("" : : : "memory")
180#define mb() __asm__ __volatile__("" : : : "memory") 185#define rmb() __asm__ __volatile__("lock; addl $0,0(%%esp)" : : : "memory")
186#define mb() __asm__ __volatile__("lock; addl $0,0(%%esp)" : : : "memory")
181 187
182/* Wrapper for the last available index. Makes it easier to change. */ 188/* Wrapper for the last available index. Makes it easier to change. */
183#define lg_last_avail(vq) ((vq)->last_avail_idx) 189#define lg_last_avail(vq) ((vq)->last_avail_idx)
@@ -676,6 +682,12 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
676 errx(1, "Guest moved used index from %u to %u", 682 errx(1, "Guest moved used index from %u to %u",
677 last_avail, vq->vring.avail->idx); 683 last_avail, vq->vring.avail->idx);
678 684
685 /*
686 * Make sure we read the descriptor number *after* we read the ring
687 * update; don't let the cpu or compiler change the order.
688 */
689 rmb();
690
679 /* 691 /*
680 * Grab the next descriptor number they're advertising, and increment 692 * Grab the next descriptor number they're advertising, and increment
681 * the index we've seen. 693 * the index we've seen.
@@ -695,6 +707,12 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
695 i = head; 707 i = head;
696 708
697 /* 709 /*
710 * We have to read the descriptor after we read the descriptor number,
711 * but there's a data dependency there so the CPU shouldn't reorder
712 * that: no rmb() required.
713 */
714
715 /*
698 * If this is an indirect entry, then this buffer contains a descriptor 716 * If this is an indirect entry, then this buffer contains a descriptor
699 * table which we handle as if it's any normal descriptor chain. 717 * table which we handle as if it's any normal descriptor chain.
700 */ 718 */
@@ -1530,6 +1548,8 @@ static void setup_tun_net(char *arg)
1530 add_feature(dev, VIRTIO_NET_F_HOST_ECN); 1548 add_feature(dev, VIRTIO_NET_F_HOST_ECN);
1531 /* We handle indirect ring entries */ 1549 /* We handle indirect ring entries */
1532 add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC); 1550 add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC);
1551 /* We're compliant with the damn spec. */
1552 add_feature(dev, VIRTIO_F_ANY_LAYOUT);
1533 set_config(dev, sizeof(conf), &conf); 1553 set_config(dev, sizeof(conf), &conf);
1534 1554
1535 /* We don't need the socket any more; setup is done. */ 1555 /* We don't need the socket any more; setup is done. */
diff --git a/tools/lib/lk/Makefile b/tools/lib/lk/Makefile
index 926cbf3efc7f..3dba0a4aebbf 100644
--- a/tools/lib/lk/Makefile
+++ b/tools/lib/lk/Makefile
@@ -1,5 +1,8 @@
1include ../../scripts/Makefile.include 1include ../../scripts/Makefile.include
2 2
3CC = $(CROSS_COMPILE)gcc
4AR = $(CROSS_COMPILE)ar
5
3# guard against environment variables 6# guard against environment variables
4LIB_H= 7LIB_H=
5LIB_OBJS= 8LIB_OBJS=
@@ -11,7 +14,7 @@ LIB_OBJS += $(OUTPUT)debugfs.o
11LIBFILE = liblk.a 14LIBFILE = liblk.a
12 15
13CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC 16CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC
14EXTLIBS = -lpthread -lrt -lelf -lm 17EXTLIBS = -lelf -lpthread -lrt -lm
15ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 18ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
16ALL_LDFLAGS = $(LDFLAGS) 19ALL_LDFLAGS = $(LDFLAGS)
17 20
diff --git a/tools/lib/lk/debugfs.c b/tools/lib/lk/debugfs.c
index 099e7cd022e4..7c4347962353 100644
--- a/tools/lib/lk/debugfs.c
+++ b/tools/lib/lk/debugfs.c
@@ -5,7 +5,6 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include <sys/vfs.h> 6#include <sys/vfs.h>
7#include <sys/mount.h> 7#include <sys/mount.h>
8#include <linux/magic.h>
9#include <linux/kernel.h> 8#include <linux/kernel.h>
10 9
11#include "debugfs.h" 10#include "debugfs.h"
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index 0b0a90787db6..ca6cb779876a 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -39,13 +39,8 @@ bindir_relative = bin
39bindir = $(prefix)/$(bindir_relative) 39bindir = $(prefix)/$(bindir_relative)
40man_dir = $(prefix)/share/man 40man_dir = $(prefix)/share/man
41man_dir_SQ = '$(subst ','\'',$(man_dir))' 41man_dir_SQ = '$(subst ','\'',$(man_dir))'
42html_install = $(prefix)/share/kernelshark/html
43html_install_SQ = '$(subst ','\'',$(html_install))'
44img_install = $(prefix)/share/kernelshark/html/images
45img_install_SQ = '$(subst ','\'',$(img_install))'
46 42
47export man_dir man_dir_SQ html_install html_install_SQ INSTALL 43export man_dir man_dir_SQ INSTALL
48export img_install img_install_SQ
49export DESTDIR DESTDIR_SQ 44export DESTDIR DESTDIR_SQ
50 45
51# copy a bit from Linux kbuild 46# copy a bit from Linux kbuild
@@ -65,7 +60,7 @@ ifeq ($(BUILD_SRC),)
65ifneq ($(BUILD_OUTPUT),) 60ifneq ($(BUILD_OUTPUT),)
66 61
67define build_output 62define build_output
68 $(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) \ 63 $(if $(VERBOSE:1=),@)+$(MAKE) -C $(BUILD_OUTPUT) \
69 BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1 64 BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1
70endef 65endef
71 66
@@ -76,10 +71,7 @@ $(if $(BUILD_OUTPUT),, \
76 71
77all: sub-make 72all: sub-make
78 73
79gui: force 74$(MAKECMDGOALS): sub-make
80 $(call build_output, all_cmd)
81
82$(filter-out gui,$(MAKECMDGOALS)): sub-make
83 75
84sub-make: force 76sub-make: force
85 $(call build_output, $(MAKECMDGOALS)) 77 $(call build_output, $(MAKECMDGOALS))
@@ -189,6 +181,7 @@ $(obj)/%.o: $(src)/%.c
189 $(Q)$(call do_compile) 181 $(Q)$(call do_compile)
190 182
191PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o 183PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
184PEVENT_LIB_OBJS += kbuffer-parse.o
192 185
193ALL_OBJS = $(PEVENT_LIB_OBJS) 186ALL_OBJS = $(PEVENT_LIB_OBJS)
194 187
@@ -258,9 +251,6 @@ define check_deps
258 $(RM) $@.$$$$ 251 $(RM) $@.$$$$
259endef 252endef
260 253
261$(gui_deps): ks_version.h
262$(non_gui_deps): tc_version.h
263
264$(all_deps): .%.d: $(src)/%.c 254$(all_deps): .%.d: $(src)/%.c
265 $(Q)$(call check_deps) 255 $(Q)$(call check_deps)
266 256
@@ -300,7 +290,7 @@ define do_install
300 $(INSTALL) $1 '$(DESTDIR_SQ)$2' 290 $(INSTALL) $1 '$(DESTDIR_SQ)$2'
301endef 291endef
302 292
303install_lib: all_cmd install_plugins install_python 293install_lib: all_cmd
304 $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) 294 $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
305 295
306install: install_lib 296install: install_lib
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 82b0606dcb8a..d1c2a6a4cd32 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -5450,10 +5450,9 @@ int pevent_register_print_function(struct pevent *pevent,
5450 * If @id is >= 0, then it is used to find the event. 5450 * If @id is >= 0, then it is used to find the event.
5451 * else @sys_name and @event_name are used. 5451 * else @sys_name and @event_name are used.
5452 */ 5452 */
5453int pevent_register_event_handler(struct pevent *pevent, 5453int pevent_register_event_handler(struct pevent *pevent, int id,
5454 int id, char *sys_name, char *event_name, 5454 const char *sys_name, const char *event_name,
5455 pevent_event_handler_func func, 5455 pevent_event_handler_func func, void *context)
5456 void *context)
5457{ 5456{
5458 struct event_format *event; 5457 struct event_format *event;
5459 struct event_handler *handle; 5458 struct event_handler *handle;
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 7be7e89533e4..c37b2026d04a 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -69,6 +69,7 @@ struct trace_seq {
69}; 69};
70 70
71void trace_seq_init(struct trace_seq *s); 71void trace_seq_init(struct trace_seq *s);
72void trace_seq_reset(struct trace_seq *s);
72void trace_seq_destroy(struct trace_seq *s); 73void trace_seq_destroy(struct trace_seq *s);
73 74
74extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) 75extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
@@ -399,6 +400,7 @@ struct pevent {
399 400
400 int cpus; 401 int cpus;
401 int long_size; 402 int long_size;
403 int page_size;
402 404
403 struct cmdline *cmdlines; 405 struct cmdline *cmdlines;
404 struct cmdline_list *cmdlist; 406 struct cmdline_list *cmdlist;
@@ -561,7 +563,8 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
561 struct event_format *event, const char *name, 563 struct event_format *event, const char *name,
562 struct pevent_record *record, int err); 564 struct pevent_record *record, int err);
563 565
564int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name, 566int pevent_register_event_handler(struct pevent *pevent, int id,
567 const char *sys_name, const char *event_name,
565 pevent_event_handler_func func, void *context); 568 pevent_event_handler_func func, void *context);
566int pevent_register_print_function(struct pevent *pevent, 569int pevent_register_print_function(struct pevent *pevent,
567 pevent_func_handler func, 570 pevent_func_handler func,
@@ -619,6 +622,16 @@ static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
619 pevent->long_size = long_size; 622 pevent->long_size = long_size;
620} 623}
621 624
625static inline int pevent_get_page_size(struct pevent *pevent)
626{
627 return pevent->page_size;
628}
629
630static inline void pevent_set_page_size(struct pevent *pevent, int _page_size)
631{
632 pevent->page_size = _page_size;
633}
634
622static inline int pevent_is_file_bigendian(struct pevent *pevent) 635static inline int pevent_is_file_bigendian(struct pevent *pevent)
623{ 636{
624 return pevent->file_bigendian; 637 return pevent->file_bigendian;
diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c
new file mode 100644
index 000000000000..dcc665228c71
--- /dev/null
+++ b/tools/lib/traceevent/kbuffer-parse.c
@@ -0,0 +1,732 @@
1/*
2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
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 Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "kbuffer.h"
26
27#define MISSING_EVENTS (1 << 31)
28#define MISSING_STORED (1 << 30)
29
30#define COMMIT_MASK ((1 << 27) - 1)
31
32enum {
33 KBUFFER_FL_HOST_BIG_ENDIAN = (1<<0),
34 KBUFFER_FL_BIG_ENDIAN = (1<<1),
35 KBUFFER_FL_LONG_8 = (1<<2),
36 KBUFFER_FL_OLD_FORMAT = (1<<3),
37};
38
39#define ENDIAN_MASK (KBUFFER_FL_HOST_BIG_ENDIAN | KBUFFER_FL_BIG_ENDIAN)
40
41/** kbuffer
42 * @timestamp - timestamp of current event
43 * @lost_events - # of lost events between this subbuffer and previous
44 * @flags - special flags of the kbuffer
45 * @subbuffer - pointer to the sub-buffer page
46 * @data - pointer to the start of data on the sub-buffer page
47 * @index - index from @data to the @curr event data
48 * @curr - offset from @data to the start of current event
49 * (includes metadata)
50 * @next - offset from @data to the start of next event
51 * @size - The size of data on @data
52 * @start - The offset from @subbuffer where @data lives
53 *
54 * @read_4 - Function to read 4 raw bytes (may swap)
55 * @read_8 - Function to read 8 raw bytes (may swap)
56 * @read_long - Function to read a long word (4 or 8 bytes with needed swap)
57 */
58struct kbuffer {
59 unsigned long long timestamp;
60 long long lost_events;
61 unsigned long flags;
62 void *subbuffer;
63 void *data;
64 unsigned int index;
65 unsigned int curr;
66 unsigned int next;
67 unsigned int size;
68 unsigned int start;
69
70 unsigned int (*read_4)(void *ptr);
71 unsigned long long (*read_8)(void *ptr);
72 unsigned long long (*read_long)(struct kbuffer *kbuf, void *ptr);
73 int (*next_event)(struct kbuffer *kbuf);
74};
75
76static void *zmalloc(size_t size)
77{
78 return calloc(1, size);
79}
80
81static int host_is_bigendian(void)
82{
83 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
84 unsigned int *ptr;
85
86 ptr = (unsigned int *)str;
87 return *ptr == 0x01020304;
88}
89
90static int do_swap(struct kbuffer *kbuf)
91{
92 return ((kbuf->flags & KBUFFER_FL_HOST_BIG_ENDIAN) + kbuf->flags) &
93 ENDIAN_MASK;
94}
95
96static unsigned long long __read_8(void *ptr)
97{
98 unsigned long long data = *(unsigned long long *)ptr;
99
100 return data;
101}
102
103static unsigned long long __read_8_sw(void *ptr)
104{
105 unsigned long long data = *(unsigned long long *)ptr;
106 unsigned long long swap;
107
108 swap = ((data & 0xffULL) << 56) |
109 ((data & (0xffULL << 8)) << 40) |
110 ((data & (0xffULL << 16)) << 24) |
111 ((data & (0xffULL << 24)) << 8) |
112 ((data & (0xffULL << 32)) >> 8) |
113 ((data & (0xffULL << 40)) >> 24) |
114 ((data & (0xffULL << 48)) >> 40) |
115 ((data & (0xffULL << 56)) >> 56);
116
117 return swap;
118}
119
120static unsigned int __read_4(void *ptr)
121{
122 unsigned int data = *(unsigned int *)ptr;
123
124 return data;
125}
126
127static unsigned int __read_4_sw(void *ptr)
128{
129 unsigned int data = *(unsigned int *)ptr;
130 unsigned int swap;
131
132 swap = ((data & 0xffULL) << 24) |
133 ((data & (0xffULL << 8)) << 8) |
134 ((data & (0xffULL << 16)) >> 8) |
135 ((data & (0xffULL << 24)) >> 24);
136
137 return swap;
138}
139
140static unsigned long long read_8(struct kbuffer *kbuf, void *ptr)
141{
142 return kbuf->read_8(ptr);
143}
144
145static unsigned int read_4(struct kbuffer *kbuf, void *ptr)
146{
147 return kbuf->read_4(ptr);
148}
149
150static unsigned long long __read_long_8(struct kbuffer *kbuf, void *ptr)
151{
152 return kbuf->read_8(ptr);
153}
154
155static unsigned long long __read_long_4(struct kbuffer *kbuf, void *ptr)
156{
157 return kbuf->read_4(ptr);
158}
159
160static unsigned long long read_long(struct kbuffer *kbuf, void *ptr)
161{
162 return kbuf->read_long(kbuf, ptr);
163}
164
165static int calc_index(struct kbuffer *kbuf, void *ptr)
166{
167 return (unsigned long)ptr - (unsigned long)kbuf->data;
168}
169
170static int __next_event(struct kbuffer *kbuf);
171
172/**
173 * kbuffer_alloc - allocat a new kbuffer
174 * @size; enum to denote size of word
175 * @endian: enum to denote endianness
176 *
177 * Allocates and returns a new kbuffer.
178 */
179struct kbuffer *
180kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian)
181{
182 struct kbuffer *kbuf;
183 int flags = 0;
184
185 switch (size) {
186 case KBUFFER_LSIZE_4:
187 break;
188 case KBUFFER_LSIZE_8:
189 flags |= KBUFFER_FL_LONG_8;
190 break;
191 default:
192 return NULL;
193 }
194
195 switch (endian) {
196 case KBUFFER_ENDIAN_LITTLE:
197 break;
198 case KBUFFER_ENDIAN_BIG:
199 flags |= KBUFFER_FL_BIG_ENDIAN;
200 break;
201 default:
202 return NULL;
203 }
204
205 kbuf = zmalloc(sizeof(*kbuf));
206 if (!kbuf)
207 return NULL;
208
209 kbuf->flags = flags;
210
211 if (host_is_bigendian())
212 kbuf->flags |= KBUFFER_FL_HOST_BIG_ENDIAN;
213
214 if (do_swap(kbuf)) {
215 kbuf->read_8 = __read_8_sw;
216 kbuf->read_4 = __read_4_sw;
217 } else {
218 kbuf->read_8 = __read_8;
219 kbuf->read_4 = __read_4;
220 }
221
222 if (kbuf->flags & KBUFFER_FL_LONG_8)
223 kbuf->read_long = __read_long_8;
224 else
225 kbuf->read_long = __read_long_4;
226
227 /* May be changed by kbuffer_set_old_format() */
228 kbuf->next_event = __next_event;
229
230 return kbuf;
231}
232
233/** kbuffer_free - free an allocated kbuffer
234 * @kbuf: The kbuffer to free
235 *
236 * Can take NULL as a parameter.
237 */
238void kbuffer_free(struct kbuffer *kbuf)
239{
240 free(kbuf);
241}
242
243static unsigned int type4host(struct kbuffer *kbuf,
244 unsigned int type_len_ts)
245{
246 if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
247 return (type_len_ts >> 29) & 3;
248 else
249 return type_len_ts & 3;
250}
251
252static unsigned int len4host(struct kbuffer *kbuf,
253 unsigned int type_len_ts)
254{
255 if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
256 return (type_len_ts >> 27) & 7;
257 else
258 return (type_len_ts >> 2) & 7;
259}
260
261static unsigned int type_len4host(struct kbuffer *kbuf,
262 unsigned int type_len_ts)
263{
264 if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
265 return (type_len_ts >> 27) & ((1 << 5) - 1);
266 else
267 return type_len_ts & ((1 << 5) - 1);
268}
269
270static unsigned int ts4host(struct kbuffer *kbuf,
271 unsigned int type_len_ts)
272{
273 if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
274 return type_len_ts & ((1 << 27) - 1);
275 else
276 return type_len_ts >> 5;
277}
278
279/*
280 * Linux 2.6.30 and earlier (not much ealier) had a different
281 * ring buffer format. It should be obsolete, but we handle it anyway.
282 */
283enum old_ring_buffer_type {
284 OLD_RINGBUF_TYPE_PADDING,
285 OLD_RINGBUF_TYPE_TIME_EXTEND,
286 OLD_RINGBUF_TYPE_TIME_STAMP,
287 OLD_RINGBUF_TYPE_DATA,
288};
289
290static unsigned int old_update_pointers(struct kbuffer *kbuf)
291{
292 unsigned long long extend;
293 unsigned int type_len_ts;
294 unsigned int type;
295 unsigned int len;
296 unsigned int delta;
297 unsigned int length;
298 void *ptr = kbuf->data + kbuf->curr;
299
300 type_len_ts = read_4(kbuf, ptr);
301 ptr += 4;
302
303 type = type4host(kbuf, type_len_ts);
304 len = len4host(kbuf, type_len_ts);
305 delta = ts4host(kbuf, type_len_ts);
306
307 switch (type) {
308 case OLD_RINGBUF_TYPE_PADDING:
309 kbuf->next = kbuf->size;
310 return 0;
311
312 case OLD_RINGBUF_TYPE_TIME_EXTEND:
313 extend = read_4(kbuf, ptr);
314 extend <<= TS_SHIFT;
315 extend += delta;
316 delta = extend;
317 ptr += 4;
318 break;
319
320 case OLD_RINGBUF_TYPE_TIME_STAMP:
321 /* should never happen! */
322 kbuf->curr = kbuf->size;
323 kbuf->next = kbuf->size;
324 kbuf->index = kbuf->size;
325 return -1;
326 default:
327 if (len)
328 length = len * 4;
329 else {
330 length = read_4(kbuf, ptr);
331 length -= 4;
332 ptr += 4;
333 }
334 break;
335 }
336
337 kbuf->timestamp += delta;
338 kbuf->index = calc_index(kbuf, ptr);
339 kbuf->next = kbuf->index + length;
340
341 return type;
342}
343
344static int __old_next_event(struct kbuffer *kbuf)
345{
346 int type;
347
348 do {
349 kbuf->curr = kbuf->next;
350 if (kbuf->next >= kbuf->size)
351 return -1;
352 type = old_update_pointers(kbuf);
353 } while (type == OLD_RINGBUF_TYPE_TIME_EXTEND || type == OLD_RINGBUF_TYPE_PADDING);
354
355 return 0;
356}
357
358static unsigned int
359translate_data(struct kbuffer *kbuf, void *data, void **rptr,
360 unsigned long long *delta, int *length)
361{
362 unsigned long long extend;
363 unsigned int type_len_ts;
364 unsigned int type_len;
365
366 type_len_ts = read_4(kbuf, data);
367 data += 4;
368
369 type_len = type_len4host(kbuf, type_len_ts);
370 *delta = ts4host(kbuf, type_len_ts);
371
372 switch (type_len) {
373 case KBUFFER_TYPE_PADDING:
374 *length = read_4(kbuf, data);
375 data += *length;
376 break;
377
378 case KBUFFER_TYPE_TIME_EXTEND:
379 extend = read_4(kbuf, data);
380 data += 4;
381 extend <<= TS_SHIFT;
382 extend += *delta;
383 *delta = extend;
384 *length = 0;
385 break;
386
387 case KBUFFER_TYPE_TIME_STAMP:
388 data += 12;
389 *length = 0;
390 break;
391 case 0:
392 *length = read_4(kbuf, data) - 4;
393 *length = (*length + 3) & ~3;
394 data += 4;
395 break;
396 default:
397 *length = type_len * 4;
398 break;
399 }
400
401 *rptr = data;
402
403 return type_len;
404}
405
406static unsigned int update_pointers(struct kbuffer *kbuf)
407{
408 unsigned long long delta;
409 unsigned int type_len;
410 int length;
411 void *ptr = kbuf->data + kbuf->curr;
412
413 type_len = translate_data(kbuf, ptr, &ptr, &delta, &length);
414
415 kbuf->timestamp += delta;
416 kbuf->index = calc_index(kbuf, ptr);
417 kbuf->next = kbuf->index + length;
418
419 return type_len;
420}
421
422/**
423 * kbuffer_translate_data - read raw data to get a record
424 * @swap: Set to 1 if bytes in words need to be swapped when read
425 * @data: The raw data to read
426 * @size: Address to store the size of the event data.
427 *
428 * Returns a pointer to the event data. To determine the entire
429 * record size (record metadata + data) just add the difference between
430 * @data and the returned value to @size.
431 */
432void *kbuffer_translate_data(int swap, void *data, unsigned int *size)
433{
434 unsigned long long delta;
435 struct kbuffer kbuf;
436 int type_len;
437 int length;
438 void *ptr;
439
440 if (swap) {
441 kbuf.read_8 = __read_8_sw;
442 kbuf.read_4 = __read_4_sw;
443 kbuf.flags = host_is_bigendian() ? 0 : KBUFFER_FL_BIG_ENDIAN;
444 } else {
445 kbuf.read_8 = __read_8;
446 kbuf.read_4 = __read_4;
447 kbuf.flags = host_is_bigendian() ? KBUFFER_FL_BIG_ENDIAN: 0;
448 }
449
450 type_len = translate_data(&kbuf, data, &ptr, &delta, &length);
451 switch (type_len) {
452 case KBUFFER_TYPE_PADDING:
453 case KBUFFER_TYPE_TIME_EXTEND:
454 case KBUFFER_TYPE_TIME_STAMP:
455 return NULL;
456 };
457
458 *size = length;
459
460 return ptr;
461}
462
463static int __next_event(struct kbuffer *kbuf)
464{
465 int type;
466
467 do {
468 kbuf->curr = kbuf->next;
469 if (kbuf->next >= kbuf->size)
470 return -1;
471 type = update_pointers(kbuf);
472 } while (type == KBUFFER_TYPE_TIME_EXTEND || type == KBUFFER_TYPE_PADDING);
473
474 return 0;
475}
476
477static int next_event(struct kbuffer *kbuf)
478{
479 return kbuf->next_event(kbuf);
480}
481
482/**
483 * kbuffer_next_event - increment the current pointer
484 * @kbuf: The kbuffer to read
485 * @ts: Address to store the next record's timestamp (may be NULL to ignore)
486 *
487 * Increments the pointers into the subbuffer of the kbuffer to point to the
488 * next event so that the next kbuffer_read_event() will return a
489 * new event.
490 *
491 * Returns the data of the next event if a new event exists on the subbuffer,
492 * NULL otherwise.
493 */
494void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts)
495{
496 int ret;
497
498 if (!kbuf || !kbuf->subbuffer)
499 return NULL;
500
501 ret = next_event(kbuf);
502 if (ret < 0)
503 return NULL;
504
505 if (ts)
506 *ts = kbuf->timestamp;
507
508 return kbuf->data + kbuf->index;
509}
510
511/**
512 * kbuffer_load_subbuffer - load a new subbuffer into the kbuffer
513 * @kbuf: The kbuffer to load
514 * @subbuffer: The subbuffer to load into @kbuf.
515 *
516 * Load a new subbuffer (page) into @kbuf. This will reset all
517 * the pointers and update the @kbuf timestamp. The next read will
518 * return the first event on @subbuffer.
519 *
520 * Returns 0 on succes, -1 otherwise.
521 */
522int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer)
523{
524 unsigned long long flags;
525 void *ptr = subbuffer;
526
527 if (!kbuf || !subbuffer)
528 return -1;
529
530 kbuf->subbuffer = subbuffer;
531
532 kbuf->timestamp = read_8(kbuf, ptr);
533 ptr += 8;
534
535 kbuf->curr = 0;
536
537 if (kbuf->flags & KBUFFER_FL_LONG_8)
538 kbuf->start = 16;
539 else
540 kbuf->start = 12;
541
542 kbuf->data = subbuffer + kbuf->start;
543
544 flags = read_long(kbuf, ptr);
545 kbuf->size = (unsigned int)flags & COMMIT_MASK;
546
547 if (flags & MISSING_EVENTS) {
548 if (flags & MISSING_STORED) {
549 ptr = kbuf->data + kbuf->size;
550 kbuf->lost_events = read_long(kbuf, ptr);
551 } else
552 kbuf->lost_events = -1;
553 } else
554 kbuf->lost_events = 0;
555
556 kbuf->index = 0;
557 kbuf->next = 0;
558
559 next_event(kbuf);
560
561 return 0;
562}
563
564/**
565 * kbuffer_read_event - read the next event in the kbuffer subbuffer
566 * @kbuf: The kbuffer to read from
567 * @ts: The address to store the timestamp of the event (may be NULL to ignore)
568 *
569 * Returns a pointer to the data part of the current event.
570 * NULL if no event is left on the subbuffer.
571 */
572void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts)
573{
574 if (!kbuf || !kbuf->subbuffer)
575 return NULL;
576
577 if (kbuf->curr >= kbuf->size)
578 return NULL;
579
580 if (ts)
581 *ts = kbuf->timestamp;
582 return kbuf->data + kbuf->index;
583}
584
585/**
586 * kbuffer_timestamp - Return the timestamp of the current event
587 * @kbuf: The kbuffer to read from
588 *
589 * Returns the timestamp of the current (next) event.
590 */
591unsigned long long kbuffer_timestamp(struct kbuffer *kbuf)
592{
593 return kbuf->timestamp;
594}
595
596/**
597 * kbuffer_read_at_offset - read the event that is at offset
598 * @kbuf: The kbuffer to read from
599 * @offset: The offset into the subbuffer
600 * @ts: The address to store the timestamp of the event (may be NULL to ignore)
601 *
602 * The @offset must be an index from the @kbuf subbuffer beginning.
603 * If @offset is bigger than the stored subbuffer, NULL will be returned.
604 *
605 * Returns the data of the record that is at @offset. Note, @offset does
606 * not need to be the start of the record, the offset just needs to be
607 * in the record (or beginning of it).
608 *
609 * Note, the kbuf timestamp and pointers are updated to the
610 * returned record. That is, kbuffer_read_event() will return the same
611 * data and timestamp, and kbuffer_next_event() will increment from
612 * this record.
613 */
614void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset,
615 unsigned long long *ts)
616{
617 void *data;
618
619 if (offset < kbuf->start)
620 offset = 0;
621 else
622 offset -= kbuf->start;
623
624 /* Reset the buffer */
625 kbuffer_load_subbuffer(kbuf, kbuf->subbuffer);
626
627 while (kbuf->curr < offset) {
628 data = kbuffer_next_event(kbuf, ts);
629 if (!data)
630 break;
631 }
632
633 return data;
634}
635
636/**
637 * kbuffer_subbuffer_size - the size of the loaded subbuffer
638 * @kbuf: The kbuffer to read from
639 *
640 * Returns the size of the subbuffer. Note, this size is
641 * where the last event resides. The stored subbuffer may actually be
642 * bigger due to padding and such.
643 */
644int kbuffer_subbuffer_size(struct kbuffer *kbuf)
645{
646 return kbuf->size;
647}
648
649/**
650 * kbuffer_curr_index - Return the index of the record
651 * @kbuf: The kbuffer to read from
652 *
653 * Returns the index from the start of the data part of
654 * the subbuffer to the current location. Note this is not
655 * from the start of the subbuffer. An index of zero will
656 * point to the first record. Use kbuffer_curr_offset() for
657 * the actually offset (that can be used by kbuffer_read_at_offset())
658 */
659int kbuffer_curr_index(struct kbuffer *kbuf)
660{
661 return kbuf->curr;
662}
663
664/**
665 * kbuffer_curr_offset - Return the offset of the record
666 * @kbuf: The kbuffer to read from
667 *
668 * Returns the offset from the start of the subbuffer to the
669 * current location.
670 */
671int kbuffer_curr_offset(struct kbuffer *kbuf)
672{
673 return kbuf->curr + kbuf->start;
674}
675
676/**
677 * kbuffer_event_size - return the size of the event data
678 * @kbuf: The kbuffer to read
679 *
680 * Returns the size of the event data (the payload not counting
681 * the meta data of the record) of the current event.
682 */
683int kbuffer_event_size(struct kbuffer *kbuf)
684{
685 return kbuf->next - kbuf->index;
686}
687
688/**
689 * kbuffer_curr_size - return the size of the entire record
690 * @kbuf: The kbuffer to read
691 *
692 * Returns the size of the entire record (meta data and payload)
693 * of the current event.
694 */
695int kbuffer_curr_size(struct kbuffer *kbuf)
696{
697 return kbuf->next - kbuf->curr;
698}
699
700/**
701 * kbuffer_missed_events - return the # of missed events from last event.
702 * @kbuf: The kbuffer to read from
703 *
704 * Returns the # of missed events (if recorded) before the current
705 * event. Note, only events on the beginning of a subbuffer can
706 * have missed events, all other events within the buffer will be
707 * zero.
708 */
709int kbuffer_missed_events(struct kbuffer *kbuf)
710{
711 /* Only the first event can have missed events */
712 if (kbuf->curr)
713 return 0;
714
715 return kbuf->lost_events;
716}
717
718/**
719 * kbuffer_set_old_forma - set the kbuffer to use the old format parsing
720 * @kbuf: The kbuffer to set
721 *
722 * This is obsolete (or should be). The first kernels to use the
723 * new ring buffer had a slightly different ring buffer format
724 * (2.6.30 and earlier). It is still somewhat supported by kbuffer,
725 * but should not be counted on in the future.
726 */
727void kbuffer_set_old_format(struct kbuffer *kbuf)
728{
729 kbuf->flags |= KBUFFER_FL_OLD_FORMAT;
730
731 kbuf->next_event = __old_next_event;
732}
diff --git a/tools/lib/traceevent/kbuffer.h b/tools/lib/traceevent/kbuffer.h
new file mode 100644
index 000000000000..c831f64b17a0
--- /dev/null
+++ b/tools/lib/traceevent/kbuffer.h
@@ -0,0 +1,67 @@
1/*
2 * Copyright (C) 2012 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
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 Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#ifndef _KBUFFER_H
22#define _KBUFFER_H
23
24#ifndef TS_SHIFT
25#define TS_SHIFT 27
26#endif
27
28enum kbuffer_endian {
29 KBUFFER_ENDIAN_BIG,
30 KBUFFER_ENDIAN_LITTLE,
31};
32
33enum kbuffer_long_size {
34 KBUFFER_LSIZE_4,
35 KBUFFER_LSIZE_8,
36};
37
38enum {
39 KBUFFER_TYPE_PADDING = 29,
40 KBUFFER_TYPE_TIME_EXTEND = 30,
41 KBUFFER_TYPE_TIME_STAMP = 31,
42};
43
44struct kbuffer;
45
46struct kbuffer *kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian);
47void kbuffer_free(struct kbuffer *kbuf);
48int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer);
49void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts);
50void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts);
51unsigned long long kbuffer_timestamp(struct kbuffer *kbuf);
52
53void *kbuffer_translate_data(int swap, void *data, unsigned int *size);
54
55void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, unsigned long long *ts);
56
57int kbuffer_curr_index(struct kbuffer *kbuf);
58
59int kbuffer_curr_offset(struct kbuffer *kbuf);
60int kbuffer_curr_size(struct kbuffer *kbuf);
61int kbuffer_event_size(struct kbuffer *kbuf);
62int kbuffer_missed_events(struct kbuffer *kbuf);
63int kbuffer_subbuffer_size(struct kbuffer *kbuf);
64
65void kbuffer_set_old_format(struct kbuffer *kbuf);
66
67#endif /* _K_BUFFER_H */
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c
index a57db805136a..d7f2e68bc5b9 100644
--- a/tools/lib/traceevent/trace-seq.c
+++ b/tools/lib/traceevent/trace-seq.c
@@ -49,6 +49,19 @@ void trace_seq_init(struct trace_seq *s)
49} 49}
50 50
51/** 51/**
52 * trace_seq_reset - re-initialize the trace_seq structure
53 * @s: a pointer to the trace_seq structure to reset
54 */
55void trace_seq_reset(struct trace_seq *s)
56{
57 if (!s)
58 return;
59 TRACE_SEQ_CHECK(s);
60 s->len = 0;
61 s->readpos = 0;
62}
63
64/**
52 * trace_seq_destroy - free up memory of a trace_seq 65 * trace_seq_destroy - free up memory of a trace_seq
53 * @s: a pointer to the trace_seq to free the buffer 66 * @s: a pointer to the trace_seq to free the buffer
54 * 67 *
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index eb30044a922a..5a37a7c84e69 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -1,12 +1,6 @@
1include ../../scripts/Makefile.include
1include ../config/utilities.mak 2include ../config/utilities.mak
2 3
3OUTPUT := ./
4ifeq ("$(origin O)", "command line")
5 ifneq ($(O),)
6 OUTPUT := $(O)/
7 endif
8endif
9
10MAN1_TXT= \ 4MAN1_TXT= \
11 $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \ 5 $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
12 $(wildcard perf-*.txt)) \ 6 $(wildcard perf-*.txt)) \
@@ -150,7 +144,7 @@ NO_SUBDIR = :
150endif 144endif
151 145
152ifneq ($(findstring $(MAKEFLAGS),s),s) 146ifneq ($(findstring $(MAKEFLAGS),s),s)
153ifndef V 147ifneq ($(V),1)
154 QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@; 148 QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@;
155 QUIET_XMLTO = @echo ' ' XMLTO $@; 149 QUIET_XMLTO = @echo ' ' XMLTO $@;
156 QUIET_DB2TEXI = @echo ' ' DB2TEXI $@; 150 QUIET_DB2TEXI = @echo ' ' DB2TEXI $@;
@@ -277,7 +271,7 @@ $(MAN_HTML): $(OUTPUT)%.html : %.txt
277 271
278$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml 272$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml
279 $(QUIET_XMLTO)$(RM) $@ && \ 273 $(QUIET_XMLTO)$(RM) $@ && \
280 $(XMLTO) -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< 274 $(XMLTO) -o $(OUTPUT). -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
281 275
282$(OUTPUT)%.xml : %.txt 276$(OUTPUT)%.xml : %.txt
283 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ 277 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
diff --git a/tools/perf/Documentation/examples.txt b/tools/perf/Documentation/examples.txt
index 77f952762426..a4e392156488 100644
--- a/tools/perf/Documentation/examples.txt
+++ b/tools/perf/Documentation/examples.txt
@@ -66,7 +66,7 @@ Furthermore, these tracepoints can be used to sample the workload as
66well. For example the page allocations done by a 'git gc' can be 66well. For example the page allocations done by a 'git gc' can be
67captured the following way: 67captured the following way:
68 68
69 titan:~/git> perf record -f -e kmem:mm_page_alloc -c 1 ./git gc 69 titan:~/git> perf record -e kmem:mm_page_alloc -c 1 ./git gc
70 Counting objects: 1148, done. 70 Counting objects: 1148, done.
71 Delta compression using up to 2 threads. 71 Delta compression using up to 2 threads.
72 Compressing objects: 100% (450/450), done. 72 Compressing objects: 100% (450/450), done.
@@ -120,7 +120,7 @@ Furthermore, call-graph sampling can be done too, of page
120allocations - to see precisely what kind of page allocations there 120allocations - to see precisely what kind of page allocations there
121are: 121are:
122 122
123 titan:~/git> perf record -f -g -e kmem:mm_page_alloc -c 1 ./git gc 123 titan:~/git> perf record -g -e kmem:mm_page_alloc -c 1 ./git gc
124 Counting objects: 1148, done. 124 Counting objects: 1148, done.
125 Delta compression using up to 2 threads. 125 Delta compression using up to 2 threads.
126 Compressing objects: 100% (450/450), done. 126 Compressing objects: 100% (450/450), done.
diff --git a/tools/perf/Documentation/perf-archive.txt b/tools/perf/Documentation/perf-archive.txt
index fae174dc7d01..5032a142853e 100644
--- a/tools/perf/Documentation/perf-archive.txt
+++ b/tools/perf/Documentation/perf-archive.txt
@@ -13,7 +13,7 @@ SYNOPSIS
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command runs runs perf-buildid-list --with-hits, and collects the files 15This command runs runs perf-buildid-list --with-hits, and collects the files
16with the buildids found so that analisys of perf.data contents can be possible 16with the buildids found so that analysis of perf.data contents can be possible
17on another machine. 17on another machine.
18 18
19 19
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 5b3123d5721f..fdfceee0ffd0 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -3,17 +3,17 @@ perf-diff(1)
3 3
4NAME 4NAME
5---- 5----
6perf-diff - Read two perf.data files and display the differential profile 6perf-diff - Read perf.data files and display the differential profile
7 7
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf diff' [oldfile] [newfile] 11'perf diff' [baseline file] [data file1] [[data file2] ... ]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command displays the performance difference amongst two perf.data files 15This command displays the performance difference amongst two or more perf.data
16captured via perf record. 16files captured via perf record.
17 17
18If no parameters are passed it will assume perf.data.old and perf.data. 18If no parameters are passed it will assume perf.data.old and perf.data.
19 19
@@ -75,8 +75,6 @@ OPTIONS
75-c:: 75-c::
76--compute:: 76--compute::
77 Differential computation selection - delta,ratio,wdiff (default is delta). 77 Differential computation selection - delta,ratio,wdiff (default is delta).
78 If '+' is specified as a first character, the output is sorted based
79 on the computation results.
80 See COMPARISON METHODS section for more info. 78 See COMPARISON METHODS section for more info.
81 79
82-p:: 80-p::
@@ -87,6 +85,63 @@ OPTIONS
87--formula:: 85--formula::
88 Show formula for given computation. 86 Show formula for given computation.
89 87
88-o::
89--order::
90 Specify compute sorting column number.
91
92COMPARISON
93----------
94The comparison is governed by the baseline file. The baseline perf.data
95file is iterated for samples. All other perf.data files specified on
96the command line are searched for the baseline sample pair. If the pair
97is found, specified computation is made and result is displayed.
98
99All samples from non-baseline perf.data files, that do not match any
100baseline entry, are displayed with empty space within baseline column
101and possible computation results (delta) in their related column.
102
103Example files samples:
104- file A with samples f1, f2, f3, f4, f6
105- file B with samples f2, f4, f5
106- file C with samples f1, f2, f5
107
108Example output:
109 x - computation takes place for pair
110 b - baseline sample percentage
111
112- perf diff A B C
113
114 baseline/A compute/B compute/C samples
115 ---------------------------------------
116 b x f1
117 b x x f2
118 b f3
119 b x f4
120 b f6
121 x x f5
122
123- perf diff B A C
124
125 baseline/B compute/A compute/C samples
126 ---------------------------------------
127 b x x f2
128 b x f4
129 b x f5
130 x x f1
131 x f3
132 x f6
133
134- perf diff C B A
135
136 baseline/C compute/B compute/A samples
137 ---------------------------------------
138 b x f1
139 b x x f2
140 b x f5
141 x f3
142 x x f4
143 x f6
144
90COMPARISON METHODS 145COMPARISON METHODS
91------------------ 146------------------
92delta 147delta
@@ -96,7 +151,7 @@ If specified the 'Delta' column is displayed with value 'd' computed as:
96 d = A->period_percent - B->period_percent 151 d = A->period_percent - B->period_percent
97 152
98with: 153with:
99 - A/B being matching hist entry from first/second file specified 154 - A/B being matching hist entry from data/baseline file specified
100 (or perf.data/perf.data.old) respectively. 155 (or perf.data/perf.data.old) respectively.
101 156
102 - period_percent being the % of the hist entry period value within 157 - period_percent being the % of the hist entry period value within
@@ -109,24 +164,26 @@ If specified the 'Ratio' column is displayed with value 'r' computed as:
109 r = A->period / B->period 164 r = A->period / B->period
110 165
111with: 166with:
112 - A/B being matching hist entry from first/second file specified 167 - A/B being matching hist entry from data/baseline file specified
113 (or perf.data/perf.data.old) respectively. 168 (or perf.data/perf.data.old) respectively.
114 169
115 - period being the hist entry period value 170 - period being the hist entry period value
116 171
117wdiff 172wdiff:WEIGHT-B,WEIGHT-A
118~~~~~ 173~~~~~~~~~~~~~~~~~~~~~~~
119If specified the 'Weighted diff' column is displayed with value 'd' computed as: 174If specified the 'Weighted diff' column is displayed with value 'd' computed as:
120 175
121 d = B->period * WEIGHT-A - A->period * WEIGHT-B 176 d = B->period * WEIGHT-A - A->period * WEIGHT-B
122 177
123 - A/B being matching hist entry from first/second file specified 178 - A/B being matching hist entry from data/baseline file specified
124 (or perf.data/perf.data.old) respectively. 179 (or perf.data/perf.data.old) respectively.
125 180
126 - period being the hist entry period value 181 - period being the hist entry period value
127 182
128 - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option 183 - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option
129 behind ':' separator like '-c wdiff:1,2'. 184 behind ':' separator like '-c wdiff:1,2'.
185 - WIEGHT-A being the weight of the data file
186 - WIEGHT-B being the weight of the baseline data file
130 187
131SEE ALSO 188SEE ALSO
132-------- 189--------
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index 326f2cb333cb..ac84db2d2334 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -13,6 +13,7 @@ SYNOPSIS
13 {top|record|report|diff|buildid-list} 13 {top|record|report|diff|buildid-list}
14'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> 14'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
15 | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} 15 | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat}
16'perf kvm stat [record|report|live] [<options>]
16 17
17DESCRIPTION 18DESCRIPTION
18----------- 19-----------
@@ -50,6 +51,10 @@ There are a couple of variants of perf kvm:
50 'perf kvm stat report' reports statistical data which includes events 51 'perf kvm stat report' reports statistical data which includes events
51 handled time, samples, and so on. 52 handled time, samples, and so on.
52 53
54 'perf kvm stat live' reports statistical data in a live mode (similar to
55 record + report but with statistical data updated live at a given display
56 rate).
57
53OPTIONS 58OPTIONS
54------- 59-------
55-i:: 60-i::
@@ -85,13 +90,50 @@ STAT REPORT OPTIONS
85--vcpu=<value>:: 90--vcpu=<value>::
86 analyze events which occures on this vcpu. (default: all vcpus) 91 analyze events which occures on this vcpu. (default: all vcpus)
87 92
88--events=<value>:: 93--event=<value>::
89 events to be analyzed. Possible values: vmexit, mmio, ioport. 94 event to be analyzed. Possible values: vmexit, mmio, ioport.
90 (default: vmexit) 95 (default: vmexit)
91-k:: 96-k::
92--key=<value>:: 97--key=<value>::
93 Sorting key. Possible values: sample (default, sort by samples 98 Sorting key. Possible values: sample (default, sort by samples
94 number), time (sort by average time). 99 number), time (sort by average time).
100-p::
101--pid=::
102 Analyze events only for given process ID(s) (comma separated list).
103
104STAT LIVE OPTIONS
105-----------------
106-d::
107--display::
108 Time in seconds between display updates
109
110-m::
111--mmap-pages=::
112 Number of mmap data pages. Must be a power of two.
113
114-a::
115--all-cpus::
116 System-wide collection from all CPUs.
117
118-p::
119--pid=::
120 Analyze events only for given process ID(s) (comma separated list).
121
122--vcpu=<value>::
123 analyze events which occures on this vcpu. (default: all vcpus)
124
125
126--event=<value>::
127 event to be analyzed. Possible values: vmexit, mmio, ioport.
128 (default: vmexit)
129
130-k::
131--key=<value>::
132 Sorting key. Possible values: sample (default, sort by samples
133 number), time (sort by average time).
134
135--duration=<value>::
136 Show events other than HLT that take longer than duration usecs.
95 137
96SEE ALSO 138SEE ALSO
97-------- 139--------
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index d1e39dc8c810..6fce6a622206 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -8,7 +8,7 @@ perf-list - List all symbolic event types
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf list' [hw|sw|cache|tracepoint|event_glob] 11'perf list' [hw|sw|cache|tracepoint|pmu|event_glob]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -29,6 +29,8 @@ counted. The following modifiers exist:
29 G - guest counting (in KVM guests) 29 G - guest counting (in KVM guests)
30 H - host counting (not in KVM guests) 30 H - host counting (not in KVM guests)
31 p - precise level 31 p - precise level
32 S - read sample value (PERF_SAMPLE_READ)
33 D - pin the event to the PMU
32 34
33The 'p' modifier can be used for specifying how precise the instruction 35The 'p' modifier can be used for specifying how precise the instruction
34address should be. The 'p' modifier can be specified multiple times: 36address should be. The 'p' modifier can be specified multiple times:
@@ -104,6 +106,8 @@ To limit the list use:
104 'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched, 106 'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
105 block, etc. 107 block, etc.
106 108
109. 'pmu' to print the kernel supplied PMU events.
110
107. If none of the above is matched, it will apply the supplied glob to all 111. If none of the above is matched, it will apply the supplied glob to all
108 events, printing the ones that match. 112 events, printing the ones that match.
109 113
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index d4da111ef53d..e297b74471b8 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -65,16 +65,10 @@ OPTIONS
65-r:: 65-r::
66--realtime=:: 66--realtime=::
67 Collect data with this RT SCHED_FIFO priority. 67 Collect data with this RT SCHED_FIFO priority.
68
68-D:: 69-D::
69--no-delay:: 70--no-delay::
70 Collect data without buffering. 71 Collect data without buffering.
71-A::
72--append::
73 Append to the output file to do incremental profiling.
74
75-f::
76--force::
77 Overwrite existing data file. (deprecated)
78 72
79-c:: 73-c::
80--count=:: 74--count=::
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 7d5f4f38aa52..2b8097ee39d8 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -115,7 +115,7 @@ OPTIONS
115--dump-raw-trace:: 115--dump-raw-trace::
116 Dump raw trace in ASCII. 116 Dump raw trace in ASCII.
117 117
118-g [type,min[,limit],order]:: 118-g [type,min[,limit],order[,key]]::
119--call-graph:: 119--call-graph::
120 Display call chains using type, min percent threshold, optional print 120 Display call chains using type, min percent threshold, optional print
121 limit and order. 121 limit and order.
@@ -129,12 +129,21 @@ OPTIONS
129 - callee: callee based call graph. 129 - callee: callee based call graph.
130 - caller: inverted caller based call graph. 130 - caller: inverted caller based call graph.
131 131
132 Default: fractal,0.5,callee. 132 key can be:
133 - function: compare on functions
134 - address: compare on individual code addresses
135
136 Default: fractal,0.5,callee,function.
133 137
134-G:: 138-G::
135--inverted:: 139--inverted::
136 alias for inverted caller based call graph. 140 alias for inverted caller based call graph.
137 141
142--ignore-callees=<regex>::
143 Ignore callees of the function(s) matching the given regex.
144 This has the effect of collecting the callers of each such
145 function into one place in the call-graph tree.
146
138--pretty=<key>:: 147--pretty=<key>::
139 Pretty printing style. key: normal, raw 148 Pretty printing style. key: normal, raw
140 149
@@ -210,6 +219,10 @@ OPTIONS
210 Demangle symbol names to human readable form. It's enabled by default, 219 Demangle symbol names to human readable form. It's enabled by default,
211 disable with --no-demangle. 220 disable with --no-demangle.
212 221
222--percent-limit::
223 Do not show entries which have an overhead under that percent.
224 (Default: 0).
225
213SEE ALSO 226SEE ALSO
214-------- 227--------
215linkperf:perf-stat[1], linkperf:perf-annotate[1] 228linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 2fe87fb558f0..73c9759005a3 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -132,6 +132,11 @@ is a useful mode to detect imbalance between physical cores. To enable this mod
132use --per-core in addition to -a. (system-wide). The output includes the 132use --per-core in addition to -a. (system-wide). The output includes the
133core number and the number of online logical processors on that physical processor. 133core number and the number of online logical processors on that physical processor.
134 134
135-D msecs::
136--initial-delay msecs::
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.
139
135EXAMPLES 140EXAMPLES
136-------- 141--------
137 142
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 9f1a2fe54757..58d6598a9686 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -155,6 +155,15 @@ Default is to monitor all CPUS.
155 155
156 Default: fractal,0.5,callee. 156 Default: fractal,0.5,callee.
157 157
158--ignore-callees=<regex>::
159 Ignore callees of the function(s) matching the given regex.
160 This has the effect of collecting the callers of each such
161 function into one place in the call-graph tree.
162
163--percent-limit::
164 Do not show entries which have an overhead under that percent.
165 (Default: 0).
166
158INTERACTIVE PROMPTING KEYS 167INTERACTIVE PROMPTING KEYS
159-------------------------- 168--------------------------
160 169
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 68718ccdd178..daccd2c0a48f 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -23,25 +23,45 @@ analysis phases.
23OPTIONS 23OPTIONS
24------- 24-------
25 25
26-a::
26--all-cpus:: 27--all-cpus::
27 System-wide collection from all CPUs. 28 System-wide collection from all CPUs.
28 29
30-e::
31--expr::
32 List of events to show, currently only syscall names.
33 Prefixing with ! shows all syscalls but the ones specified. You may
34 need to escape it.
35
36-o::
37--output=::
38 Output file name.
39
29-p:: 40-p::
30--pid=:: 41--pid=::
31 Record events on existing process ID (comma separated list). 42 Record events on existing process ID (comma separated list).
32 43
44-t::
33--tid=:: 45--tid=::
34 Record events on existing thread ID (comma separated list). 46 Record events on existing thread ID (comma separated list).
35 47
48-u::
36--uid=:: 49--uid=::
37 Record events in threads owned by uid. Name or number. 50 Record events in threads owned by uid. Name or number.
38 51
52-v::
53--verbose=::
54 Verbosity level.
55
56-i::
39--no-inherit:: 57--no-inherit::
40 Child tasks do not inherit counters. 58 Child tasks do not inherit counters.
41 59
60-m::
42--mmap-pages=:: 61--mmap-pages=::
43 Number of mmap data pages. Must be a power of two. 62 Number of mmap data pages. Must be a power of two.
44 63
64-C::
45--cpu:: 65--cpu::
46Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a 66Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a
47comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. 67comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
@@ -54,6 +74,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
54--sched: 74--sched:
55 Accrue thread runtime and provide a summary at the end of the session. 75 Accrue thread runtime and provide a summary at the end of the session.
56 76
77-i
78--input
79 Process events from a given perf data file.
80
57SEE ALSO 81SEE ALSO
58-------- 82--------
59linkperf:perf-record[1], linkperf:perf-script[1] 83linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index b0f164b133d9..3a0ff7fb71b6 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -51,189 +51,63 @@ include config/utilities.mak
51# Define NO_BACKTRACE if you do not want stack backtrace debug feature 51# Define NO_BACKTRACE if you do not want stack backtrace debug feature
52# 52#
53# Define NO_LIBNUMA if you do not want numa perf benchmark 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
54 58
55$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 59ifeq ($(srctree),)
56 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 60srctree := $(patsubst %/,%,$(dir $(shell pwd)))
57 61srctree := $(patsubst %/,%,$(dir $(srctree)))
58uname_M := $(shell uname -m 2>/dev/null || echo not) 62#$(info Determined 'srctree' to be $(srctree))
59
60ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
61 -e s/arm.*/arm/ -e s/sa110/arm/ \
62 -e s/s390x/s390/ -e s/parisc64/parisc/ \
63 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
64 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
65NO_PERF_REGS := 1
66
67CC = $(CROSS_COMPILE)gcc
68AR = $(CROSS_COMPILE)ar
69
70# Additional ARCH settings for x86
71ifeq ($(ARCH),i386)
72 override ARCH := x86
73 NO_PERF_REGS := 0
74 LIBUNWIND_LIBS = -lunwind -lunwind-x86
75endif
76ifeq ($(ARCH),x86_64)
77 override ARCH := x86
78 IS_X86_64 := 0
79 ifeq (, $(findstring m32,$(EXTRA_CFLAGS)))
80 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1)
81 endif
82 ifeq (${IS_X86_64}, 1)
83 RAW_ARCH := x86_64
84 ARCH_CFLAGS := -DARCH_X86_64
85 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
86 endif
87 NO_PERF_REGS := 0
88 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
89endif
90
91# Treat warnings as errors unless directed not to
92ifneq ($(WERROR),0)
93 CFLAGS_WERROR := -Werror
94endif
95
96ifeq ("$(origin DEBUG)", "command line")
97 PERF_DEBUG = $(DEBUG)
98endif
99ifndef PERF_DEBUG
100 CFLAGS_OPTIMIZE = -O6
101endif 63endif
102 64
103ifdef PARSER_DEBUG 65ifneq ($(objtree),)
104 PARSER_DEBUG_BISON := -t 66#$(info Determined 'objtree' to be $(objtree))
105 PARSER_DEBUG_FLEX := -d
106 PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
107endif 67endif
108 68
109ifdef NO_NEWT 69ifneq ($(OUTPUT),)
110 NO_SLANG=1 70#$(info Determined 'OUTPUT' to be $(OUTPUT))
111endif 71endif
112 72
113CFLAGS = -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS) 73$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
114EXTLIBS = -lpthread -lrt -lelf -lm 74 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
115ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
116ALL_LDFLAGS = $(LDFLAGS)
117STRIP ?= strip
118
119# Among the variables below, these:
120# perfexecdir
121# template_dir
122# mandir
123# infodir
124# htmldir
125# ETC_PERFCONFIG (but not sysconfdir)
126# can be specified as a relative path some/where/else;
127# this is interpreted as relative to $(prefix) and "perf" at
128# runtime figures out where they are based on the path to the executable.
129# This can help installing the suite in a relocatable way.
130
131# Make the path relative to DESTDIR, not to prefix
132ifndef DESTDIR
133prefix = $(HOME)
134endif
135bindir_relative = bin
136bindir = $(prefix)/$(bindir_relative)
137mandir = share/man
138infodir = share/info
139perfexecdir = libexec/perf-core
140sharedir = $(prefix)/share
141template_dir = share/perf-core/templates
142htmldir = share/doc/perf-doc
143ifeq ($(prefix),/usr)
144sysconfdir = /etc
145ETC_PERFCONFIG = $(sysconfdir)/perfconfig
146else
147sysconfdir = $(prefix)/etc
148ETC_PERFCONFIG = etc/perfconfig
149endif
150lib = lib
151 75
152export prefix bindir sharedir sysconfdir 76CC = $(CROSS_COMPILE)gcc
77AR = $(CROSS_COMPILE)ar
153 78
154RM = rm -f 79RM = rm -f
155MKDIR = mkdir 80MKDIR = mkdir
156FIND = find 81FIND = find
157INSTALL = install 82INSTALL = install
158FLEX = flex 83FLEX = flex
159BISON= bison 84BISON = bison
160 85STRIP = strip
161# sparse is architecture-neutral, which means that we need to tell it
162# explicitly what architecture to check for. Fix this up for yours..
163SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
164
165ifneq ($(MAKECMDGOALS),clean)
166ifneq ($(MAKECMDGOALS),tags)
167-include config/feature-tests.mak
168
169ifeq ($(call get-executable,$(FLEX)),)
170 dummy := $(error Error: $(FLEX) is missing on this system, please install it)
171endif
172 86
173ifeq ($(call get-executable,$(BISON)),) 87LK_DIR = $(srctree)/tools/lib/lk/
174 dummy := $(error Error: $(BISON) is missing on this system, please install it) 88TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
175endif
176
177ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
178 CFLAGS := $(CFLAGS) -fstack-protector-all
179endif
180 89
181ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y) 90# include config/Makefile by default and rule out
182 CFLAGS := $(CFLAGS) -Wstack-protector 91# non-config cases
183endif 92config := 1
184 93
185ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y) 94NON_CONFIG_TARGETS := clean TAGS tags cscope help
186 CFLAGS := $(CFLAGS) -Wvolatile-register-var
187endif
188 95
189ifndef PERF_DEBUG 96ifdef MAKECMDGOALS
190 ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -D_FORTIFY_SOURCE=2,-D_FORTIFY_SOURCE=2),y) 97ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
191 CFLAGS := $(CFLAGS) -D_FORTIFY_SOURCE=2 98 config := 0
192 endif
193endif 99endif
194
195### --- END CONFIGURATION SECTION ---
196
197ifeq ($(srctree),)
198srctree := $(patsubst %/,%,$(dir $(shell pwd)))
199srctree := $(patsubst %/,%,$(dir $(srctree)))
200#$(info Determined 'srctree' to be $(srctree))
201endif 100endif
202 101
203ifneq ($(objtree),) 102ifeq ($(config),1)
204#$(info Determined 'objtree' to be $(objtree)) 103include config/Makefile
205endif 104endif
206 105
207ifneq ($(OUTPUT),) 106export prefix bindir sharedir sysconfdir
208#$(info Determined 'OUTPUT' to be $(OUTPUT))
209endif
210 107
211BASIC_CFLAGS = \ 108# sparse is architecture-neutral, which means that we need to tell it
212 -Iutil/include \ 109# explicitly what architecture to check for. Fix this up for yours..
213 -Iarch/$(ARCH)/include \ 110SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
214 $(if $(objtree),-I$(objtree)/arch/$(ARCH)/include/generated/uapi) \
215 -I$(srctree)/arch/$(ARCH)/include/uapi \
216 -I$(srctree)/arch/$(ARCH)/include \
217 $(if $(objtree),-I$(objtree)/include/generated/uapi) \
218 -I$(srctree)/include/uapi \
219 -I$(srctree)/include \
220 -I$(OUTPUT)util \
221 -Iutil \
222 -I. \
223 -I$(TRACE_EVENT_DIR) \
224 -I../lib/ \
225 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
226
227BASIC_LDFLAGS =
228
229ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
230 BIONIC := 1
231 EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
232 EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
233 BASIC_CFLAGS += -I.
234endif
235endif # MAKECMDGOALS != tags
236endif # MAKECMDGOALS != clean
237 111
238# Guard against environment variables 112# Guard against environment variables
239BUILTIN_OBJS = 113BUILTIN_OBJS =
@@ -247,20 +121,16 @@ SCRIPT_SH += perf-archive.sh
247grep-libs = $(filter -l%,$(1)) 121grep-libs = $(filter -l%,$(1))
248strip-libs = $(filter-out -l%,$(1)) 122strip-libs = $(filter-out -l%,$(1))
249 123
250LK_DIR = ../lib/lk/
251TRACE_EVENT_DIR = ../lib/traceevent/
252
253LK_PATH=$(LK_DIR)
254
255ifneq ($(OUTPUT),) 124ifneq ($(OUTPUT),)
256 TE_PATH=$(OUTPUT) 125 TE_PATH=$(OUTPUT)
257ifneq ($(subdir),) 126ifneq ($(subdir),)
258 LK_PATH=$(OUTPUT)$(LK_DIR) 127 LK_PATH=$(OUTPUT)/../lib/lk/
259else 128else
260 LK_PATH=$(OUTPUT) 129 LK_PATH=$(OUTPUT)
261endif 130endif
262else 131else
263 TE_PATH=$(TRACE_EVENT_DIR) 132 TE_PATH=$(TRACE_EVENT_DIR)
133 LK_PATH=$(LK_DIR)
264endif 134endif
265 135
266LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 136LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
@@ -278,10 +148,10 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
278python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so 148python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
279 149
280PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) 150PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
281PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) 151PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK)
282 152
283$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) 153$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
284 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ 154 $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
285 --quiet build_ext; \ 155 --quiet build_ext; \
286 mkdir -p $(OUTPUT)python && \ 156 mkdir -p $(OUTPUT)python && \
287 cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ 157 cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
@@ -296,8 +166,6 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
296# 166#
297PROGRAMS += $(OUTPUT)perf 167PROGRAMS += $(OUTPUT)perf
298 168
299LANG_BINDINGS =
300
301# what 'all' will build and 'install' will install, in perfexecdir 169# what 'all' will build and 'install' will install, in perfexecdir
302ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 170ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
303 171
@@ -306,10 +174,10 @@ OTHER_PROGRAMS = $(OUTPUT)perf
306 174
307# Set paths to tools early so that they can be used for version tests. 175# Set paths to tools early so that they can be used for version tests.
308ifndef SHELL_PATH 176ifndef SHELL_PATH
309 SHELL_PATH = /bin/sh 177 SHELL_PATH = /bin/sh
310endif 178endif
311ifndef PERL_PATH 179ifndef PERL_PATH
312 PERL_PATH = /usr/bin/perl 180 PERL_PATH = /usr/bin/perl
313endif 181endif
314 182
315export PERL_PATH 183export PERL_PATH
@@ -413,7 +281,7 @@ LIB_H += util/cpumap.h
413LIB_H += util/top.h 281LIB_H += util/top.h
414LIB_H += $(ARCH_INCLUDE) 282LIB_H += $(ARCH_INCLUDE)
415LIB_H += util/cgroup.h 283LIB_H += util/cgroup.h
416LIB_H += $(TRACE_EVENT_DIR)event-parse.h 284LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
417LIB_H += util/target.h 285LIB_H += util/target.h
418LIB_H += util/rblist.h 286LIB_H += util/rblist.h
419LIB_H += util/intlist.h 287LIB_H += util/intlist.h
@@ -492,6 +360,7 @@ LIB_OBJS += $(OUTPUT)util/rblist.o
492LIB_OBJS += $(OUTPUT)util/intlist.o 360LIB_OBJS += $(OUTPUT)util/intlist.o
493LIB_OBJS += $(OUTPUT)util/vdso.o 361LIB_OBJS += $(OUTPUT)util/vdso.o
494LIB_OBJS += $(OUTPUT)util/stat.o 362LIB_OBJS += $(OUTPUT)util/stat.o
363LIB_OBJS += $(OUTPUT)util/record.o
495 364
496LIB_OBJS += $(OUTPUT)ui/setup.o 365LIB_OBJS += $(OUTPUT)ui/setup.o
497LIB_OBJS += $(OUTPUT)ui/helpline.o 366LIB_OBJS += $(OUTPUT)ui/helpline.o
@@ -521,6 +390,12 @@ LIB_OBJS += $(OUTPUT)tests/bp_signal.o
521LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o 390LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
522LIB_OBJS += $(OUTPUT)tests/task-exit.o 391LIB_OBJS += $(OUTPUT)tests/task-exit.o
523LIB_OBJS += $(OUTPUT)tests/sw-clock.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
524 399
525BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 400BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
526BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 401BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -557,79 +432,14 @@ BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
557 432
558PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT) 433PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
559 434
560#
561# Platform specific tweaks
562#
563ifneq ($(MAKECMDGOALS),clean)
564ifneq ($(MAKECMDGOALS),tags)
565
566# We choose to avoid "if .. else if .. else .. endif endif" 435# We choose to avoid "if .. else if .. else .. endif endif"
567# because maintaining the nesting to match is a pain. If 436# because maintaining the nesting to match is a pain. If
568# we had "elif" things would have been much nicer... 437# we had "elif" things would have been much nicer...
569 438
570ifdef NO_LIBELF
571 NO_DWARF := 1
572 NO_DEMANGLE := 1
573 NO_LIBUNWIND := 1
574else
575FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
576ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
577 FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
578 ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
579 LIBC_SUPPORT := 1
580 endif
581 ifeq ($(BIONIC),1)
582 LIBC_SUPPORT := 1
583 endif
584 ifeq ($(LIBC_SUPPORT),1)
585 msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
586
587 NO_LIBELF := 1
588 NO_DWARF := 1
589 NO_DEMANGLE := 1
590 else
591 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
592 endif
593else
594 # for linking with debug library, run like:
595 # make DEBUG=1 LIBDW_DIR=/opt/libdw/
596 ifdef LIBDW_DIR
597 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
598 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
599 endif
600
601 FLAGS_DWARF=$(ALL_CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
602 ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
603 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);
604 NO_DWARF := 1
605 endif # Dwarf support
606endif # SOURCE_LIBELF
607endif # NO_LIBELF
608
609# There's only x86 (both 32 and 64) support for CFI unwind so far
610ifneq ($(ARCH),x86)
611 NO_LIBUNWIND := 1
612endif
613
614ifndef NO_LIBUNWIND
615# for linking with debug library, run like:
616# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
617ifdef LIBUNWIND_DIR
618 LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
619 LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
620endif
621
622FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
623ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
624 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
625 NO_LIBUNWIND := 1
626endif # Libunwind support
627endif # NO_LIBUNWIND
628
629-include arch/$(ARCH)/Makefile 439-include arch/$(ARCH)/Makefile
630 440
631ifneq ($(OUTPUT),) 441ifneq ($(OUTPUT),)
632 BASIC_CFLAGS += -I$(OUTPUT) 442 CFLAGS += -I$(OUTPUT)
633endif 443endif
634 444
635ifdef NO_LIBELF 445ifdef NO_LIBELF
@@ -647,281 +457,75 @@ BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
647LIB_OBJS += $(OUTPUT)util/symbol-minimal.o 457LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
648 458
649else # NO_LIBELF 459else # NO_LIBELF
650BASIC_CFLAGS += -DLIBELF_SUPPORT
651
652FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
653ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
654 BASIC_CFLAGS += -DLIBELF_MMAP
655endif
656
657ifndef NO_DWARF 460ifndef NO_DWARF
658ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) 461 LIB_OBJS += $(OUTPUT)util/probe-finder.o
659 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); 462 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
660else
661 BASIC_CFLAGS := -DDWARF_SUPPORT $(LIBDW_CFLAGS) $(BASIC_CFLAGS)
662 BASIC_LDFLAGS := $(LIBDW_LDFLAGS) $(BASIC_LDFLAGS)
663 EXTLIBS += -lelf -ldw
664 LIB_OBJS += $(OUTPUT)util/probe-finder.o
665 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
666endif # PERF_HAVE_DWARF_REGS
667endif # NO_DWARF 463endif # NO_DWARF
668endif # NO_LIBELF 464endif # NO_LIBELF
669 465
670ifndef NO_LIBUNWIND 466ifndef NO_LIBUNWIND
671 BASIC_CFLAGS += -DLIBUNWIND_SUPPORT 467 LIB_OBJS += $(OUTPUT)util/unwind.o
672 EXTLIBS += $(LIBUNWIND_LIBS)
673 BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS)
674 BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS)
675 LIB_OBJS += $(OUTPUT)util/unwind.o
676endif 468endif
469LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
677 470
678ifndef NO_LIBAUDIT 471ifndef NO_LIBAUDIT
679 FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit 472 BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
680 ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
681 msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
682 else
683 BASIC_CFLAGS += -DLIBAUDIT_SUPPORT
684 BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
685 EXTLIBS += -laudit
686 endif
687endif 473endif
688 474
689ifndef NO_SLANG 475ifndef NO_SLANG
690 FLAGS_SLANG=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang 476 LIB_OBJS += $(OUTPUT)ui/browser.o
691 ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y) 477 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
692 msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev); 478 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
693 else 479 LIB_OBJS += $(OUTPUT)ui/browsers/map.o
694 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h 480 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
695 BASIC_CFLAGS += -I/usr/include/slang 481 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
696 BASIC_CFLAGS += -DSLANG_SUPPORT 482 LIB_OBJS += $(OUTPUT)ui/tui/util.o
697 EXTLIBS += -lslang 483 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
698 LIB_OBJS += $(OUTPUT)ui/browser.o 484 LIB_OBJS += $(OUTPUT)ui/tui/progress.o
699 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o 485 LIB_H += ui/browser.h
700 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o 486 LIB_H += ui/browsers/map.h
701 LIB_OBJS += $(OUTPUT)ui/browsers/map.o 487 LIB_H += ui/keysyms.h
702 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o 488 LIB_H += ui/libslang.h
703 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
704 LIB_OBJS += $(OUTPUT)ui/tui/util.o
705 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
706 LIB_OBJS += $(OUTPUT)ui/tui/progress.o
707 LIB_H += ui/browser.h
708 LIB_H += ui/browsers/map.h
709 LIB_H += ui/keysyms.h
710 LIB_H += ui/libslang.h
711 endif
712endif 489endif
713 490
714ifndef NO_GTK2 491ifndef NO_GTK2
715 FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) 492 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
716 ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y) 493 LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
717 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); 494 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
718 else 495 LIB_OBJS += $(OUTPUT)ui/gtk/util.o
719 ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y) 496 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
720 BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR 497 LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
721 endif 498 LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
722 BASIC_CFLAGS += -DGTK2_SUPPORT
723 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
724 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
725 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
726 LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
727 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
728 LIB_OBJS += $(OUTPUT)ui/gtk/util.o
729 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
730 LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
731 LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
732 endif
733endif
734
735ifdef NO_LIBPERL
736 BASIC_CFLAGS += -DNO_LIBPERL
737else
738 PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
739 PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
740 PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
741 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
742 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
743
744 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y)
745 BASIC_CFLAGS += -DNO_LIBPERL
746 else
747 ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS)
748 EXTLIBS += $(PERL_EMBED_LIBADD)
749 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
750 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
751 endif
752endif 499endif
753 500
754disable-python = $(eval $(disable-python_code)) 501ifndef NO_LIBPERL
755define disable-python_code 502 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
756 BASIC_CFLAGS += -DNO_LIBPYTHON 503 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
757 $(if $(1),$(warning No $(1) was found))
758 $(warning Python support will not be built)
759endef
760
761override PYTHON := \
762 $(call get-executable-or-default,PYTHON,python)
763
764ifndef PYTHON
765 $(call disable-python,python interpreter)
766else
767
768 PYTHON_WORD := $(call shell-wordify,$(PYTHON))
769
770 ifdef NO_LIBPYTHON
771 $(call disable-python)
772 else
773
774 override PYTHON_CONFIG := \
775 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
776
777 ifndef PYTHON_CONFIG
778 $(call disable-python,python-config tool)
779 else
780
781 PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
782
783 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
784 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
785 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
786 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
787 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
788
789 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y)
790 $(call disable-python,Python.h (for Python 2.x))
791 else
792
793 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y)
794 $(warning Python 3 is not yet supported; please set)
795 $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
796 $(warning If you also have Python 2 installed, then)
797 $(warning try something like:)
798 $(warning $(and ,))
799 $(warning $(and ,) make PYTHON=python2)
800 $(warning $(and ,))
801 $(warning Otherwise, disable Python support entirely:)
802 $(warning $(and ,))
803 $(warning $(and ,) make NO_LIBPYTHON=1)
804 $(warning $(and ,))
805 $(error $(and ,))
806 else
807 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
808 EXTLIBS += $(PYTHON_EMBED_LIBADD)
809 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
810 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
811 LANG_BINDINGS += $(OUTPUT)python/perf.so
812 endif
813
814 endif
815 endif
816 endif
817endif 504endif
818 505
819ifdef NO_DEMANGLE 506ifndef NO_LIBPYTHON
820 BASIC_CFLAGS += -DNO_DEMANGLE 507 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
821else 508 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
822 ifdef HAVE_CPLUS_DEMANGLE
823 EXTLIBS += -liberty
824 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
825 else
826 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
827 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd)
828 ifeq ($(has_bfd),y)
829 EXTLIBS += -lbfd
830 else
831 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
832 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
833 ifeq ($(has_bfd_iberty),y)
834 EXTLIBS += -lbfd -liberty
835 else
836 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
837 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz)
838 ifeq ($(has_bfd_iberty_z),y)
839 EXTLIBS += -lbfd -liberty -lz
840 else
841 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
842 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle)
843 ifeq ($(has_cplus_demangle),y)
844 EXTLIBS += -liberty
845 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
846 else
847 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
848 BASIC_CFLAGS += -DNO_DEMANGLE
849 endif
850 endif
851 endif
852 endif
853 endif
854endif 509endif
855 510
856ifeq ($(NO_PERF_REGS),0) 511ifeq ($(NO_PERF_REGS),0)
857 ifeq ($(ARCH),x86) 512 ifeq ($(ARCH),x86)
858 LIB_H += arch/x86/include/perf_regs.h 513 LIB_H += arch/x86/include/perf_regs.h
859 endif 514 endif
860 BASIC_CFLAGS += -DHAVE_PERF_REGS
861endif
862
863ifndef NO_STRLCPY
864 ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y)
865 BASIC_CFLAGS += -DHAVE_STRLCPY
866 endif
867endif
868
869ifndef NO_ON_EXIT
870 ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y)
871 BASIC_CFLAGS += -DHAVE_ON_EXIT
872 endif
873endif
874
875ifndef NO_BACKTRACE
876 ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y)
877 BASIC_CFLAGS += -DBACKTRACE_SUPPORT
878 endif
879endif 515endif
880 516
881ifndef NO_LIBNUMA 517ifndef NO_LIBNUMA
882 FLAGS_LIBNUMA = $(ALL_CFLAGS) $(ALL_LDFLAGS) -lnuma 518 BUILTIN_OBJS += $(OUTPUT)bench/numa.o
883 ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y)
884 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev);
885 else
886 BASIC_CFLAGS += -DLIBNUMA_SUPPORT
887 BUILTIN_OBJS += $(OUTPUT)bench/numa.o
888 EXTLIBS += -lnuma
889 endif
890endif 519endif
891 520
892ifdef ASCIIDOC8 521ifdef ASCIIDOC8
893 export ASCIIDOC8 522 export ASCIIDOC8
894endif 523endif
895 524
896endif # MAKECMDGOALS != tags
897endif # MAKECMDGOALS != clean
898
899# Shell quote (do not use $(call) to accommodate ancient setups);
900
901ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
902
903DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
904bindir_SQ = $(subst ','\'',$(bindir))
905bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
906mandir_SQ = $(subst ','\'',$(mandir))
907infodir_SQ = $(subst ','\'',$(infodir))
908perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
909template_dir_SQ = $(subst ','\'',$(template_dir))
910htmldir_SQ = $(subst ','\'',$(htmldir))
911prefix_SQ = $(subst ','\'',$(prefix))
912sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
913
914SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
915
916LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group 525LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
917 526
918ALL_CFLAGS += $(BASIC_CFLAGS)
919ALL_CFLAGS += $(ARCH_CFLAGS)
920ALL_LDFLAGS += $(BASIC_LDFLAGS)
921
922export INSTALL SHELL_PATH 527export INSTALL SHELL_PATH
923 528
924
925### Build rules 529### Build rules
926 530
927SHELL = $(SHELL_PATH) 531SHELL = $(SHELL_PATH)
@@ -939,20 +543,20 @@ strip: $(PROGRAMS) $(OUTPUT)perf
939$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 543$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
940 $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \ 544 $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
941 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 545 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
942 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ 546 $(CFLAGS) -c $(filter %.c,$^) -o $@
943 547
944$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) 548$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
945 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \ 549 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \
946 $(BUILTIN_OBJS) $(LIBS) -o $@ 550 $(BUILTIN_OBJS) $(LIBS) -o $@
947 551
948$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 552$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
949 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 553 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
950 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 554 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
951 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 555 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
952 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 556 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
953 557
954$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 558$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
955 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 559 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
956 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 560 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
957 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 561 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
958 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 562 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
@@ -977,77 +581,77 @@ $(OUTPUT)perf.o perf.spec \
977# over the general rule for .o 581# over the general rule for .o
978 582
979$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS 583$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
980 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -w $< 584 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $<
981 585
982$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS 586$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
983 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $< 587 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
984 588
985$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 589$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
986 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 590 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
987$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS 591$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
988 $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $< 592 $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
989$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS 593$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
990 $(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $< 594 $(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $<
991$(OUTPUT)%.o: %.S 595$(OUTPUT)%.o: %.S
992 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 596 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
993$(OUTPUT)%.s: %.S 597$(OUTPUT)%.s: %.S
994 $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $< 598 $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
995 599
996$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS 600$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
997 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 601 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
998 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ 602 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
999 '-DPREFIX="$(prefix_SQ)"' \ 603 '-DPREFIX="$(prefix_SQ)"' \
1000 $< 604 $<
1001 605
1002$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS 606$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
1003 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 607 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
1004 '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \ 608 '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
1005 $< 609 $<
1006 610
1007$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS 611$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
1008 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 612 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
1009 -DPYTHONPATH='"$(OUTPUT)python"' \ 613 -DPYTHONPATH='"$(OUTPUT)python"' \
1010 -DPYTHON='"$(PYTHON_WORD)"' \ 614 -DPYTHON='"$(PYTHON_WORD)"' \
1011 $< 615 $<
1012 616
1013$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 617$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
1014 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 618 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
1015 619
1016$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS 620$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
1017 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 621 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
1018 622
1019$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 623$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
1020 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 624 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
1021 625
1022$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 626$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
1023 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 627 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
1024 628
1025$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS 629$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
1026 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 630 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
1027 631
1028$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS 632$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
1029 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 633 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
1030 634
1031$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS 635$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
1032 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 636 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
1033 637
1034$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS 638$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
1035 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $< 639 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
1036 640
1037$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS 641$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
1038 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< 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 $<
1039 643
1040$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS 644$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
1041 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 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 $<
1042 646
1043$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS 647$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
1044 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< 648 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
1045 649
1046$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS 650$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
1047 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 651 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
1048 652
1049$(OUTPUT)perf-%: %.o $(PERFLIBS) 653$(OUTPUT)perf-%: %.o $(PERFLIBS)
1050 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 654 $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
1051 655
1052$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) 656$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
1053$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) 657$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
@@ -1134,7 +738,7 @@ cscope:
1134 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b 738 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b
1135 739
1136### Detect prefix changes 740### Detect prefix changes
1137TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ 741TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
1138 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) 742 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
1139 743
1140$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS 744$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
@@ -1155,7 +759,7 @@ check: $(OUTPUT)common-cmds.h
1155 then \ 759 then \
1156 for i in *.c */*.c; \ 760 for i in *.c */*.c; \
1157 do \ 761 do \
1158 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ 762 sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
1159 done; \ 763 done; \
1160 else \ 764 else \
1161 exit 1; \ 765 exit 1; \
@@ -1163,27 +767,24 @@ check: $(OUTPUT)common-cmds.h
1163 767
1164### Installation rules 768### Installation rules
1165 769
1166ifneq ($(filter /%,$(firstword $(perfexecdir))),)
1167perfexec_instdir = $(perfexecdir)
1168else
1169perfexec_instdir = $(prefix)/$(perfexecdir)
1170endif
1171perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
1172
1173install-bin: all 770install-bin: all
1174 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 771 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1175 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' 772 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
773 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
774ifndef NO_LIBPERL
1176 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 775 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1177 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 776 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1178 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1179 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 777 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1180 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl' 778 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
1181 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 779 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
780endif
781ifndef NO_LIBPYTHON
1182 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace' 782 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1183 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 783 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1184 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace' 784 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1185 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' 785 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1186 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 786 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
787endif
1187 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d' 788 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'
1188 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' 789 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
1189 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests' 790 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 815841c04eb2..8801fe02f206 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -6,3 +6,5 @@ ifndef NO_LIBUNWIND
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o 6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
7endif 7endif
8LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 8LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
9LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
10LIB_H += arch/$(ARCH)/util/tsc.h
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c
new file mode 100644
index 000000000000..b2519e49424f
--- /dev/null
+++ b/tools/perf/arch/x86/util/tsc.c
@@ -0,0 +1,59 @@
1#include <stdbool.h>
2#include <errno.h>
3
4#include <linux/perf_event.h>
5
6#include "../../perf.h"
7#include "../../util/types.h"
8#include "../../util/debug.h"
9#include "tsc.h"
10
11u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
12{
13 u64 t, quot, rem;
14
15 t = ns - tc->time_zero;
16 quot = t / tc->time_mult;
17 rem = t % tc->time_mult;
18 return (quot << tc->time_shift) +
19 (rem << tc->time_shift) / tc->time_mult;
20}
21
22u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
23{
24 u64 quot, rem;
25
26 quot = cyc >> tc->time_shift;
27 rem = cyc & ((1 << tc->time_shift) - 1);
28 return tc->time_zero + quot * tc->time_mult +
29 ((rem * tc->time_mult) >> tc->time_shift);
30}
31
32int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
33 struct perf_tsc_conversion *tc)
34{
35 bool cap_user_time_zero;
36 u32 seq;
37 int i = 0;
38
39 while (1) {
40 seq = pc->lock;
41 rmb();
42 tc->time_mult = pc->time_mult;
43 tc->time_shift = pc->time_shift;
44 tc->time_zero = pc->time_zero;
45 cap_user_time_zero = pc->cap_user_time_zero;
46 rmb();
47 if (pc->lock == seq && !(seq & 1))
48 break;
49 if (++i > 10000) {
50 pr_debug("failed to get perf_event_mmap_page lock\n");
51 return -EINVAL;
52 }
53 }
54
55 if (!cap_user_time_zero)
56 return -EOPNOTSUPP;
57
58 return 0;
59}
diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h
new file mode 100644
index 000000000000..a24dec81c795
--- /dev/null
+++ b/tools/perf/arch/x86/util/tsc.h
@@ -0,0 +1,20 @@
1#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
2#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
3
4#include "../../util/types.h"
5
6struct perf_tsc_conversion {
7 u16 time_shift;
8 u32 time_mult;
9 u64 time_zero;
10};
11
12struct perf_event_mmap_page;
13
14int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
15 struct perf_tsc_conversion *tc);
16
17u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
18u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
19
20#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index 93c83e3cb4a7..8cdca43016b2 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -111,12 +111,14 @@ static double timeval2double(struct timeval *ts)
111static void alloc_mem(void **dst, void **src, size_t length) 111static void alloc_mem(void **dst, void **src, size_t length)
112{ 112{
113 *dst = zalloc(length); 113 *dst = zalloc(length);
114 if (!dst) 114 if (!*dst)
115 die("memory allocation failed - maybe length is too large?\n"); 115 die("memory allocation failed - maybe length is too large?\n");
116 116
117 *src = zalloc(length); 117 *src = zalloc(length);
118 if (!src) 118 if (!*src)
119 die("memory allocation failed - maybe length is too large?\n"); 119 die("memory allocation failed - maybe length is too large?\n");
120 /* Make sure to always replace the zero pages even if MMAP_THRESH is crossed */
121 memset(*src, 0, length);
120} 122}
121 123
122static u64 do_memcpy_cycle(memcpy_t fn, size_t len, bool prefault) 124static u64 do_memcpy_cycle(memcpy_t fn, size_t len, bool prefault)
diff --git a/tools/perf/bench/mem-memset.c b/tools/perf/bench/mem-memset.c
index c6e4bc523492..4a2f12081964 100644
--- a/tools/perf/bench/mem-memset.c
+++ b/tools/perf/bench/mem-memset.c
@@ -111,7 +111,7 @@ static double timeval2double(struct timeval *ts)
111static void alloc_mem(void **dst, size_t length) 111static void alloc_mem(void **dst, size_t length)
112{ 112{
113 *dst = zalloc(length); 113 *dst = zalloc(length);
114 if (!dst) 114 if (!*dst)
115 die("memory allocation failed - maybe length is too large?\n"); 115 die("memory allocation failed - maybe length is too large?\n");
116} 116}
117 117
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index db491e9a812b..5ebd0c3b71b6 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -90,8 +90,7 @@ static int process_sample_event(struct perf_tool *tool,
90 struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool); 90 struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool);
91 struct addr_location al; 91 struct addr_location al;
92 92
93 if (perf_event__preprocess_sample(event, machine, &al, sample, 93 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
94 symbol__annotate_init) < 0) {
95 pr_warning("problem processing %d event, skipping it.\n", 94 pr_warning("problem processing %d event, skipping it.\n",
96 event->header.type); 95 event->header.type);
97 return -1; 96 return -1;
@@ -195,6 +194,8 @@ static int __cmd_annotate(struct perf_annotate *ann)
195 if (session == NULL) 194 if (session == NULL)
196 return -ENOMEM; 195 return -ENOMEM;
197 196
197 machines__set_symbol_filter(&session->machines, symbol__annotate_init);
198
198 if (ann->cpu_list) { 199 if (ann->cpu_list) {
199 ret = perf_session__cpu_bitmap(session, ann->cpu_list, 200 ret = perf_session__cpu_bitmap(session, ann->cpu_list,
200 ann->cpu_bitmap); 201 ann->cpu_bitmap);
@@ -276,6 +277,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
276 .tool = { 277 .tool = {
277 .sample = process_sample_event, 278 .sample = process_sample_event,
278 .mmap = perf_event__process_mmap, 279 .mmap = perf_event__process_mmap,
280 .mmap2 = perf_event__process_mmap2,
279 .comm = perf_event__process_comm, 281 .comm = perf_event__process_comm,
280 .exit = perf_event__process_exit, 282 .exit = perf_event__process_exit,
281 .fork = perf_event__process_fork, 283 .fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 2d0462d89a97..f28799e94f2a 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -18,15 +18,53 @@
18#include "util/util.h" 18#include "util/util.h"
19 19
20#include <stdlib.h> 20#include <stdlib.h>
21#include <math.h>
21 22
22static char const *input_old = "perf.data.old", 23/* Diff command specific HPP columns. */
23 *input_new = "perf.data"; 24enum {
24static char diff__default_sort_order[] = "dso,symbol"; 25 PERF_HPP_DIFF__BASELINE,
25static bool force; 26 PERF_HPP_DIFF__PERIOD,
27 PERF_HPP_DIFF__PERIOD_BASELINE,
28 PERF_HPP_DIFF__DELTA,
29 PERF_HPP_DIFF__RATIO,
30 PERF_HPP_DIFF__WEIGHTED_DIFF,
31 PERF_HPP_DIFF__FORMULA,
32
33 PERF_HPP_DIFF__MAX_INDEX
34};
35
36struct diff_hpp_fmt {
37 struct perf_hpp_fmt fmt;
38 int idx;
39 char *header;
40 int header_width;
41};
42
43struct data__file {
44 struct perf_session *session;
45 const char *file;
46 int idx;
47 struct hists *hists;
48 struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
49};
50
51static struct data__file *data__files;
52static int data__files_cnt;
53
54#define data__for_each_file_start(i, d, s) \
55 for (i = s, d = &data__files[s]; \
56 i < data__files_cnt; \
57 i++, d = &data__files[i])
58
59#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
60#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
61
62static char diff__default_sort_order[] = "dso,symbol";
63static bool force;
26static bool show_period; 64static bool show_period;
27static bool show_formula; 65static bool show_formula;
28static bool show_baseline_only; 66static bool show_baseline_only;
29static bool sort_compute; 67static unsigned int sort_compute;
30 68
31static s64 compute_wdiff_w1; 69static s64 compute_wdiff_w1;
32static s64 compute_wdiff_w2; 70static s64 compute_wdiff_w2;
@@ -46,6 +84,47 @@ const char *compute_names[COMPUTE_MAX] = {
46 84
47static int compute; 85static int compute;
48 86
87static int compute_2_hpp[COMPUTE_MAX] = {
88 [COMPUTE_DELTA] = PERF_HPP_DIFF__DELTA,
89 [COMPUTE_RATIO] = PERF_HPP_DIFF__RATIO,
90 [COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF,
91};
92
93#define MAX_COL_WIDTH 70
94
95static struct header_column {
96 const char *name;
97 int width;
98} columns[PERF_HPP_DIFF__MAX_INDEX] = {
99 [PERF_HPP_DIFF__BASELINE] = {
100 .name = "Baseline",
101 },
102 [PERF_HPP_DIFF__PERIOD] = {
103 .name = "Period",
104 .width = 14,
105 },
106 [PERF_HPP_DIFF__PERIOD_BASELINE] = {
107 .name = "Base period",
108 .width = 14,
109 },
110 [PERF_HPP_DIFF__DELTA] = {
111 .name = "Delta",
112 .width = 7,
113 },
114 [PERF_HPP_DIFF__RATIO] = {
115 .name = "Ratio",
116 .width = 14,
117 },
118 [PERF_HPP_DIFF__WEIGHTED_DIFF] = {
119 .name = "Weighted diff",
120 .width = 14,
121 },
122 [PERF_HPP_DIFF__FORMULA] = {
123 .name = "Formula",
124 .width = MAX_COL_WIDTH,
125 }
126};
127
49static int setup_compute_opt_wdiff(char *opt) 128static int setup_compute_opt_wdiff(char *opt)
50{ 129{
51 char *w1_str = opt; 130 char *w1_str = opt;
@@ -109,13 +188,6 @@ static int setup_compute(const struct option *opt, const char *str,
109 return 0; 188 return 0;
110 } 189 }
111 190
112 if (*str == '+') {
113 sort_compute = true;
114 cstr = (char *) ++str;
115 if (!*str)
116 return 0;
117 }
118
119 option = strchr(str, ':'); 191 option = strchr(str, ':');
120 if (option) { 192 if (option) {
121 unsigned len = option++ - str; 193 unsigned len = option++ - str;
@@ -145,42 +217,42 @@ static int setup_compute(const struct option *opt, const char *str,
145 return -EINVAL; 217 return -EINVAL;
146} 218}
147 219
148double perf_diff__period_percent(struct hist_entry *he, u64 period) 220static double period_percent(struct hist_entry *he, u64 period)
149{ 221{
150 u64 total = he->hists->stats.total_period; 222 u64 total = he->hists->stats.total_period;
151 return (period * 100.0) / total; 223 return (period * 100.0) / total;
152} 224}
153 225
154double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair) 226static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
155{ 227{
156 double new_percent = perf_diff__period_percent(he, he->stat.period); 228 double old_percent = period_percent(he, he->stat.period);
157 double old_percent = perf_diff__period_percent(pair, pair->stat.period); 229 double new_percent = period_percent(pair, pair->stat.period);
158 230
159 he->diff.period_ratio_delta = new_percent - old_percent; 231 pair->diff.period_ratio_delta = new_percent - old_percent;
160 he->diff.computed = true; 232 pair->diff.computed = true;
161 return he->diff.period_ratio_delta; 233 return pair->diff.period_ratio_delta;
162} 234}
163 235
164double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair) 236static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
165{ 237{
166 double new_period = he->stat.period; 238 double old_period = he->stat.period ?: 1;
167 double old_period = pair->stat.period; 239 double new_period = pair->stat.period;
168 240
169 he->diff.computed = true; 241 pair->diff.computed = true;
170 he->diff.period_ratio = new_period / old_period; 242 pair->diff.period_ratio = new_period / old_period;
171 return he->diff.period_ratio; 243 return pair->diff.period_ratio;
172} 244}
173 245
174s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair) 246static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
175{ 247{
176 u64 new_period = he->stat.period; 248 u64 old_period = he->stat.period;
177 u64 old_period = pair->stat.period; 249 u64 new_period = pair->stat.period;
178 250
179 he->diff.computed = true; 251 pair->diff.computed = true;
180 he->diff.wdiff = new_period * compute_wdiff_w2 - 252 pair->diff.wdiff = new_period * compute_wdiff_w2 -
181 old_period * compute_wdiff_w1; 253 old_period * compute_wdiff_w1;
182 254
183 return he->diff.wdiff; 255 return pair->diff.wdiff;
184} 256}
185 257
186static int formula_delta(struct hist_entry *he, struct hist_entry *pair, 258static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
@@ -189,15 +261,15 @@ static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
189 return scnprintf(buf, size, 261 return scnprintf(buf, size,
190 "(%" PRIu64 " * 100 / %" PRIu64 ") - " 262 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
191 "(%" PRIu64 " * 100 / %" PRIu64 ")", 263 "(%" PRIu64 " * 100 / %" PRIu64 ")",
192 he->stat.period, he->hists->stats.total_period, 264 pair->stat.period, pair->hists->stats.total_period,
193 pair->stat.period, pair->hists->stats.total_period); 265 he->stat.period, he->hists->stats.total_period);
194} 266}
195 267
196static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, 268static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
197 char *buf, size_t size) 269 char *buf, size_t size)
198{ 270{
199 double new_period = he->stat.period; 271 double old_period = he->stat.period;
200 double old_period = pair->stat.period; 272 double new_period = pair->stat.period;
201 273
202 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); 274 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
203} 275}
@@ -205,16 +277,16 @@ static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
205static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair, 277static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
206 char *buf, size_t size) 278 char *buf, size_t size)
207{ 279{
208 u64 new_period = he->stat.period; 280 u64 old_period = he->stat.period;
209 u64 old_period = pair->stat.period; 281 u64 new_period = pair->stat.period;
210 282
211 return scnprintf(buf, size, 283 return scnprintf(buf, size,
212 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", 284 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
213 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); 285 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
214} 286}
215 287
216int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, 288static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
217 char *buf, size_t size) 289 char *buf, size_t size)
218{ 290{
219 switch (compute) { 291 switch (compute) {
220 case COMPUTE_DELTA: 292 case COMPUTE_DELTA:
@@ -247,7 +319,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
247{ 319{
248 struct addr_location al; 320 struct addr_location al;
249 321
250 if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { 322 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
251 pr_warning("problem processing %d event, skipping it.\n", 323 pr_warning("problem processing %d event, skipping it.\n",
252 event->header.type); 324 event->header.type);
253 return -1; 325 return -1;
@@ -299,6 +371,29 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
299 } 371 }
300} 372}
301 373
374static struct hist_entry*
375get_pair_data(struct hist_entry *he, struct data__file *d)
376{
377 if (hist_entry__has_pairs(he)) {
378 struct hist_entry *pair;
379
380 list_for_each_entry(pair, &he->pairs.head, pairs.node)
381 if (pair->hists == d->hists)
382 return pair;
383 }
384
385 return NULL;
386}
387
388static struct hist_entry*
389get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
390{
391 void *ptr = dfmt - dfmt->idx;
392 struct data__file *d = container_of(ptr, struct data__file, fmt);
393
394 return get_pair_data(he, d);
395}
396
302static void hists__baseline_only(struct hists *hists) 397static void hists__baseline_only(struct hists *hists)
303{ 398{
304 struct rb_root *root; 399 struct rb_root *root;
@@ -323,25 +418,34 @@ static void hists__baseline_only(struct hists *hists)
323 418
324static void hists__precompute(struct hists *hists) 419static void hists__precompute(struct hists *hists)
325{ 420{
326 struct rb_node *next = rb_first(&hists->entries); 421 struct rb_root *root;
422 struct rb_node *next;
327 423
424 if (sort__need_collapse)
425 root = &hists->entries_collapsed;
426 else
427 root = hists->entries_in;
428
429 next = rb_first(root);
328 while (next != NULL) { 430 while (next != NULL) {
329 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 431 struct hist_entry *he, *pair;
330 struct hist_entry *pair = hist_entry__next_pair(he); 432
433 he = rb_entry(next, struct hist_entry, rb_node_in);
434 next = rb_next(&he->rb_node_in);
331 435
332 next = rb_next(&he->rb_node); 436 pair = get_pair_data(he, &data__files[sort_compute]);
333 if (!pair) 437 if (!pair)
334 continue; 438 continue;
335 439
336 switch (compute) { 440 switch (compute) {
337 case COMPUTE_DELTA: 441 case COMPUTE_DELTA:
338 perf_diff__compute_delta(he, pair); 442 compute_delta(he, pair);
339 break; 443 break;
340 case COMPUTE_RATIO: 444 case COMPUTE_RATIO:
341 perf_diff__compute_ratio(he, pair); 445 compute_ratio(he, pair);
342 break; 446 break;
343 case COMPUTE_WEIGHTED_DIFF: 447 case COMPUTE_WEIGHTED_DIFF:
344 perf_diff__compute_wdiff(he, pair); 448 compute_wdiff(he, pair);
345 break; 449 break;
346 default: 450 default:
347 BUG_ON(1); 451 BUG_ON(1);
@@ -360,7 +464,7 @@ static int64_t cmp_doubles(double l, double r)
360} 464}
361 465
362static int64_t 466static int64_t
363hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, 467__hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
364 int c) 468 int c)
365{ 469{
366 switch (c) { 470 switch (c) {
@@ -392,6 +496,36 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
392 return 0; 496 return 0;
393} 497}
394 498
499static int64_t
500hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
501 int c)
502{
503 bool pairs_left = hist_entry__has_pairs(left);
504 bool pairs_right = hist_entry__has_pairs(right);
505 struct hist_entry *p_right, *p_left;
506
507 if (!pairs_left && !pairs_right)
508 return 0;
509
510 if (!pairs_left || !pairs_right)
511 return pairs_left ? -1 : 1;
512
513 p_left = get_pair_data(left, &data__files[sort_compute]);
514 p_right = get_pair_data(right, &data__files[sort_compute]);
515
516 if (!p_left && !p_right)
517 return 0;
518
519 if (!p_left || !p_right)
520 return p_left ? -1 : 1;
521
522 /*
523 * We have 2 entries of same kind, let's
524 * make the data comparison.
525 */
526 return __hist_entry__cmp_compute(p_left, p_right, c);
527}
528
395static void insert_hist_entry_by_compute(struct rb_root *root, 529static void insert_hist_entry_by_compute(struct rb_root *root,
396 struct hist_entry *he, 530 struct hist_entry *he,
397 int c) 531 int c)
@@ -441,75 +575,121 @@ static void hists__compute_resort(struct hists *hists)
441 } 575 }
442} 576}
443 577
444static void hists__process(struct hists *old, struct hists *new) 578static void hists__process(struct hists *hists)
445{ 579{
446 hists__match(new, old);
447
448 if (show_baseline_only) 580 if (show_baseline_only)
449 hists__baseline_only(new); 581 hists__baseline_only(hists);
450 else
451 hists__link(new, old);
452 582
453 if (sort_compute) { 583 if (sort_compute) {
454 hists__precompute(new); 584 hists__precompute(hists);
455 hists__compute_resort(new); 585 hists__compute_resort(hists);
456 } else { 586 } else {
457 hists__output_resort(new); 587 hists__output_resort(hists);
458 } 588 }
459 589
460 hists__fprintf(new, true, 0, 0, stdout); 590 hists__fprintf(hists, true, 0, 0, 0, stdout);
461} 591}
462 592
463static int __cmd_diff(void) 593static void data__fprintf(void)
464{ 594{
465 int ret, i; 595 struct data__file *d;
466#define older (session[0]) 596 int i;
467#define newer (session[1]) 597
468 struct perf_session *session[2]; 598 fprintf(stdout, "# Data files:\n");
469 struct perf_evlist *evlist_new, *evlist_old; 599
470 struct perf_evsel *evsel; 600 data__for_each_file(i, d)
601 fprintf(stdout, "# [%d] %s %s\n",
602 d->idx, d->file,
603 !d->idx ? "(Baseline)" : "");
604
605 fprintf(stdout, "#\n");
606}
607
608static void data_process(void)
609{
610 struct perf_evlist *evlist_base = data__files[0].session->evlist;
611 struct perf_evsel *evsel_base;
471 bool first = true; 612 bool first = true;
472 613
473 older = perf_session__new(input_old, O_RDONLY, force, false, 614 list_for_each_entry(evsel_base, &evlist_base->entries, node) {
474 &tool); 615 struct data__file *d;
475 newer = perf_session__new(input_new, O_RDONLY, force, false, 616 int i;
476 &tool);
477 if (session[0] == NULL || session[1] == NULL)
478 return -ENOMEM;
479 617
480 for (i = 0; i < 2; ++i) { 618 data__for_each_file_new(i, d) {
481 ret = perf_session__process_events(session[i], &tool); 619 struct perf_evlist *evlist = d->session->evlist;
482 if (ret) 620 struct perf_evsel *evsel;
483 goto out_delete;
484 }
485 621
486 evlist_old = older->evlist; 622 evsel = evsel_match(evsel_base, evlist);
487 evlist_new = newer->evlist; 623 if (!evsel)
624 continue;
488 625
489 perf_evlist__collapse_resort(evlist_old); 626 d->hists = &evsel->hists;
490 perf_evlist__collapse_resort(evlist_new);
491 627
492 list_for_each_entry(evsel, &evlist_new->entries, node) { 628 hists__match(&evsel_base->hists, &evsel->hists);
493 struct perf_evsel *evsel_old;
494 629
495 evsel_old = evsel_match(evsel, evlist_old); 630 if (!show_baseline_only)
496 if (!evsel_old) 631 hists__link(&evsel_base->hists,
497 continue; 632 &evsel->hists);
633 }
498 634
499 fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n", 635 fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
500 perf_evsel__name(evsel)); 636 perf_evsel__name(evsel_base));
501 637
502 first = false; 638 first = false;
503 639
504 hists__process(&evsel_old->hists, &evsel->hists); 640 if (verbose || data__files_cnt > 2)
641 data__fprintf();
642
643 hists__process(&evsel_base->hists);
505 } 644 }
645}
646
647static void data__free(struct data__file *d)
648{
649 int col;
650
651 for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
652 struct diff_hpp_fmt *fmt = &d->fmt[col];
506 653
507out_delete: 654 free(fmt->header);
508 for (i = 0; i < 2; ++i) 655 }
509 perf_session__delete(session[i]); 656}
657
658static int __cmd_diff(void)
659{
660 struct data__file *d;
661 int ret = -EINVAL, i;
662
663 data__for_each_file(i, d) {
664 d->session = perf_session__new(d->file, O_RDONLY, force,
665 false, &tool);
666 if (!d->session) {
667 pr_err("Failed to open %s\n", d->file);
668 ret = -ENOMEM;
669 goto out_delete;
670 }
671
672 ret = perf_session__process_events(d->session, &tool);
673 if (ret) {
674 pr_err("Failed to process %s\n", d->file);
675 goto out_delete;
676 }
677
678 perf_evlist__collapse_resort(d->session->evlist);
679 }
680
681 data_process();
682
683 out_delete:
684 data__for_each_file(i, d) {
685 if (d->session)
686 perf_session__delete(d->session);
687
688 data__free(d);
689 }
690
691 free(data__files);
510 return ret; 692 return ret;
511#undef older
512#undef newer
513} 693}
514 694
515static const char * const diff_usage[] = { 695static const char * const diff_usage[] = {
@@ -548,62 +728,310 @@ static const struct option options[] = {
548 "columns '.' is reserved."), 728 "columns '.' is reserved."),
549 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 729 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
550 "Look for files with symbols relative to this directory"), 730 "Look for files with symbols relative to this directory"),
731 OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
551 OPT_END() 732 OPT_END()
552}; 733};
553 734
554static void ui_init(void) 735static double baseline_percent(struct hist_entry *he)
555{ 736{
556 /* 737 struct hists *hists = he->hists;
557 * Display baseline/delta/ratio 738 return 100.0 * he->stat.period / hists->stats.total_period;
558 * formula/periods columns. 739}
559 */
560 perf_hpp__column_enable(PERF_HPP__BASELINE);
561 740
562 switch (compute) { 741static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
563 case COMPUTE_DELTA: 742 struct perf_hpp *hpp, struct hist_entry *he)
564 perf_hpp__column_enable(PERF_HPP__DELTA); 743{
744 struct diff_hpp_fmt *dfmt =
745 container_of(fmt, struct diff_hpp_fmt, fmt);
746 double percent = baseline_percent(he);
747 char pfmt[20] = " ";
748
749 if (!he->dummy) {
750 scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
751 return percent_color_snprintf(hpp->buf, hpp->size,
752 pfmt, percent);
753 } else
754 return scnprintf(hpp->buf, hpp->size, "%*s",
755 dfmt->header_width, pfmt);
756}
757
758static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
759{
760 double percent = baseline_percent(he);
761 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
762 int ret = 0;
763
764 if (!he->dummy)
765 ret = scnprintf(buf, size, fmt, percent);
766
767 return ret;
768}
769
770static void
771hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
772{
773 switch (idx) {
774 case PERF_HPP_DIFF__PERIOD_BASELINE:
775 scnprintf(buf, size, "%" PRIu64, he->stat.period);
565 break; 776 break;
566 case COMPUTE_RATIO: 777
567 perf_hpp__column_enable(PERF_HPP__RATIO); 778 default:
568 break; 779 break;
569 case COMPUTE_WEIGHTED_DIFF: 780 }
570 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF); 781}
782
783static void
784hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
785 int idx, char *buf, size_t size)
786{
787 double diff;
788 double ratio;
789 s64 wdiff;
790
791 switch (idx) {
792 case PERF_HPP_DIFF__DELTA:
793 if (pair->diff.computed)
794 diff = pair->diff.period_ratio_delta;
795 else
796 diff = compute_delta(he, pair);
797
798 if (fabs(diff) >= 0.01)
799 scnprintf(buf, size, "%+4.2F%%", diff);
800 break;
801
802 case PERF_HPP_DIFF__RATIO:
803 /* No point for ratio number if we are dummy.. */
804 if (he->dummy)
805 break;
806
807 if (pair->diff.computed)
808 ratio = pair->diff.period_ratio;
809 else
810 ratio = compute_ratio(he, pair);
811
812 if (ratio > 0.0)
813 scnprintf(buf, size, "%14.6F", ratio);
571 break; 814 break;
815
816 case PERF_HPP_DIFF__WEIGHTED_DIFF:
817 /* No point for wdiff number if we are dummy.. */
818 if (he->dummy)
819 break;
820
821 if (pair->diff.computed)
822 wdiff = pair->diff.wdiff;
823 else
824 wdiff = compute_wdiff(he, pair);
825
826 if (wdiff != 0)
827 scnprintf(buf, size, "%14ld", wdiff);
828 break;
829
830 case PERF_HPP_DIFF__FORMULA:
831 formula_fprintf(he, pair, buf, size);
832 break;
833
834 case PERF_HPP_DIFF__PERIOD:
835 scnprintf(buf, size, "%" PRIu64, pair->stat.period);
836 break;
837
572 default: 838 default:
573 BUG_ON(1); 839 BUG_ON(1);
574 }; 840 };
841}
575 842
576 if (show_formula) 843static void
577 perf_hpp__column_enable(PERF_HPP__FORMULA); 844__hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
845 char *buf, size_t size)
846{
847 struct hist_entry *pair = get_pair_fmt(he, dfmt);
848 int idx = dfmt->idx;
849
850 /* baseline is special */
851 if (idx == PERF_HPP_DIFF__BASELINE)
852 hpp__entry_baseline(he, buf, size);
853 else {
854 if (pair)
855 hpp__entry_pair(he, pair, idx, buf, size);
856 else
857 hpp__entry_unpair(he, idx, buf, size);
858 }
859}
860
861static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
862 struct hist_entry *he)
863{
864 struct diff_hpp_fmt *dfmt =
865 container_of(_fmt, struct diff_hpp_fmt, fmt);
866 char buf[MAX_COL_WIDTH] = " ";
867
868 __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
578 869
579 if (show_period) { 870 if (symbol_conf.field_sep)
580 perf_hpp__column_enable(PERF_HPP__PERIOD); 871 return scnprintf(hpp->buf, hpp->size, "%s", buf);
581 perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE); 872 else
873 return scnprintf(hpp->buf, hpp->size, "%*s",
874 dfmt->header_width, buf);
875}
876
877static int hpp__header(struct perf_hpp_fmt *fmt,
878 struct perf_hpp *hpp)
879{
880 struct diff_hpp_fmt *dfmt =
881 container_of(fmt, struct diff_hpp_fmt, fmt);
882
883 BUG_ON(!dfmt->header);
884 return scnprintf(hpp->buf, hpp->size, dfmt->header);
885}
886
887static int hpp__width(struct perf_hpp_fmt *fmt,
888 struct perf_hpp *hpp __maybe_unused)
889{
890 struct diff_hpp_fmt *dfmt =
891 container_of(fmt, struct diff_hpp_fmt, fmt);
892
893 BUG_ON(dfmt->header_width <= 0);
894 return dfmt->header_width;
895}
896
897static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
898{
899#define MAX_HEADER_NAME 100
900 char buf_indent[MAX_HEADER_NAME];
901 char buf[MAX_HEADER_NAME];
902 const char *header = NULL;
903 int width = 0;
904
905 BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
906 header = columns[dfmt->idx].name;
907 width = columns[dfmt->idx].width;
908
909 /* Only our defined HPP fmts should appear here. */
910 BUG_ON(!header);
911
912 if (data__files_cnt > 2)
913 scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
914
915#define NAME (data__files_cnt > 2 ? buf : header)
916 dfmt->header_width = width;
917 width = (int) strlen(NAME);
918 if (dfmt->header_width < width)
919 dfmt->header_width = width;
920
921 scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
922 dfmt->header_width, NAME);
923
924 dfmt->header = strdup(buf_indent);
925#undef MAX_HEADER_NAME
926#undef NAME
927}
928
929static void data__hpp_register(struct data__file *d, int idx)
930{
931 struct diff_hpp_fmt *dfmt = &d->fmt[idx];
932 struct perf_hpp_fmt *fmt = &dfmt->fmt;
933
934 dfmt->idx = idx;
935
936 fmt->header = hpp__header;
937 fmt->width = hpp__width;
938 fmt->entry = hpp__entry_global;
939
940 /* TODO more colors */
941 if (idx == PERF_HPP_DIFF__BASELINE)
942 fmt->color = hpp__color_baseline;
943
944 init_header(d, dfmt);
945 perf_hpp__column_register(fmt);
946}
947
948static void ui_init(void)
949{
950 struct data__file *d;
951 int i;
952
953 data__for_each_file(i, d) {
954
955 /*
956 * Baseline or compute realted columns:
957 *
958 * PERF_HPP_DIFF__BASELINE
959 * PERF_HPP_DIFF__DELTA
960 * PERF_HPP_DIFF__RATIO
961 * PERF_HPP_DIFF__WEIGHTED_DIFF
962 */
963 data__hpp_register(d, i ? compute_2_hpp[compute] :
964 PERF_HPP_DIFF__BASELINE);
965
966 /*
967 * And the rest:
968 *
969 * PERF_HPP_DIFF__FORMULA
970 * PERF_HPP_DIFF__PERIOD
971 * PERF_HPP_DIFF__PERIOD_BASELINE
972 */
973 if (show_formula && i)
974 data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
975
976 if (show_period)
977 data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
978 PERF_HPP_DIFF__PERIOD_BASELINE);
582 } 979 }
583} 980}
584 981
585int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) 982static int data_init(int argc, const char **argv)
586{ 983{
587 sort_order = diff__default_sort_order; 984 struct data__file *d;
588 argc = parse_options(argc, argv, options, diff_usage, 0); 985 static const char *defaults[] = {
986 "perf.data.old",
987 "perf.data",
988 };
989 bool use_default = true;
990 int i;
991
992 data__files_cnt = 2;
993
589 if (argc) { 994 if (argc) {
590 if (argc > 2) 995 if (argc == 1)
591 usage_with_options(diff_usage, options); 996 defaults[1] = argv[0];
592 if (argc == 2) { 997 else {
593 input_old = argv[0]; 998 data__files_cnt = argc;
594 input_new = argv[1]; 999 use_default = false;
595 } else 1000 }
596 input_new = argv[0];
597 } else if (symbol_conf.default_guest_vmlinux_name || 1001 } else if (symbol_conf.default_guest_vmlinux_name ||
598 symbol_conf.default_guest_kallsyms) { 1002 symbol_conf.default_guest_kallsyms) {
599 input_old = "perf.data.host"; 1003 defaults[0] = "perf.data.host";
600 input_new = "perf.data.guest"; 1004 defaults[1] = "perf.data.guest";
1005 }
1006
1007 if (sort_compute >= (unsigned int) data__files_cnt) {
1008 pr_err("Order option out of limit.\n");
1009 return -EINVAL;
1010 }
1011
1012 data__files = zalloc(sizeof(*data__files) * data__files_cnt);
1013 if (!data__files)
1014 return -ENOMEM;
1015
1016 data__for_each_file(i, d) {
1017 d->file = use_default ? defaults[i] : argv[i];
1018 d->idx = i;
601 } 1019 }
602 1020
603 symbol_conf.exclude_other = false; 1021 return 0;
1022}
1023
1024int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1025{
1026 sort_order = diff__default_sort_order;
1027 argc = parse_options(argc, argv, options, diff_usage, 0);
1028
604 if (symbol__init() < 0) 1029 if (symbol__init() < 0)
605 return -1; 1030 return -1;
606 1031
1032 if (data_init(argc, argv) < 0)
1033 return -1;
1034
607 ui_init(); 1035 ui_init();
608 1036
609 if (setup_sorting() < 0) 1037 if (setup_sorting() < 0)
@@ -611,9 +1039,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
611 1039
612 setup_pager(); 1040 setup_pager();
613 1041
614 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); 1042 sort__setup_elide(NULL);
615 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL);
616 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL);
617 1043
618 return __cmd_diff(); 1044 return __cmd_diff();
619} 1045}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 84ad6abe4258..afe377b2884f 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -38,8 +38,7 @@ struct event_entry {
38}; 38};
39 39
40static int perf_event__repipe_synth(struct perf_tool *tool, 40static int perf_event__repipe_synth(struct perf_tool *tool,
41 union perf_event *event, 41 union perf_event *event)
42 struct machine *machine __maybe_unused)
43{ 42{
44 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 43 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
45 uint32_t size; 44 uint32_t size;
@@ -65,39 +64,28 @@ static int perf_event__repipe_op2_synth(struct perf_tool *tool,
65 struct perf_session *session 64 struct perf_session *session
66 __maybe_unused) 65 __maybe_unused)
67{ 66{
68 return perf_event__repipe_synth(tool, event, NULL); 67 return perf_event__repipe_synth(tool, event);
69} 68}
70 69
71static int perf_event__repipe_event_type_synth(struct perf_tool *tool, 70static int perf_event__repipe_attr(struct perf_tool *tool,
72 union perf_event *event) 71 union perf_event *event,
73{ 72 struct perf_evlist **pevlist)
74 return perf_event__repipe_synth(tool, event, NULL);
75}
76
77static int perf_event__repipe_tracing_data_synth(union perf_event *event,
78 struct perf_session *session
79 __maybe_unused)
80{
81 return perf_event__repipe_synth(NULL, event, NULL);
82}
83
84static int perf_event__repipe_attr(union perf_event *event,
85 struct perf_evlist **pevlist __maybe_unused)
86{ 73{
87 int ret; 74 int ret;
88 ret = perf_event__process_attr(event, pevlist); 75
76 ret = perf_event__process_attr(tool, event, pevlist);
89 if (ret) 77 if (ret)
90 return ret; 78 return ret;
91 79
92 return perf_event__repipe_synth(NULL, event, NULL); 80 return perf_event__repipe_synth(tool, event);
93} 81}
94 82
95static int perf_event__repipe(struct perf_tool *tool, 83static int perf_event__repipe(struct perf_tool *tool,
96 union perf_event *event, 84 union perf_event *event,
97 struct perf_sample *sample __maybe_unused, 85 struct perf_sample *sample __maybe_unused,
98 struct machine *machine) 86 struct machine *machine __maybe_unused)
99{ 87{
100 return perf_event__repipe_synth(tool, event, machine); 88 return perf_event__repipe_synth(tool, event);
101} 89}
102 90
103typedef int (*inject_handler)(struct perf_tool *tool, 91typedef int (*inject_handler)(struct perf_tool *tool,
@@ -119,7 +107,7 @@ static int perf_event__repipe_sample(struct perf_tool *tool,
119 107
120 build_id__mark_dso_hit(tool, event, sample, evsel, machine); 108 build_id__mark_dso_hit(tool, event, sample, evsel, machine);
121 109
122 return perf_event__repipe_synth(tool, event, machine); 110 return perf_event__repipe_synth(tool, event);
123} 111}
124 112
125static int perf_event__repipe_mmap(struct perf_tool *tool, 113static int perf_event__repipe_mmap(struct perf_tool *tool,
@@ -135,6 +123,19 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
135 return err; 123 return err;
136} 124}
137 125
126static int perf_event__repipe_mmap2(struct perf_tool *tool,
127 union perf_event *event,
128 struct perf_sample *sample,
129 struct machine *machine)
130{
131 int err;
132
133 err = perf_event__process_mmap2(tool, event, sample, machine);
134 perf_event__repipe(tool, event, sample, machine);
135
136 return err;
137}
138
138static int perf_event__repipe_fork(struct perf_tool *tool, 139static int perf_event__repipe_fork(struct perf_tool *tool,
139 union perf_event *event, 140 union perf_event *event,
140 struct perf_sample *sample, 141 struct perf_sample *sample,
@@ -148,13 +149,14 @@ static int perf_event__repipe_fork(struct perf_tool *tool,
148 return err; 149 return err;
149} 150}
150 151
151static int perf_event__repipe_tracing_data(union perf_event *event, 152static int perf_event__repipe_tracing_data(struct perf_tool *tool,
153 union perf_event *event,
152 struct perf_session *session) 154 struct perf_session *session)
153{ 155{
154 int err; 156 int err;
155 157
156 perf_event__repipe_synth(NULL, event, NULL); 158 perf_event__repipe_synth(tool, event);
157 err = perf_event__process_tracing_data(event, session); 159 err = perf_event__process_tracing_data(tool, event, session);
158 160
159 return err; 161 return err;
160} 162}
@@ -209,7 +211,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
209 211
210 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 212 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
211 213
212 thread = machine__findnew_thread(machine, event->ip.pid); 214 thread = machine__findnew_thread(machine, sample->pid, sample->pid);
213 if (thread == NULL) { 215 if (thread == NULL) {
214 pr_err("problem processing %d event, skipping it.\n", 216 pr_err("problem processing %d event, skipping it.\n",
215 event->header.type); 217 event->header.type);
@@ -217,7 +219,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
217 } 219 }
218 220
219 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 221 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
220 event->ip.ip, &al); 222 sample->ip, &al);
221 223
222 if (al.map != NULL) { 224 if (al.map != NULL) {
223 if (!al.map->dso->hit) { 225 if (!al.map->dso->hit) {
@@ -312,13 +314,13 @@ found:
312 sample_sw.period = sample->period; 314 sample_sw.period = sample->period;
313 sample_sw.time = sample->time; 315 sample_sw.time = sample->time;
314 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type, 316 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
315 &sample_sw, false); 317 evsel->attr.sample_regs_user,
318 evsel->attr.read_format, &sample_sw,
319 false);
316 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine); 320 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
317 return perf_event__repipe(tool, event_sw, &sample_sw, machine); 321 return perf_event__repipe(tool, event_sw, &sample_sw, machine);
318} 322}
319 323
320extern volatile int session_done;
321
322static void sig_handler(int sig __maybe_unused) 324static void sig_handler(int sig __maybe_unused)
323{ 325{
324 session_done = 1; 326 session_done = 1;
@@ -348,6 +350,7 @@ static int __cmd_inject(struct perf_inject *inject)
348 350
349 if (inject->build_ids || inject->sched_stat) { 351 if (inject->build_ids || inject->sched_stat) {
350 inject->tool.mmap = perf_event__repipe_mmap; 352 inject->tool.mmap = perf_event__repipe_mmap;
353 inject->tool.mmap2 = perf_event__repipe_mmap2;
351 inject->tool.fork = perf_event__repipe_fork; 354 inject->tool.fork = perf_event__repipe_fork;
352 inject->tool.tracing_data = perf_event__repipe_tracing_data; 355 inject->tool.tracing_data = perf_event__repipe_tracing_data;
353 } 356 }
@@ -399,6 +402,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
399 .tool = { 402 .tool = {
400 .sample = perf_event__repipe_sample, 403 .sample = perf_event__repipe_sample,
401 .mmap = perf_event__repipe, 404 .mmap = perf_event__repipe,
405 .mmap2 = perf_event__repipe,
402 .comm = perf_event__repipe, 406 .comm = perf_event__repipe,
403 .fork = perf_event__repipe, 407 .fork = perf_event__repipe,
404 .exit = perf_event__repipe, 408 .exit = perf_event__repipe,
@@ -407,8 +411,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
407 .throttle = perf_event__repipe, 411 .throttle = perf_event__repipe,
408 .unthrottle = perf_event__repipe, 412 .unthrottle = perf_event__repipe,
409 .attr = perf_event__repipe_attr, 413 .attr = perf_event__repipe_attr,
410 .event_type = perf_event__repipe_event_type_synth, 414 .tracing_data = perf_event__repipe_op2_synth,
411 .tracing_data = perf_event__repipe_tracing_data_synth, 415 .finished_round = perf_event__repipe_op2_synth,
412 .build_id = perf_event__repipe_op2_synth, 416 .build_id = perf_event__repipe_op2_synth,
413 }, 417 },
414 .input_name = "-", 418 .input_name = "-",
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 46878daca5cc..9b5f077fee5b 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -101,7 +101,7 @@ static int setup_cpunode_map(void)
101 101
102 dir1 = opendir(PATH_SYS_NODE); 102 dir1 = opendir(PATH_SYS_NODE);
103 if (!dir1) 103 if (!dir1)
104 return -1; 104 return 0;
105 105
106 while ((dent1 = readdir(dir1)) != NULL) { 106 while ((dent1 = readdir(dir1)) != NULL) {
107 if (dent1->d_type != DT_DIR || 107 if (dent1->d_type != DT_DIR ||
@@ -305,7 +305,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
305 struct perf_evsel *evsel, 305 struct perf_evsel *evsel,
306 struct machine *machine) 306 struct machine *machine)
307{ 307{
308 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 308 struct thread *thread = machine__findnew_thread(machine, sample->pid,
309 sample->pid);
309 310
310 if (thread == NULL) { 311 if (thread == NULL) {
311 pr_debug("problem processing %d event, skipping it.\n", 312 pr_debug("problem processing %d event, skipping it.\n",
@@ -313,7 +314,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
313 return -1; 314 return -1;
314 } 315 }
315 316
316 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 317 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
317 318
318 if (evsel->handler.func != NULL) { 319 if (evsel->handler.func != NULL) {
319 tracepoint_handler f = evsel->handler.func; 320 tracepoint_handler f = evsel->handler.func;
@@ -708,7 +709,7 @@ static int parse_line_opt(const struct option *opt __maybe_unused,
708static int __cmd_record(int argc, const char **argv) 709static int __cmd_record(int argc, const char **argv)
709{ 710{
710 const char * const record_args[] = { 711 const char * const record_args[] = {
711 "record", "-a", "-R", "-f", "-c", "1", 712 "record", "-a", "-R", "-c", "1",
712 "-e", "kmem:kmalloc", 713 "-e", "kmem:kmalloc",
713 "-e", "kmem:kmalloc_node", 714 "-e", "kmem:kmalloc_node",
714 "-e", "kmem:kfree", 715 "-e", "kmem:kfree",
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 533501e2b07c..935d52216c89 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -2,22 +2,26 @@
2#include "perf.h" 2#include "perf.h"
3 3
4#include "util/evsel.h" 4#include "util/evsel.h"
5#include "util/evlist.h"
5#include "util/util.h" 6#include "util/util.h"
6#include "util/cache.h" 7#include "util/cache.h"
7#include "util/symbol.h" 8#include "util/symbol.h"
8#include "util/thread.h" 9#include "util/thread.h"
9#include "util/header.h" 10#include "util/header.h"
10#include "util/session.h" 11#include "util/session.h"
11 12#include "util/intlist.h"
12#include "util/parse-options.h" 13#include "util/parse-options.h"
13#include "util/trace-event.h" 14#include "util/trace-event.h"
14#include "util/debug.h" 15#include "util/debug.h"
15#include <lk/debugfs.h> 16#include <lk/debugfs.h>
16#include "util/tool.h" 17#include "util/tool.h"
17#include "util/stat.h" 18#include "util/stat.h"
19#include "util/top.h"
18 20
19#include <sys/prctl.h> 21#include <sys/prctl.h>
22#include <sys/timerfd.h>
20 23
24#include <termios.h>
21#include <semaphore.h> 25#include <semaphore.h>
22#include <pthread.h> 26#include <pthread.h>
23#include <math.h> 27#include <math.h>
@@ -82,6 +86,8 @@ struct exit_reasons_table {
82 86
83struct perf_kvm_stat { 87struct perf_kvm_stat {
84 struct perf_tool tool; 88 struct perf_tool tool;
89 struct perf_record_opts opts;
90 struct perf_evlist *evlist;
85 struct perf_session *session; 91 struct perf_session *session;
86 92
87 const char *file_name; 93 const char *file_name;
@@ -96,10 +102,20 @@ struct perf_kvm_stat {
96 struct kvm_events_ops *events_ops; 102 struct kvm_events_ops *events_ops;
97 key_cmp_fun compare; 103 key_cmp_fun compare;
98 struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; 104 struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
105
99 u64 total_time; 106 u64 total_time;
100 u64 total_count; 107 u64 total_count;
108 u64 lost_events;
109 u64 duration;
110
111 const char *pid_str;
112 struct intlist *pid_list;
101 113
102 struct rb_root result; 114 struct rb_root result;
115
116 int timerfd;
117 unsigned int display_time;
118 bool live;
103}; 119};
104 120
105 121
@@ -320,6 +336,28 @@ static void init_kvm_event_record(struct perf_kvm_stat *kvm)
320 INIT_LIST_HEAD(&kvm->kvm_events_cache[i]); 336 INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
321} 337}
322 338
339static void clear_events_cache_stats(struct list_head *kvm_events_cache)
340{
341 struct list_head *head;
342 struct kvm_event *event;
343 unsigned int i;
344 int j;
345
346 for (i = 0; i < EVENTS_CACHE_SIZE; i++) {
347 head = &kvm_events_cache[i];
348 list_for_each_entry(event, head, hash_entry) {
349 /* reset stats for event */
350 event->total.time = 0;
351 init_stats(&event->total.stats);
352
353 for (j = 0; j < event->max_vcpu; ++j) {
354 event->vcpu[j].time = 0;
355 init_stats(&event->vcpu[j].stats);
356 }
357 }
358 }
359}
360
323static int kvm_events_hash_fn(u64 key) 361static int kvm_events_hash_fn(u64 key)
324{ 362{
325 return key & (EVENTS_CACHE_SIZE - 1); 363 return key & (EVENTS_CACHE_SIZE - 1);
@@ -328,6 +366,7 @@ static int kvm_events_hash_fn(u64 key)
328static bool kvm_event_expand(struct kvm_event *event, int vcpu_id) 366static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
329{ 367{
330 int old_max_vcpu = event->max_vcpu; 368 int old_max_vcpu = event->max_vcpu;
369 void *prev;
331 370
332 if (vcpu_id < event->max_vcpu) 371 if (vcpu_id < event->max_vcpu)
333 return true; 372 return true;
@@ -335,9 +374,11 @@ static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
335 while (event->max_vcpu <= vcpu_id) 374 while (event->max_vcpu <= vcpu_id)
336 event->max_vcpu += DEFAULT_VCPU_NUM; 375 event->max_vcpu += DEFAULT_VCPU_NUM;
337 376
377 prev = event->vcpu;
338 event->vcpu = realloc(event->vcpu, 378 event->vcpu = realloc(event->vcpu,
339 event->max_vcpu * sizeof(*event->vcpu)); 379 event->max_vcpu * sizeof(*event->vcpu));
340 if (!event->vcpu) { 380 if (!event->vcpu) {
381 free(prev);
341 pr_err("Not enough memory\n"); 382 pr_err("Not enough memory\n");
342 return false; 383 return false;
343 } 384 }
@@ -433,7 +474,7 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
433static bool handle_end_event(struct perf_kvm_stat *kvm, 474static bool handle_end_event(struct perf_kvm_stat *kvm,
434 struct vcpu_event_record *vcpu_record, 475 struct vcpu_event_record *vcpu_record,
435 struct event_key *key, 476 struct event_key *key,
436 u64 timestamp) 477 struct perf_sample *sample)
437{ 478{
438 struct kvm_event *event; 479 struct kvm_event *event;
439 u64 time_begin, time_diff; 480 u64 time_begin, time_diff;
@@ -469,9 +510,25 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
469 vcpu_record->last_event = NULL; 510 vcpu_record->last_event = NULL;
470 vcpu_record->start_time = 0; 511 vcpu_record->start_time = 0;
471 512
472 BUG_ON(timestamp < time_begin); 513 /* seems to happen once in a while during live mode */
514 if (sample->time < time_begin) {
515 pr_debug("End time before begin time; skipping event.\n");
516 return true;
517 }
518
519 time_diff = sample->time - time_begin;
520
521 if (kvm->duration && time_diff > kvm->duration) {
522 char decode[32];
523
524 kvm->events_ops->decode_key(kvm, &event->key, decode);
525 if (strcmp(decode, "HLT")) {
526 pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n",
527 sample->time, sample->pid, vcpu_record->vcpu_id,
528 decode, time_diff/1000);
529 }
530 }
473 531
474 time_diff = timestamp - time_begin;
475 return update_kvm_event(event, vcpu, time_diff); 532 return update_kvm_event(event, vcpu, time_diff);
476} 533}
477 534
@@ -518,7 +575,7 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
518 return handle_begin_event(kvm, vcpu_record, &key, sample->time); 575 return handle_begin_event(kvm, vcpu_record, &key, sample->time);
519 576
520 if (kvm->events_ops->is_end_event(evsel, sample, &key)) 577 if (kvm->events_ops->is_end_event(evsel, sample, &key))
521 return handle_end_event(kvm, vcpu_record, &key, sample->time); 578 return handle_end_event(kvm, vcpu_record, &key, sample);
522 579
523 return true; 580 return true;
524} 581}
@@ -547,6 +604,8 @@ static int compare_kvm_event_ ## func(struct kvm_event *one, \
547GET_EVENT_KEY(time, time); 604GET_EVENT_KEY(time, time);
548COMPARE_EVENT_KEY(count, stats.n); 605COMPARE_EVENT_KEY(count, stats.n);
549COMPARE_EVENT_KEY(mean, stats.mean); 606COMPARE_EVENT_KEY(mean, stats.mean);
607GET_EVENT_KEY(max, stats.max);
608GET_EVENT_KEY(min, stats.min);
550 609
551#define DEF_SORT_NAME_KEY(name, compare_key) \ 610#define DEF_SORT_NAME_KEY(name, compare_key) \
552 { #name, compare_kvm_event_ ## compare_key } 611 { #name, compare_kvm_event_ ## compare_key }
@@ -636,43 +695,81 @@ static struct kvm_event *pop_from_result(struct rb_root *result)
636 return container_of(node, struct kvm_event, rb); 695 return container_of(node, struct kvm_event, rb);
637} 696}
638 697
639static void print_vcpu_info(int vcpu) 698static void print_vcpu_info(struct perf_kvm_stat *kvm)
640{ 699{
700 int vcpu = kvm->trace_vcpu;
701
641 pr_info("Analyze events for "); 702 pr_info("Analyze events for ");
642 703
704 if (kvm->live) {
705 if (kvm->opts.target.system_wide)
706 pr_info("all VMs, ");
707 else if (kvm->opts.target.pid)
708 pr_info("pid(s) %s, ", kvm->opts.target.pid);
709 else
710 pr_info("dazed and confused on what is monitored, ");
711 }
712
643 if (vcpu == -1) 713 if (vcpu == -1)
644 pr_info("all VCPUs:\n\n"); 714 pr_info("all VCPUs:\n\n");
645 else 715 else
646 pr_info("VCPU %d:\n\n", vcpu); 716 pr_info("VCPU %d:\n\n", vcpu);
647} 717}
648 718
719static void show_timeofday(void)
720{
721 char date[64];
722 struct timeval tv;
723 struct tm ltime;
724
725 gettimeofday(&tv, NULL);
726 if (localtime_r(&tv.tv_sec, &ltime)) {
727 strftime(date, sizeof(date), "%H:%M:%S", &ltime);
728 pr_info("%s.%06ld", date, tv.tv_usec);
729 } else
730 pr_info("00:00:00.000000");
731
732 return;
733}
734
649static void print_result(struct perf_kvm_stat *kvm) 735static void print_result(struct perf_kvm_stat *kvm)
650{ 736{
651 char decode[20]; 737 char decode[20];
652 struct kvm_event *event; 738 struct kvm_event *event;
653 int vcpu = kvm->trace_vcpu; 739 int vcpu = kvm->trace_vcpu;
654 740
741 if (kvm->live) {
742 puts(CONSOLE_CLEAR);
743 show_timeofday();
744 }
745
655 pr_info("\n\n"); 746 pr_info("\n\n");
656 print_vcpu_info(vcpu); 747 print_vcpu_info(kvm);
657 pr_info("%20s ", kvm->events_ops->name); 748 pr_info("%20s ", kvm->events_ops->name);
658 pr_info("%10s ", "Samples"); 749 pr_info("%10s ", "Samples");
659 pr_info("%9s ", "Samples%"); 750 pr_info("%9s ", "Samples%");
660 751
661 pr_info("%9s ", "Time%"); 752 pr_info("%9s ", "Time%");
753 pr_info("%10s ", "Min Time");
754 pr_info("%10s ", "Max Time");
662 pr_info("%16s ", "Avg time"); 755 pr_info("%16s ", "Avg time");
663 pr_info("\n\n"); 756 pr_info("\n\n");
664 757
665 while ((event = pop_from_result(&kvm->result))) { 758 while ((event = pop_from_result(&kvm->result))) {
666 u64 ecount, etime; 759 u64 ecount, etime, max, min;
667 760
668 ecount = get_event_count(event, vcpu); 761 ecount = get_event_count(event, vcpu);
669 etime = get_event_time(event, vcpu); 762 etime = get_event_time(event, vcpu);
763 max = get_event_max(event, vcpu);
764 min = get_event_min(event, vcpu);
670 765
671 kvm->events_ops->decode_key(kvm, &event->key, decode); 766 kvm->events_ops->decode_key(kvm, &event->key, decode);
672 pr_info("%20s ", decode); 767 pr_info("%20s ", decode);
673 pr_info("%10llu ", (unsigned long long)ecount); 768 pr_info("%10llu ", (unsigned long long)ecount);
674 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); 769 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
675 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); 770 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
771 pr_info("%8" PRIu64 "us ", min / 1000);
772 pr_info("%8" PRIu64 "us ", max / 1000);
676 pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, 773 pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
677 kvm_event_rel_stddev(vcpu, event)); 774 kvm_event_rel_stddev(vcpu, event));
678 pr_info("\n"); 775 pr_info("\n");
@@ -680,6 +777,29 @@ static void print_result(struct perf_kvm_stat *kvm)
680 777
681 pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n", 778 pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n",
682 kvm->total_count, kvm->total_time / 1e3); 779 kvm->total_count, kvm->total_time / 1e3);
780
781 if (kvm->lost_events)
782 pr_info("\nLost events: %" PRIu64 "\n\n", kvm->lost_events);
783}
784
785static int process_lost_event(struct perf_tool *tool,
786 union perf_event *event __maybe_unused,
787 struct perf_sample *sample __maybe_unused,
788 struct machine *machine __maybe_unused)
789{
790 struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, tool);
791
792 kvm->lost_events++;
793 return 0;
794}
795
796static bool skip_sample(struct perf_kvm_stat *kvm,
797 struct perf_sample *sample)
798{
799 if (kvm->pid_list && intlist__find(kvm->pid_list, sample->pid) == NULL)
800 return true;
801
802 return false;
683} 803}
684 804
685static int process_sample_event(struct perf_tool *tool, 805static int process_sample_event(struct perf_tool *tool,
@@ -688,10 +808,14 @@ static int process_sample_event(struct perf_tool *tool,
688 struct perf_evsel *evsel, 808 struct perf_evsel *evsel,
689 struct machine *machine) 809 struct machine *machine)
690{ 810{
691 struct thread *thread = machine__findnew_thread(machine, sample->tid); 811 struct thread *thread;
692 struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, 812 struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,
693 tool); 813 tool);
694 814
815 if (skip_sample(kvm, sample))
816 return 0;
817
818 thread = machine__findnew_thread(machine, sample->pid, sample->tid);
695 if (thread == NULL) { 819 if (thread == NULL) {
696 pr_debug("problem processing %d event, skipping it.\n", 820 pr_debug("problem processing %d event, skipping it.\n",
697 event->header.type); 821 event->header.type);
@@ -704,10 +828,20 @@ static int process_sample_event(struct perf_tool *tool,
704 return 0; 828 return 0;
705} 829}
706 830
707static int get_cpu_isa(struct perf_session *session) 831static int cpu_isa_config(struct perf_kvm_stat *kvm)
708{ 832{
709 char *cpuid = session->header.env.cpuid; 833 char buf[64], *cpuid;
710 int isa; 834 int err, isa;
835
836 if (kvm->live) {
837 err = get_cpuid(buf, sizeof(buf));
838 if (err != 0) {
839 pr_err("Failed to look up CPU type (Intel or AMD)\n");
840 return err;
841 }
842 cpuid = buf;
843 } else
844 cpuid = kvm->session->header.env.cpuid;
711 845
712 if (strstr(cpuid, "Intel")) 846 if (strstr(cpuid, "Intel"))
713 isa = 1; 847 isa = 1;
@@ -715,10 +849,361 @@ static int get_cpu_isa(struct perf_session *session)
715 isa = 0; 849 isa = 0;
716 else { 850 else {
717 pr_err("CPU %s is not supported.\n", cpuid); 851 pr_err("CPU %s is not supported.\n", cpuid);
718 isa = -ENOTSUP; 852 return -ENOTSUP;
853 }
854
855 if (isa == 1) {
856 kvm->exit_reasons = vmx_exit_reasons;
857 kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
858 kvm->exit_reasons_isa = "VMX";
859 }
860
861 return 0;
862}
863
864static bool verify_vcpu(int vcpu)
865{
866 if (vcpu != -1 && vcpu < 0) {
867 pr_err("Invalid vcpu:%d.\n", vcpu);
868 return false;
869 }
870
871 return true;
872}
873
874/* keeping the max events to a modest level to keep
875 * the processing of samples per mmap smooth.
876 */
877#define PERF_KVM__MAX_EVENTS_PER_MMAP 25
878
879static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
880 u64 *mmap_time)
881{
882 union perf_event *event;
883 struct perf_sample sample;
884 s64 n = 0;
885 int err;
886
887 *mmap_time = ULLONG_MAX;
888 while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) {
889 err = perf_evlist__parse_sample(kvm->evlist, event, &sample);
890 if (err) {
891 pr_err("Failed to parse sample\n");
892 return -1;
893 }
894
895 err = perf_session_queue_event(kvm->session, event, &sample, 0);
896 if (err) {
897 pr_err("Failed to enqueue sample: %d\n", err);
898 return -1;
899 }
900
901 /* save time stamp of our first sample for this mmap */
902 if (n == 0)
903 *mmap_time = sample.time;
904
905 /* limit events per mmap handled all at once */
906 n++;
907 if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
908 break;
909 }
910
911 return n;
912}
913
914static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm)
915{
916 int i, err, throttled = 0;
917 s64 n, ntotal = 0;
918 u64 flush_time = ULLONG_MAX, mmap_time;
919
920 for (i = 0; i < kvm->evlist->nr_mmaps; i++) {
921 n = perf_kvm__mmap_read_idx(kvm, i, &mmap_time);
922 if (n < 0)
923 return -1;
924
925 /* flush time is going to be the minimum of all the individual
926 * mmap times. Essentially, we flush all the samples queued up
927 * from the last pass under our minimal start time -- that leaves
928 * a very small race for samples to come in with a lower timestamp.
929 * The ioctl to return the perf_clock timestamp should close the
930 * race entirely.
931 */
932 if (mmap_time < flush_time)
933 flush_time = mmap_time;
934
935 ntotal += n;
936 if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
937 throttled = 1;
938 }
939
940 /* flush queue after each round in which we processed events */
941 if (ntotal) {
942 kvm->session->ordered_samples.next_flush = flush_time;
943 err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session);
944 if (err) {
945 if (kvm->lost_events)
946 pr_info("\nLost events: %" PRIu64 "\n\n",
947 kvm->lost_events);
948 return err;
949 }
950 }
951
952 return throttled;
953}
954
955static volatile int done;
956
957static void sig_handler(int sig __maybe_unused)
958{
959 done = 1;
960}
961
962static int perf_kvm__timerfd_create(struct perf_kvm_stat *kvm)
963{
964 struct itimerspec new_value;
965 int rc = -1;
966
967 kvm->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
968 if (kvm->timerfd < 0) {
969 pr_err("timerfd_create failed\n");
970 goto out;
971 }
972
973 new_value.it_value.tv_sec = kvm->display_time;
974 new_value.it_value.tv_nsec = 0;
975 new_value.it_interval.tv_sec = kvm->display_time;
976 new_value.it_interval.tv_nsec = 0;
977
978 if (timerfd_settime(kvm->timerfd, 0, &new_value, NULL) != 0) {
979 pr_err("timerfd_settime failed: %d\n", errno);
980 close(kvm->timerfd);
981 goto out;
982 }
983
984 rc = 0;
985out:
986 return rc;
987}
988
989static int perf_kvm__handle_timerfd(struct perf_kvm_stat *kvm)
990{
991 uint64_t c;
992 int rc;
993
994 rc = read(kvm->timerfd, &c, sizeof(uint64_t));
995 if (rc < 0) {
996 if (errno == EAGAIN)
997 return 0;
998
999 pr_err("Failed to read timer fd: %d\n", errno);
1000 return -1;
1001 }
1002
1003 if (rc != sizeof(uint64_t)) {
1004 pr_err("Error reading timer fd - invalid size returned\n");
1005 return -1;
1006 }
1007
1008 if (c != 1)
1009 pr_debug("Missed timer beats: %" PRIu64 "\n", c-1);
1010
1011 /* update display */
1012 sort_result(kvm);
1013 print_result(kvm);
1014
1015 /* reset counts */
1016 clear_events_cache_stats(kvm->kvm_events_cache);
1017 kvm->total_count = 0;
1018 kvm->total_time = 0;
1019 kvm->lost_events = 0;
1020
1021 return 0;
1022}
1023
1024static int fd_set_nonblock(int fd)
1025{
1026 long arg = 0;
1027
1028 arg = fcntl(fd, F_GETFL);
1029 if (arg < 0) {
1030 pr_err("Failed to get current flags for fd %d\n", fd);
1031 return -1;
1032 }
1033
1034 if (fcntl(fd, F_SETFL, arg | O_NONBLOCK) < 0) {
1035 pr_err("Failed to set non-block option on fd %d\n", fd);
1036 return -1;
1037 }
1038
1039 return 0;
1040}
1041
1042static
1043int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save)
1044{
1045 int c;
1046
1047 tcsetattr(0, TCSANOW, tc_now);
1048 c = getc(stdin);
1049 tcsetattr(0, TCSAFLUSH, tc_save);
1050
1051 if (c == 'q')
1052 return 1;
1053
1054 return 0;
1055}
1056
1057static int kvm_events_live_report(struct perf_kvm_stat *kvm)
1058{
1059 struct pollfd *pollfds = NULL;
1060 int nr_fds, nr_stdin, ret, err = -EINVAL;
1061 struct termios tc, save;
1062
1063 /* live flag must be set first */
1064 kvm->live = true;
1065
1066 ret = cpu_isa_config(kvm);
1067 if (ret < 0)
1068 return ret;
1069
1070 if (!verify_vcpu(kvm->trace_vcpu) ||
1071 !select_key(kvm) ||
1072 !register_kvm_events_ops(kvm)) {
1073 goto out;
1074 }
1075
1076 init_kvm_event_record(kvm);
1077
1078 tcgetattr(0, &save);
1079 tc = save;
1080 tc.c_lflag &= ~(ICANON | ECHO);
1081 tc.c_cc[VMIN] = 0;
1082 tc.c_cc[VTIME] = 0;
1083
1084 signal(SIGINT, sig_handler);
1085 signal(SIGTERM, sig_handler);
1086
1087 /* copy pollfds -- need to add timerfd and stdin */
1088 nr_fds = kvm->evlist->nr_fds;
1089 pollfds = zalloc(sizeof(struct pollfd) * (nr_fds + 2));
1090 if (!pollfds) {
1091 err = -ENOMEM;
1092 goto out;
719 } 1093 }
1094 memcpy(pollfds, kvm->evlist->pollfd,
1095 sizeof(struct pollfd) * kvm->evlist->nr_fds);
1096
1097 /* add timer fd */
1098 if (perf_kvm__timerfd_create(kvm) < 0) {
1099 err = -1;
1100 goto out;
1101 }
1102
1103 pollfds[nr_fds].fd = kvm->timerfd;
1104 pollfds[nr_fds].events = POLLIN;
1105 nr_fds++;
1106
1107 pollfds[nr_fds].fd = fileno(stdin);
1108 pollfds[nr_fds].events = POLLIN;
1109 nr_stdin = nr_fds;
1110 nr_fds++;
1111 if (fd_set_nonblock(fileno(stdin)) != 0)
1112 goto out;
1113
1114 /* everything is good - enable the events and process */
1115 perf_evlist__enable(kvm->evlist);
1116
1117 while (!done) {
1118 int rc;
1119
1120 rc = perf_kvm__mmap_read(kvm);
1121 if (rc < 0)
1122 break;
1123
1124 err = perf_kvm__handle_timerfd(kvm);
1125 if (err)
1126 goto out;
1127
1128 if (pollfds[nr_stdin].revents & POLLIN)
1129 done = perf_kvm__handle_stdin(&tc, &save);
1130
1131 if (!rc && !done)
1132 err = poll(pollfds, nr_fds, 100);
1133 }
1134
1135 perf_evlist__disable(kvm->evlist);
1136
1137 if (err == 0) {
1138 sort_result(kvm);
1139 print_result(kvm);
1140 }
1141
1142out:
1143 if (kvm->timerfd >= 0)
1144 close(kvm->timerfd);
1145
1146 if (pollfds)
1147 free(pollfds);
720 1148
721 return isa; 1149 return err;
1150}
1151
1152static int kvm_live_open_events(struct perf_kvm_stat *kvm)
1153{
1154 int err, rc = -1;
1155 struct perf_evsel *pos;
1156 struct perf_evlist *evlist = kvm->evlist;
1157
1158 perf_evlist__config(evlist, &kvm->opts);
1159
1160 /*
1161 * Note: exclude_{guest,host} do not apply here.
1162 * This command processes KVM tracepoints from host only
1163 */
1164 list_for_each_entry(pos, &evlist->entries, node) {
1165 struct perf_event_attr *attr = &pos->attr;
1166
1167 /* make sure these *are* set */
1168 perf_evsel__set_sample_bit(pos, TID);
1169 perf_evsel__set_sample_bit(pos, TIME);
1170 perf_evsel__set_sample_bit(pos, CPU);
1171 perf_evsel__set_sample_bit(pos, RAW);
1172 /* make sure these are *not*; want as small a sample as possible */
1173 perf_evsel__reset_sample_bit(pos, PERIOD);
1174 perf_evsel__reset_sample_bit(pos, IP);
1175 perf_evsel__reset_sample_bit(pos, CALLCHAIN);
1176 perf_evsel__reset_sample_bit(pos, ADDR);
1177 perf_evsel__reset_sample_bit(pos, READ);
1178 attr->mmap = 0;
1179 attr->comm = 0;
1180 attr->task = 0;
1181
1182 attr->sample_period = 1;
1183
1184 attr->watermark = 0;
1185 attr->wakeup_events = 1000;
1186
1187 /* will enable all once we are ready */
1188 attr->disabled = 1;
1189 }
1190
1191 err = perf_evlist__open(evlist);
1192 if (err < 0) {
1193 printf("Couldn't create the events: %s\n", strerror(errno));
1194 goto out;
1195 }
1196
1197 if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) {
1198 ui__error("Failed to mmap the events: %s\n", strerror(errno));
1199 perf_evlist__close(evlist);
1200 goto out;
1201 }
1202
1203 rc = 0;
1204
1205out:
1206 return rc;
722} 1207}
723 1208
724static int read_events(struct perf_kvm_stat *kvm) 1209static int read_events(struct perf_kvm_stat *kvm)
@@ -746,28 +1231,24 @@ static int read_events(struct perf_kvm_stat *kvm)
746 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not 1231 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
747 * traced in the old kernel. 1232 * traced in the old kernel.
748 */ 1233 */
749 ret = get_cpu_isa(kvm->session); 1234 ret = cpu_isa_config(kvm);
750
751 if (ret < 0) 1235 if (ret < 0)
752 return ret; 1236 return ret;
753 1237
754 if (ret == 1) {
755 kvm->exit_reasons = vmx_exit_reasons;
756 kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
757 kvm->exit_reasons_isa = "VMX";
758 }
759
760 return perf_session__process_events(kvm->session, &kvm->tool); 1238 return perf_session__process_events(kvm->session, &kvm->tool);
761} 1239}
762 1240
763static bool verify_vcpu(int vcpu) 1241static int parse_target_str(struct perf_kvm_stat *kvm)
764{ 1242{
765 if (vcpu != -1 && vcpu < 0) { 1243 if (kvm->pid_str) {
766 pr_err("Invalid vcpu:%d.\n", vcpu); 1244 kvm->pid_list = intlist__new(kvm->pid_str);
767 return false; 1245 if (kvm->pid_list == NULL) {
1246 pr_err("Error parsing process id string\n");
1247 return -EINVAL;
1248 }
768 } 1249 }
769 1250
770 return true; 1251 return 0;
771} 1252}
772 1253
773static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm) 1254static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
@@ -775,6 +1256,9 @@ static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
775 int ret = -EINVAL; 1256 int ret = -EINVAL;
776 int vcpu = kvm->trace_vcpu; 1257 int vcpu = kvm->trace_vcpu;
777 1258
1259 if (parse_target_str(kvm) != 0)
1260 goto exit;
1261
778 if (!verify_vcpu(vcpu)) 1262 if (!verify_vcpu(vcpu))
779 goto exit; 1263 goto exit;
780 1264
@@ -798,16 +1282,11 @@ exit:
798 return ret; 1282 return ret;
799} 1283}
800 1284
801static const char * const record_args[] = { 1285static const char * const kvm_events_tp[] = {
802 "record", 1286 "kvm:kvm_entry",
803 "-R", 1287 "kvm:kvm_exit",
804 "-f", 1288 "kvm:kvm_mmio",
805 "-m", "1024", 1289 "kvm:kvm_pio",
806 "-c", "1",
807 "-e", "kvm:kvm_entry",
808 "-e", "kvm:kvm_exit",
809 "-e", "kvm:kvm_mmio",
810 "-e", "kvm:kvm_pio",
811}; 1290};
812 1291
813#define STRDUP_FAIL_EXIT(s) \ 1292#define STRDUP_FAIL_EXIT(s) \
@@ -823,8 +1302,15 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
823{ 1302{
824 unsigned int rec_argc, i, j; 1303 unsigned int rec_argc, i, j;
825 const char **rec_argv; 1304 const char **rec_argv;
1305 const char * const record_args[] = {
1306 "record",
1307 "-R",
1308 "-m", "1024",
1309 "-c", "1",
1310 };
826 1311
827 rec_argc = ARRAY_SIZE(record_args) + argc + 2; 1312 rec_argc = ARRAY_SIZE(record_args) + argc + 2 +
1313 2 * ARRAY_SIZE(kvm_events_tp);
828 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1314 rec_argv = calloc(rec_argc + 1, sizeof(char *));
829 1315
830 if (rec_argv == NULL) 1316 if (rec_argv == NULL)
@@ -833,6 +1319,11 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
833 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1319 for (i = 0; i < ARRAY_SIZE(record_args); i++)
834 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); 1320 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);
835 1321
1322 for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) {
1323 rec_argv[i++] = "-e";
1324 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]);
1325 }
1326
836 rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); 1327 rec_argv[i++] = STRDUP_FAIL_EXIT("-o");
837 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name); 1328 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name);
838 1329
@@ -853,6 +1344,8 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
853 OPT_STRING('k', "key", &kvm->sort_key, "sort-key", 1344 OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
854 "key for sorting: sample(sort by samples number)" 1345 "key for sorting: sample(sort by samples number)"
855 " time (sort by avg time)"), 1346 " time (sort by avg time)"),
1347 OPT_STRING('p', "pid", &kvm->pid_str, "pid",
1348 "analyze events only for given process id(s)"),
856 OPT_END() 1349 OPT_END()
857 }; 1350 };
858 1351
@@ -875,6 +1368,190 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
875 return kvm_events_report_vcpu(kvm); 1368 return kvm_events_report_vcpu(kvm);
876} 1369}
877 1370
1371static struct perf_evlist *kvm_live_event_list(void)
1372{
1373 struct perf_evlist *evlist;
1374 char *tp, *name, *sys;
1375 unsigned int j;
1376 int err = -1;
1377
1378 evlist = perf_evlist__new();
1379 if (evlist == NULL)
1380 return NULL;
1381
1382 for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) {
1383
1384 tp = strdup(kvm_events_tp[j]);
1385 if (tp == NULL)
1386 goto out;
1387
1388 /* split tracepoint into subsystem and name */
1389 sys = tp;
1390 name = strchr(tp, ':');
1391 if (name == NULL) {
1392 pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n",
1393 kvm_events_tp[j]);
1394 free(tp);
1395 goto out;
1396 }
1397 *name = '\0';
1398 name++;
1399
1400 if (perf_evlist__add_newtp(evlist, sys, name, NULL)) {
1401 pr_err("Failed to add %s tracepoint to the list\n", kvm_events_tp[j]);
1402 free(tp);
1403 goto out;
1404 }
1405
1406 free(tp);
1407 }
1408
1409 err = 0;
1410
1411out:
1412 if (err) {
1413 perf_evlist__delete(evlist);
1414 evlist = NULL;
1415 }
1416
1417 return evlist;
1418}
1419
1420static int kvm_events_live(struct perf_kvm_stat *kvm,
1421 int argc, const char **argv)
1422{
1423 char errbuf[BUFSIZ];
1424 int err;
1425
1426 const struct option live_options[] = {
1427 OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
1428 "record events on existing process id"),
1429 OPT_UINTEGER('m', "mmap-pages", &kvm->opts.mmap_pages,
1430 "number of mmap data pages"),
1431 OPT_INCR('v', "verbose", &verbose,
1432 "be more verbose (show counter open errors, etc)"),
1433 OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide,
1434 "system-wide collection from all CPUs"),
1435 OPT_UINTEGER('d', "display", &kvm->display_time,
1436 "time in seconds between display updates"),
1437 OPT_STRING(0, "event", &kvm->report_event, "report event",
1438 "event for reporting: vmexit, mmio, ioport"),
1439 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
1440 "vcpu id to report"),
1441 OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
1442 "key for sorting: sample(sort by samples number)"
1443 " time (sort by avg time)"),
1444 OPT_U64(0, "duration", &kvm->duration,
1445 "show events other than HALT that take longer than duration usecs"),
1446 OPT_END()
1447 };
1448 const char * const live_usage[] = {
1449 "perf kvm stat live [<options>]",
1450 NULL
1451 };
1452
1453
1454 /* event handling */
1455 kvm->tool.sample = process_sample_event;
1456 kvm->tool.comm = perf_event__process_comm;
1457 kvm->tool.exit = perf_event__process_exit;
1458 kvm->tool.fork = perf_event__process_fork;
1459 kvm->tool.lost = process_lost_event;
1460 kvm->tool.ordered_samples = true;
1461 perf_tool__fill_defaults(&kvm->tool);
1462
1463 /* set defaults */
1464 kvm->display_time = 1;
1465 kvm->opts.user_interval = 1;
1466 kvm->opts.mmap_pages = 512;
1467 kvm->opts.target.uses_mmap = false;
1468 kvm->opts.target.uid_str = NULL;
1469 kvm->opts.target.uid = UINT_MAX;
1470
1471 symbol__init();
1472 disable_buildid_cache();
1473
1474 use_browser = 0;
1475 setup_browser(false);
1476
1477 if (argc) {
1478 argc = parse_options(argc, argv, live_options,
1479 live_usage, 0);
1480 if (argc)
1481 usage_with_options(live_usage, live_options);
1482 }
1483
1484 kvm->duration *= NSEC_PER_USEC; /* convert usec to nsec */
1485
1486 /*
1487 * target related setups
1488 */
1489 err = perf_target__validate(&kvm->opts.target);
1490 if (err) {
1491 perf_target__strerror(&kvm->opts.target, err, errbuf, BUFSIZ);
1492 ui__warning("%s", errbuf);
1493 }
1494
1495 if (perf_target__none(&kvm->opts.target))
1496 kvm->opts.target.system_wide = true;
1497
1498
1499 /*
1500 * generate the event list
1501 */
1502 kvm->evlist = kvm_live_event_list();
1503 if (kvm->evlist == NULL) {
1504 err = -1;
1505 goto out;
1506 }
1507
1508 symbol_conf.nr_events = kvm->evlist->nr_entries;
1509
1510 if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0)
1511 usage_with_options(live_usage, live_options);
1512
1513 /*
1514 * perf session
1515 */
1516 kvm->session = perf_session__new(NULL, O_WRONLY, false, false, &kvm->tool);
1517 if (kvm->session == NULL) {
1518 err = -ENOMEM;
1519 goto out;
1520 }
1521 kvm->session->evlist = kvm->evlist;
1522 perf_session__set_id_hdr_size(kvm->session);
1523
1524
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);
1536 if (err)
1537 goto out;
1538
1539 err = kvm_events_live_report(kvm);
1540
1541out:
1542 exit_browser(0);
1543
1544 if (kvm->session)
1545 perf_session__delete(kvm->session);
1546 kvm->session = NULL;
1547 if (kvm->evlist) {
1548 perf_evlist__delete_maps(kvm->evlist);
1549 perf_evlist__delete(kvm->evlist);
1550 }
1551
1552 return err;
1553}
1554
878static void print_kvm_stat_usage(void) 1555static void print_kvm_stat_usage(void)
879{ 1556{
880 printf("Usage: perf kvm stat <command>\n\n"); 1557 printf("Usage: perf kvm stat <command>\n\n");
@@ -882,6 +1559,7 @@ static void print_kvm_stat_usage(void)
882 printf("# Available commands:\n"); 1559 printf("# Available commands:\n");
883 printf("\trecord: record kvm events\n"); 1560 printf("\trecord: record kvm events\n");
884 printf("\treport: report statistical data of kvm events\n"); 1561 printf("\treport: report statistical data of kvm events\n");
1562 printf("\tlive: live reporting of statistical data of kvm events\n");
885 1563
886 printf("\nOtherwise, it is the alias of 'perf stat':\n"); 1564 printf("\nOtherwise, it is the alias of 'perf stat':\n");
887} 1565}
@@ -911,6 +1589,9 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
911 if (!strncmp(argv[1], "rep", 3)) 1589 if (!strncmp(argv[1], "rep", 3))
912 return kvm_events_report(&kvm, argc - 1 , argv + 1); 1590 return kvm_events_report(&kvm, argc - 1 , argv + 1);
913 1591
1592 if (!strncmp(argv[1], "live", 4))
1593 return kvm_events_live(&kvm, argc - 1 , argv + 1);
1594
914perf_stat: 1595perf_stat:
915 return cmd_stat(argc, argv, NULL); 1596 return cmd_stat(argc, argv, NULL);
916} 1597}
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 1948eceb517a..e79f423cc302 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -13,6 +13,7 @@
13 13
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 17
17int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) 18int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
18{ 19{
@@ -37,6 +38,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
37 else if (strcmp(argv[i], "cache") == 0 || 38 else if (strcmp(argv[i], "cache") == 0 ||
38 strcmp(argv[i], "hwcache") == 0) 39 strcmp(argv[i], "hwcache") == 0)
39 print_hwcache_events(NULL, false); 40 print_hwcache_events(NULL, false);
41 else if (strcmp(argv[i], "pmu") == 0)
42 print_pmu_events(NULL, false);
40 else if (strcmp(argv[i], "--raw-dump") == 0) 43 else if (strcmp(argv[i], "--raw-dump") == 0)
41 print_events(NULL, true); 44 print_events(NULL, true);
42 else { 45 else {
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 425830069749..ee33ba2f05dd 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -805,7 +805,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
805 struct perf_evsel *evsel, 805 struct perf_evsel *evsel,
806 struct machine *machine) 806 struct machine *machine)
807{ 807{
808 struct thread *thread = machine__findnew_thread(machine, sample->tid); 808 struct thread *thread = machine__findnew_thread(machine, sample->pid,
809 sample->tid);
809 810
810 if (thread == NULL) { 811 if (thread == NULL) {
811 pr_debug("problem processing %d event, skipping it.\n", 812 pr_debug("problem processing %d event, skipping it.\n",
@@ -878,7 +879,7 @@ static int __cmd_report(void)
878static int __cmd_record(int argc, const char **argv) 879static int __cmd_record(int argc, const char **argv)
879{ 880{
880 const char *record_args[] = { 881 const char *record_args[] = {
881 "record", "-R", "-f", "-m", "1024", "-c", "1", 882 "record", "-R", "-m", "1024", "-c", "1",
882 }; 883 };
883 unsigned int rec_argc, i, j; 884 unsigned int rec_argc, i, j;
884 const char **rec_argv; 885 const char **rec_argv;
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index a8ff6d264e50..253133a6251d 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -14,7 +14,6 @@ static const char *mem_operation = MEM_OPERATION_LOAD;
14struct perf_mem { 14struct perf_mem {
15 struct perf_tool tool; 15 struct perf_tool tool;
16 char const *input_name; 16 char const *input_name;
17 symbol_filter_t annotate_init;
18 bool hide_unresolved; 17 bool hide_unresolved;
19 bool dump_raw; 18 bool dump_raw;
20 const char *cpu_list; 19 const char *cpu_list;
@@ -69,8 +68,7 @@ dump_raw_samples(struct perf_tool *tool,
69 struct addr_location al; 68 struct addr_location al;
70 const char *fmt; 69 const char *fmt;
71 70
72 if (perf_event__preprocess_sample(event, machine, &al, sample, 71 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
73 mem->annotate_init) < 0) {
74 fprintf(stderr, "problem processing %d event, skipping it.\n", 72 fprintf(stderr, "problem processing %d event, skipping it.\n",
75 event->header.type); 73 event->header.type);
76 return -1; 74 return -1;
@@ -96,7 +94,7 @@ dump_raw_samples(struct perf_tool *tool,
96 symbol_conf.field_sep, 94 symbol_conf.field_sep,
97 sample->tid, 95 sample->tid,
98 symbol_conf.field_sep, 96 symbol_conf.field_sep,
99 event->ip.ip, 97 sample->ip,
100 symbol_conf.field_sep, 98 symbol_conf.field_sep,
101 sample->addr, 99 sample->addr,
102 symbol_conf.field_sep, 100 symbol_conf.field_sep,
@@ -192,6 +190,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
192 .tool = { 190 .tool = {
193 .sample = process_sample_event, 191 .sample = process_sample_event,
194 .mmap = perf_event__process_mmap, 192 .mmap = perf_event__process_mmap,
193 .mmap2 = perf_event__process_mmap2,
195 .comm = perf_event__process_comm, 194 .comm = perf_event__process_comm,
196 .lost = perf_event__process_lost, 195 .lost = perf_event__process_lost,
197 .fork = perf_event__process_fork, 196 .fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index cdf58ecc04b1..a41ac41546c9 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -61,11 +61,6 @@ static void __handle_on_exit_funcs(void)
61} 61}
62#endif 62#endif
63 63
64enum write_mode_t {
65 WRITE_FORCE,
66 WRITE_APPEND
67};
68
69struct perf_record { 64struct perf_record {
70 struct perf_tool tool; 65 struct perf_tool tool;
71 struct perf_record_opts opts; 66 struct perf_record_opts opts;
@@ -77,12 +72,8 @@ struct perf_record {
77 int output; 72 int output;
78 unsigned int page_size; 73 unsigned int page_size;
79 int realtime_prio; 74 int realtime_prio;
80 enum write_mode_t write_mode;
81 bool no_buildid; 75 bool no_buildid;
82 bool no_buildid_cache; 76 bool no_buildid_cache;
83 bool force;
84 bool file_new;
85 bool append_file;
86 long samples; 77 long samples;
87 off_t post_processing_offset; 78 off_t post_processing_offset;
88}; 79};
@@ -198,26 +189,6 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
198 return; 189 return;
199 190
200 signal(signr, SIG_DFL); 191 signal(signr, SIG_DFL);
201 kill(getpid(), signr);
202}
203
204static bool perf_evlist__equal(struct perf_evlist *evlist,
205 struct perf_evlist *other)
206{
207 struct perf_evsel *pos, *pair;
208
209 if (evlist->nr_entries != other->nr_entries)
210 return false;
211
212 pair = perf_evlist__first(other);
213
214 list_for_each_entry(pos, &evlist->entries, node) {
215 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
216 return false;
217 pair = perf_evsel__next(pair);
218 }
219
220 return true;
221} 192}
222 193
223static int perf_record__open(struct perf_record *rec) 194static int perf_record__open(struct perf_record *rec)
@@ -274,16 +245,7 @@ try_again:
274 goto out; 245 goto out;
275 } 246 }
276 247
277 if (rec->file_new) 248 session->evlist = evlist;
278 session->evlist = evlist;
279 else {
280 if (!perf_evlist__equal(session->evlist, evlist)) {
281 fprintf(stderr, "incompatible append\n");
282 rc = -1;
283 goto out;
284 }
285 }
286
287 perf_session__set_id_hdr_size(session); 249 perf_session__set_id_hdr_size(session);
288out: 250out:
289 return rc; 251 return rc;
@@ -404,6 +366,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
404 signal(SIGCHLD, sig_handler); 366 signal(SIGCHLD, sig_handler);
405 signal(SIGINT, sig_handler); 367 signal(SIGINT, sig_handler);
406 signal(SIGUSR1, sig_handler); 368 signal(SIGUSR1, sig_handler);
369 signal(SIGTERM, sig_handler);
407 370
408 if (!output_name) { 371 if (!output_name) {
409 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) 372 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
@@ -415,23 +378,15 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
415 if (!strcmp(output_name, "-")) 378 if (!strcmp(output_name, "-"))
416 opts->pipe_output = true; 379 opts->pipe_output = true;
417 else if (!stat(output_name, &st) && st.st_size) { 380 else if (!stat(output_name, &st) && st.st_size) {
418 if (rec->write_mode == WRITE_FORCE) { 381 char oldname[PATH_MAX];
419 char oldname[PATH_MAX]; 382 snprintf(oldname, sizeof(oldname), "%s.old",
420 snprintf(oldname, sizeof(oldname), "%s.old", 383 output_name);
421 output_name); 384 unlink(oldname);
422 unlink(oldname); 385 rename(output_name, oldname);
423 rename(output_name, oldname);
424 }
425 } else if (rec->write_mode == WRITE_APPEND) {
426 rec->write_mode = WRITE_FORCE;
427 } 386 }
428 } 387 }
429 388
430 flags = O_CREAT|O_RDWR; 389 flags = O_CREAT|O_RDWR|O_TRUNC;
431 if (rec->write_mode == WRITE_APPEND)
432 rec->file_new = 0;
433 else
434 flags |= O_TRUNC;
435 390
436 if (opts->pipe_output) 391 if (opts->pipe_output)
437 output = STDOUT_FILENO; 392 output = STDOUT_FILENO;
@@ -445,7 +400,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
445 rec->output = output; 400 rec->output = output;
446 401
447 session = perf_session__new(output_name, O_WRONLY, 402 session = perf_session__new(output_name, O_WRONLY,
448 rec->write_mode == WRITE_FORCE, false, NULL); 403 true, false, NULL);
449 if (session == NULL) { 404 if (session == NULL) {
450 pr_err("Not enough memory for reading perf file header\n"); 405 pr_err("Not enough memory for reading perf file header\n");
451 return -1; 406 return -1;
@@ -465,12 +420,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
465 if (!rec->opts.branch_stack) 420 if (!rec->opts.branch_stack)
466 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); 421 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
467 422
468 if (!rec->file_new) {
469 err = perf_session__read_header(session, output);
470 if (err < 0)
471 goto out_delete_session;
472 }
473
474 if (forks) { 423 if (forks) {
475 err = perf_evlist__prepare_workload(evsel_list, &opts->target, 424 err = perf_evlist__prepare_workload(evsel_list, &opts->target,
476 argv, opts->pipe_output, 425 argv, opts->pipe_output,
@@ -498,7 +447,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
498 err = perf_header__write_pipe(output); 447 err = perf_header__write_pipe(output);
499 if (err < 0) 448 if (err < 0)
500 goto out_delete_session; 449 goto out_delete_session;
501 } else if (rec->file_new) { 450 } else {
502 err = perf_session__write_header(session, evsel_list, 451 err = perf_session__write_header(session, evsel_list,
503 output, false); 452 output, false);
504 if (err < 0) 453 if (err < 0)
@@ -525,13 +474,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
525 goto out_delete_session; 474 goto out_delete_session;
526 } 475 }
527 476
528 err = perf_event__synthesize_event_types(tool, process_synthesized_event,
529 machine);
530 if (err < 0) {
531 pr_err("Couldn't synthesize event_types.\n");
532 goto out_delete_session;
533 }
534
535 if (have_tracepoints(&evsel_list->entries)) { 477 if (have_tracepoints(&evsel_list->entries)) {
536 /* 478 /*
537 * FIXME err <= 0 here actually means that 479 * FIXME err <= 0 here actually means that
@@ -869,8 +811,6 @@ static struct perf_record record = {
869 .uses_mmap = true, 811 .uses_mmap = true,
870 }, 812 },
871 }, 813 },
872 .write_mode = WRITE_FORCE,
873 .file_new = true,
874}; 814};
875 815
876#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " 816#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
@@ -906,12 +846,8 @@ const struct option record_options[] = {
906 "collect raw sample records from all opened counters"), 846 "collect raw sample records from all opened counters"),
907 OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide, 847 OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
908 "system-wide collection from all CPUs"), 848 "system-wide collection from all CPUs"),
909 OPT_BOOLEAN('A', "append", &record.append_file,
910 "append to the output file to do incremental profiling"),
911 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", 849 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
912 "list of cpus to monitor"), 850 "list of cpus to monitor"),
913 OPT_BOOLEAN('f', "force", &record.force,
914 "overwrite existing data file (deprecated)"),
915 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 851 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
916 OPT_STRING('o', "output", &record.output_name, "file", 852 OPT_STRING('o', "output", &record.output_name, "file",
917 "output file name"), 853 "output file name"),
@@ -961,7 +897,6 @@ const struct option record_options[] = {
961int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 897int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
962{ 898{
963 int err = -ENOMEM; 899 int err = -ENOMEM;
964 struct perf_evsel *pos;
965 struct perf_evlist *evsel_list; 900 struct perf_evlist *evsel_list;
966 struct perf_record *rec = &record; 901 struct perf_record *rec = &record;
967 char errbuf[BUFSIZ]; 902 char errbuf[BUFSIZ];
@@ -977,16 +912,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
977 if (!argc && perf_target__none(&rec->opts.target)) 912 if (!argc && perf_target__none(&rec->opts.target))
978 usage_with_options(record_usage, record_options); 913 usage_with_options(record_usage, record_options);
979 914
980 if (rec->force && rec->append_file) {
981 ui__error("Can't overwrite and append at the same time."
982 " You need to choose between -f and -A");
983 usage_with_options(record_usage, record_options);
984 } else if (rec->append_file) {
985 rec->write_mode = WRITE_APPEND;
986 } else {
987 rec->write_mode = WRITE_FORCE;
988 }
989
990 if (nr_cgroups && !rec->opts.target.system_wide) { 915 if (nr_cgroups && !rec->opts.target.system_wide) {
991 ui__error("cgroup monitoring only available in" 916 ui__error("cgroup monitoring only available in"
992 " system-wide mode\n"); 917 " system-wide mode\n");
@@ -1035,11 +960,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1035 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) 960 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
1036 usage_with_options(record_usage, record_options); 961 usage_with_options(record_usage, record_options);
1037 962
1038 list_for_each_entry(pos, &evsel_list->entries, node) {
1039 if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
1040 goto out_free_fd;
1041 }
1042
1043 if (rec->opts.user_interval != ULLONG_MAX) 963 if (rec->opts.user_interval != ULLONG_MAX)
1044 rec->opts.default_interval = rec->opts.user_interval; 964 rec->opts.default_interval = rec->opts.user_interval;
1045 if (rec->opts.user_freq != UINT_MAX) 965 if (rec->opts.user_freq != UINT_MAX)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index bd0ca81eeaca..72eae7498c09 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -49,9 +49,9 @@ struct perf_report {
49 bool mem_mode; 49 bool mem_mode;
50 struct perf_read_values show_threads_values; 50 struct perf_read_values show_threads_values;
51 const char *pretty_printing_style; 51 const char *pretty_printing_style;
52 symbol_filter_t annotate_init;
53 const char *cpu_list; 52 const char *cpu_list;
54 const char *symbol_filter_str; 53 const char *symbol_filter_str;
54 float min_percent;
55 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 55 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
56}; 56};
57 57
@@ -61,6 +61,11 @@ static int perf_report_config(const char *var, const char *value, void *cb)
61 symbol_conf.event_group = perf_config_bool(var, value); 61 symbol_conf.event_group = perf_config_bool(var, value);
62 return 0; 62 return 0;
63 } 63 }
64 if (!strcmp(var, "report.percent-limit")) {
65 struct perf_report *rep = cb;
66 rep->min_percent = strtof(value, NULL);
67 return 0;
68 }
64 69
65 return perf_default_config(var, value, cb); 70 return perf_default_config(var, value, cb);
66} 71}
@@ -83,7 +88,7 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
83 if ((sort__has_parent || symbol_conf.use_callchain) && 88 if ((sort__has_parent || symbol_conf.use_callchain) &&
84 sample->callchain) { 89 sample->callchain) {
85 err = machine__resolve_callchain(machine, evsel, al->thread, 90 err = machine__resolve_callchain(machine, evsel, al->thread,
86 sample, &parent); 91 sample, &parent, al);
87 if (err) 92 if (err)
88 return err; 93 return err;
89 } 94 }
@@ -174,7 +179,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
174 if ((sort__has_parent || symbol_conf.use_callchain) 179 if ((sort__has_parent || symbol_conf.use_callchain)
175 && sample->callchain) { 180 && sample->callchain) {
176 err = machine__resolve_callchain(machine, evsel, al->thread, 181 err = machine__resolve_callchain(machine, evsel, al->thread,
177 sample, &parent); 182 sample, &parent, al);
178 if (err) 183 if (err)
179 return err; 184 return err;
180 } 185 }
@@ -187,6 +192,9 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
187 for (i = 0; i < sample->branch_stack->nr; i++) { 192 for (i = 0; i < sample->branch_stack->nr; i++) {
188 if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym)) 193 if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
189 continue; 194 continue;
195
196 err = -ENOMEM;
197
190 /* 198 /*
191 * The report shows the percentage of total branches captured 199 * The report shows the percentage of total branches captured
192 * and not events sampled. Thus we use a pseudo period of 1. 200 * and not events sampled. Thus we use a pseudo period of 1.
@@ -195,7 +203,6 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
195 &bi[i], 1, 1); 203 &bi[i], 1, 1);
196 if (he) { 204 if (he) {
197 struct annotation *notes; 205 struct annotation *notes;
198 err = -ENOMEM;
199 bx = he->branch_info; 206 bx = he->branch_info;
200 if (bx->from.sym && use_browser == 1 && sort__has_sym) { 207 if (bx->from.sym && use_browser == 1 && sort__has_sym) {
201 notes = symbol__annotation(bx->from.sym); 208 notes = symbol__annotation(bx->from.sym);
@@ -226,11 +233,12 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
226 } 233 }
227 evsel->hists.stats.total_period += 1; 234 evsel->hists.stats.total_period += 1;
228 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 235 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
229 err = 0;
230 } else 236 } else
231 return -ENOMEM; 237 goto out;
232 } 238 }
239 err = 0;
233out: 240out:
241 free(bi);
234 return err; 242 return err;
235} 243}
236 244
@@ -245,7 +253,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
245 253
246 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 254 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
247 err = machine__resolve_callchain(machine, evsel, al->thread, 255 err = machine__resolve_callchain(machine, evsel, al->thread,
248 sample, &parent); 256 sample, &parent, al);
249 if (err) 257 if (err)
250 return err; 258 return err;
251 } 259 }
@@ -294,9 +302,9 @@ static int process_sample_event(struct perf_tool *tool,
294{ 302{
295 struct perf_report *rep = container_of(tool, struct perf_report, tool); 303 struct perf_report *rep = container_of(tool, struct perf_report, tool);
296 struct addr_location al; 304 struct addr_location al;
305 int ret;
297 306
298 if (perf_event__preprocess_sample(event, machine, &al, sample, 307 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
299 rep->annotate_init) < 0) {
300 fprintf(stderr, "problem processing %d event, skipping it.\n", 308 fprintf(stderr, "problem processing %d event, skipping it.\n",
301 event->header.type); 309 event->header.type);
302 return -1; 310 return -1;
@@ -308,28 +316,25 @@ static int process_sample_event(struct perf_tool *tool,
308 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) 316 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
309 return 0; 317 return 0;
310 318
311 if (sort__branch_mode == 1) { 319 if (sort__mode == SORT_MODE__BRANCH) {
312 if (perf_report__add_branch_hist_entry(tool, &al, sample, 320 ret = perf_report__add_branch_hist_entry(tool, &al, sample,
313 evsel, machine)) { 321 evsel, machine);
322 if (ret < 0)
314 pr_debug("problem adding lbr entry, skipping event\n"); 323 pr_debug("problem adding lbr entry, skipping event\n");
315 return -1;
316 }
317 } else if (rep->mem_mode == 1) { 324 } else if (rep->mem_mode == 1) {
318 if (perf_report__add_mem_hist_entry(tool, &al, sample, 325 ret = perf_report__add_mem_hist_entry(tool, &al, sample,
319 evsel, machine, event)) { 326 evsel, machine, event);
327 if (ret < 0)
320 pr_debug("problem adding mem entry, skipping event\n"); 328 pr_debug("problem adding mem entry, skipping event\n");
321 return -1;
322 }
323 } else { 329 } else {
324 if (al.map != NULL) 330 if (al.map != NULL)
325 al.map->dso->hit = 1; 331 al.map->dso->hit = 1;
326 332
327 if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) { 333 ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine);
334 if (ret < 0)
328 pr_debug("problem incrementing symbol period, skipping event\n"); 335 pr_debug("problem incrementing symbol period, skipping event\n");
329 return -1;
330 }
331 } 336 }
332 return 0; 337 return ret;
333} 338}
334 339
335static int process_read_event(struct perf_tool *tool, 340static int process_read_event(struct perf_tool *tool,
@@ -360,7 +365,7 @@ static int process_read_event(struct perf_tool *tool,
360static int perf_report__setup_sample_type(struct perf_report *rep) 365static int perf_report__setup_sample_type(struct perf_report *rep)
361{ 366{
362 struct perf_session *self = rep->session; 367 struct perf_session *self = rep->session;
363 u64 sample_type = perf_evlist__sample_type(self->evlist); 368 u64 sample_type = perf_evlist__combined_sample_type(self->evlist);
364 369
365 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { 370 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
366 if (sort__has_parent) { 371 if (sort__has_parent) {
@@ -384,7 +389,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
384 } 389 }
385 } 390 }
386 391
387 if (sort__branch_mode == 1) { 392 if (sort__mode == SORT_MODE__BRANCH) {
388 if (!self->fd_pipe && 393 if (!self->fd_pipe &&
389 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { 394 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
390 ui__error("Selected -b but no branch data. " 395 ui__error("Selected -b but no branch data. "
@@ -396,8 +401,6 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
396 return 0; 401 return 0;
397} 402}
398 403
399extern volatile int session_done;
400
401static void sig_handler(int sig __maybe_unused) 404static void sig_handler(int sig __maybe_unused)
402{ 405{
403 session_done = 1; 406 session_done = 1;
@@ -455,7 +458,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
455 continue; 458 continue;
456 459
457 hists__fprintf_nr_sample_events(rep, hists, evname, stdout); 460 hists__fprintf_nr_sample_events(rep, hists, evname, stdout);
458 hists__fprintf(hists, true, 0, 0, stdout); 461 hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
459 fprintf(stdout, "\n\n"); 462 fprintf(stdout, "\n\n");
460 } 463 }
461 464
@@ -490,7 +493,7 @@ static int __cmd_report(struct perf_report *rep)
490 ret = perf_session__cpu_bitmap(session, rep->cpu_list, 493 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
491 rep->cpu_bitmap); 494 rep->cpu_bitmap);
492 if (ret) 495 if (ret)
493 goto out_delete; 496 return ret;
494 } 497 }
495 498
496 if (use_browser <= 0) 499 if (use_browser <= 0)
@@ -501,11 +504,11 @@ static int __cmd_report(struct perf_report *rep)
501 504
502 ret = perf_report__setup_sample_type(rep); 505 ret = perf_report__setup_sample_type(rep);
503 if (ret) 506 if (ret)
504 goto out_delete; 507 return ret;
505 508
506 ret = perf_session__process_events(session, &rep->tool); 509 ret = perf_session__process_events(session, &rep->tool);
507 if (ret) 510 if (ret)
508 goto out_delete; 511 return ret;
509 512
510 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; 513 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
511 kernel_kmap = map__kmap(kernel_map); 514 kernel_kmap = map__kmap(kernel_map);
@@ -540,7 +543,7 @@ static int __cmd_report(struct perf_report *rep)
540 543
541 if (dump_trace) { 544 if (dump_trace) {
542 perf_session__fprintf_nr_events(session, stdout); 545 perf_session__fprintf_nr_events(session, stdout);
543 goto out_delete; 546 return 0;
544 } 547 }
545 548
546 nr_samples = 0; 549 nr_samples = 0;
@@ -563,9 +566,12 @@ static int __cmd_report(struct perf_report *rep)
563 } 566 }
564 } 567 }
565 568
569 if (session_done())
570 return 0;
571
566 if (nr_samples == 0) { 572 if (nr_samples == 0) {
567 ui__error("The %s file has no samples!\n", session->filename); 573 ui__error("The %s file has no samples!\n", session->filename);
568 goto out_delete; 574 return 0;
569 } 575 }
570 576
571 list_for_each_entry(pos, &session->evlist->entries, node) 577 list_for_each_entry(pos, &session->evlist->entries, node)
@@ -574,8 +580,8 @@ static int __cmd_report(struct perf_report *rep)
574 if (use_browser > 0) { 580 if (use_browser > 0) {
575 if (use_browser == 1) { 581 if (use_browser == 1) {
576 ret = perf_evlist__tui_browse_hists(session->evlist, 582 ret = perf_evlist__tui_browse_hists(session->evlist,
577 help, 583 help, NULL,
578 NULL, 584 rep->min_percent,
579 &session->header.env); 585 &session->header.env);
580 /* 586 /*
581 * Usually "ret" is the last pressed key, and we only 587 * Usually "ret" is the last pressed key, and we only
@@ -586,24 +592,11 @@ static int __cmd_report(struct perf_report *rep)
586 592
587 } else if (use_browser == 2) { 593 } else if (use_browser == 2) {
588 perf_evlist__gtk_browse_hists(session->evlist, help, 594 perf_evlist__gtk_browse_hists(session->evlist, help,
589 NULL); 595 NULL, rep->min_percent);
590 } 596 }
591 } else 597 } else
592 perf_evlist__tty_browse_hists(session->evlist, rep, help); 598 perf_evlist__tty_browse_hists(session->evlist, rep, help);
593 599
594out_delete:
595 /*
596 * Speed up the exit process, for large files this can
597 * take quite a while.
598 *
599 * XXX Enable this when using valgrind or if we ever
600 * librarize this command.
601 *
602 * Also experiment with obstacks to see how much speed
603 * up we'll get here.
604 *
605 * perf_session__delete(session);
606 */
607 return ret; 600 return ret;
608} 601}
609 602
@@ -673,12 +666,23 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
673 } 666 }
674 667
675 /* get the call chain order */ 668 /* get the call chain order */
676 if (!strcmp(tok2, "caller")) 669 if (!strncmp(tok2, "caller", strlen("caller")))
677 callchain_param.order = ORDER_CALLER; 670 callchain_param.order = ORDER_CALLER;
678 else if (!strcmp(tok2, "callee")) 671 else if (!strncmp(tok2, "callee", strlen("callee")))
679 callchain_param.order = ORDER_CALLEE; 672 callchain_param.order = ORDER_CALLEE;
680 else 673 else
681 return -1; 674 return -1;
675
676 /* Get the sort key */
677 tok2 = strtok(NULL, ",");
678 if (!tok2)
679 goto setup;
680 if (!strncmp(tok2, "function", strlen("function")))
681 callchain_param.key = CCKEY_FUNCTION;
682 else if (!strncmp(tok2, "address", strlen("address")))
683 callchain_param.key = CCKEY_ADDRESS;
684 else
685 return -1;
682setup: 686setup:
683 if (callchain_register_param(&callchain_param) < 0) { 687 if (callchain_register_param(&callchain_param) < 0) {
684 fprintf(stderr, "Can't register callchain params\n"); 688 fprintf(stderr, "Can't register callchain params\n");
@@ -687,11 +691,41 @@ setup:
687 return 0; 691 return 0;
688} 692}
689 693
694int
695report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
696 const char *arg, int unset __maybe_unused)
697{
698 if (arg) {
699 int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED);
700 if (err) {
701 char buf[BUFSIZ];
702 regerror(err, &ignore_callees_regex, buf, sizeof(buf));
703 pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf);
704 return -1;
705 }
706 have_ignore_callees = 1;
707 }
708
709 return 0;
710}
711
690static int 712static int
691parse_branch_mode(const struct option *opt __maybe_unused, 713parse_branch_mode(const struct option *opt __maybe_unused,
692 const char *str __maybe_unused, int unset) 714 const char *str __maybe_unused, int unset)
693{ 715{
694 sort__branch_mode = !unset; 716 int *branch_mode = opt->value;
717
718 *branch_mode = !unset;
719 return 0;
720}
721
722static int
723parse_percent_limit(const struct option *opt, const char *str,
724 int unset __maybe_unused)
725{
726 struct perf_report *rep = opt->value;
727
728 rep->min_percent = strtof(str, NULL);
695 return 0; 729 return 0;
696} 730}
697 731
@@ -700,6 +734,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
700 struct perf_session *session; 734 struct perf_session *session;
701 struct stat st; 735 struct stat st;
702 bool has_br_stack = false; 736 bool has_br_stack = false;
737 int branch_mode = -1;
703 int ret = -1; 738 int ret = -1;
704 char callchain_default_opt[] = "fractal,0.5,callee"; 739 char callchain_default_opt[] = "fractal,0.5,callee";
705 const char * const report_usage[] = { 740 const char * const report_usage[] = {
@@ -710,13 +745,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
710 .tool = { 745 .tool = {
711 .sample = process_sample_event, 746 .sample = process_sample_event,
712 .mmap = perf_event__process_mmap, 747 .mmap = perf_event__process_mmap,
748 .mmap2 = perf_event__process_mmap2,
713 .comm = perf_event__process_comm, 749 .comm = perf_event__process_comm,
714 .exit = perf_event__process_exit, 750 .exit = perf_event__process_exit,
715 .fork = perf_event__process_fork, 751 .fork = perf_event__process_fork,
716 .lost = perf_event__process_lost, 752 .lost = perf_event__process_lost,
717 .read = process_read_event, 753 .read = process_read_event,
718 .attr = perf_event__process_attr, 754 .attr = perf_event__process_attr,
719 .event_type = perf_event__process_event_type,
720 .tracing_data = perf_event__process_tracing_data, 755 .tracing_data = perf_event__process_tracing_data,
721 .build_id = perf_event__process_build_id, 756 .build_id = perf_event__process_build_id,
722 .ordered_samples = true, 757 .ordered_samples = true,
@@ -760,10 +795,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
760 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 795 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
761 "Only display entries with parent-match"), 796 "Only display entries with parent-match"),
762 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 797 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
763 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit and callchain order. " 798 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
764 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), 799 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
765 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, 800 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
766 "alias for inverted call graph"), 801 "alias for inverted call graph"),
802 OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
803 "ignore callees of these functions in call graphs",
804 report_parse_ignore_callees_opt),
767 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 805 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
768 "only consider symbols in these dsos"), 806 "only consider symbols in these dsos"),
769 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 807 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
@@ -796,17 +834,19 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
796 "Show a column with the sum of periods"), 834 "Show a column with the sum of periods"),
797 OPT_BOOLEAN(0, "group", &symbol_conf.event_group, 835 OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
798 "Show event group information together"), 836 "Show event group information together"),
799 OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "", 837 OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
800 "use branch records for histogram filling", parse_branch_mode), 838 "use branch records for histogram filling", parse_branch_mode),
801 OPT_STRING(0, "objdump", &objdump_path, "path", 839 OPT_STRING(0, "objdump", &objdump_path, "path",
802 "objdump binary to use for disassembly and annotations"), 840 "objdump binary to use for disassembly and annotations"),
803 OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, 841 OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
804 "Disable symbol demangling"), 842 "Disable symbol demangling"),
805 OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), 843 OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
844 OPT_CALLBACK(0, "percent-limit", &report, "percent",
845 "Don't show entries under that percent", parse_percent_limit),
806 OPT_END() 846 OPT_END()
807 }; 847 };
808 848
809 perf_config(perf_report_config, NULL); 849 perf_config(perf_report_config, &report);
810 850
811 argc = parse_options(argc, argv, options, report_usage, 0); 851 argc = parse_options(argc, argv, options, report_usage, 0);
812 852
@@ -831,7 +871,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
831 setup_browser(true); 871 setup_browser(true);
832 else { 872 else {
833 use_browser = 0; 873 use_browser = 0;
834 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
835 perf_hpp__init(); 874 perf_hpp__init();
836 } 875 }
837 876
@@ -846,11 +885,11 @@ repeat:
846 has_br_stack = perf_header__has_feat(&session->header, 885 has_br_stack = perf_header__has_feat(&session->header,
847 HEADER_BRANCH_STACK); 886 HEADER_BRANCH_STACK);
848 887
849 if (sort__branch_mode == -1 && has_br_stack) 888 if (branch_mode == -1 && has_br_stack)
850 sort__branch_mode = 1; 889 sort__mode = SORT_MODE__BRANCH;
851 890
852 /* sort__branch_mode could be 0 if --no-branch-stack */ 891 /* sort__mode could be NORMAL if --no-branch-stack */
853 if (sort__branch_mode == 1) { 892 if (sort__mode == SORT_MODE__BRANCH) {
854 /* 893 /*
855 * if no sort_order is provided, then specify 894 * if no sort_order is provided, then specify
856 * branch-mode specific order 895 * branch-mode specific order
@@ -861,10 +900,12 @@ repeat:
861 900
862 } 901 }
863 if (report.mem_mode) { 902 if (report.mem_mode) {
864 if (sort__branch_mode == 1) { 903 if (sort__mode == SORT_MODE__BRANCH) {
865 fprintf(stderr, "branch and mem mode incompatible\n"); 904 fprintf(stderr, "branch and mem mode incompatible\n");
866 goto error; 905 goto error;
867 } 906 }
907 sort__mode = SORT_MODE__MEMORY;
908
868 /* 909 /*
869 * if no sort_order is provided, then specify 910 * if no sort_order is provided, then specify
870 * branch-mode specific order 911 * branch-mode specific order
@@ -883,7 +924,8 @@ repeat:
883 */ 924 */
884 if (use_browser == 1 && sort__has_sym) { 925 if (use_browser == 1 && sort__has_sym) {
885 symbol_conf.priv_size = sizeof(struct annotation); 926 symbol_conf.priv_size = sizeof(struct annotation);
886 report.annotate_init = symbol__annotate_init; 927 machines__set_symbol_filter(&session->machines,
928 symbol__annotate_init);
887 /* 929 /*
888 * For searching by name on the "Browse map details". 930 * For searching by name on the "Browse map details".
889 * providing it only in verbose mode not to bloat too 931 * providing it only in verbose mode not to bloat too
@@ -907,16 +949,7 @@ repeat:
907 if (parent_pattern != default_parent_pattern) { 949 if (parent_pattern != default_parent_pattern) {
908 if (sort_dimension__add("parent") < 0) 950 if (sort_dimension__add("parent") < 0)
909 goto error; 951 goto error;
910 952 }
911 /*
912 * Only show the parent fields if we explicitly
913 * sort that way. If we only use parent machinery
914 * for filtering, we don't want it.
915 */
916 if (!strstr(sort_order, "parent"))
917 sort_parent.elide = 1;
918 } else
919 symbol_conf.exclude_other = false;
920 953
921 if (argc) { 954 if (argc) {
922 /* 955 /*
@@ -929,25 +962,7 @@ repeat:
929 report.symbol_filter_str = argv[0]; 962 report.symbol_filter_str = argv[0];
930 } 963 }
931 964
932 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); 965 sort__setup_elide(stdout);
933
934 if (sort__branch_mode == 1) {
935 sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout);
936 sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout);
937 sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
938 sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
939 } else {
940 if (report.mem_mode) {
941 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "symbol_daddr", stdout);
942 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso_daddr", stdout);
943 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "mem", stdout);
944 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "local_weight", stdout);
945 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "tlb", stdout);
946 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "snoop", stdout);
947 }
948 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
949 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
950 }
951 966
952 ret = __cmd_report(&report); 967 ret = __cmd_report(&report);
953 if (ret == K_SWITCH_INPUT_DATA) { 968 if (ret == K_SWITCH_INPUT_DATA) {
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 2da2a6ca22bf..d8c51b2f263f 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -109,8 +109,9 @@ struct trace_sched_handler {
109 int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel, 109 int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel,
110 struct perf_sample *sample, struct machine *machine); 110 struct perf_sample *sample, struct machine *machine);
111 111
112 int (*fork_event)(struct perf_sched *sched, struct perf_evsel *evsel, 112 /* PERF_RECORD_FORK event, not sched_process_fork tracepoint */
113 struct perf_sample *sample); 113 int (*fork_event)(struct perf_sched *sched, union perf_event *event,
114 struct machine *machine);
114 115
115 int (*migrate_task_event)(struct perf_sched *sched, 116 int (*migrate_task_event)(struct perf_sched *sched,
116 struct perf_evsel *evsel, 117 struct perf_evsel *evsel,
@@ -717,22 +718,31 @@ static int replay_switch_event(struct perf_sched *sched,
717 return 0; 718 return 0;
718} 719}
719 720
720static int replay_fork_event(struct perf_sched *sched, struct perf_evsel *evsel, 721static int replay_fork_event(struct perf_sched *sched,
721 struct perf_sample *sample) 722 union perf_event *event,
723 struct machine *machine)
722{ 724{
723 const char *parent_comm = perf_evsel__strval(evsel, sample, "parent_comm"), 725 struct thread *child, *parent;
724 *child_comm = perf_evsel__strval(evsel, sample, "child_comm"); 726
725 const u32 parent_pid = perf_evsel__intval(evsel, sample, "parent_pid"), 727 child = machine__findnew_thread(machine, event->fork.pid,
726 child_pid = perf_evsel__intval(evsel, sample, "child_pid"); 728 event->fork.tid);
729 parent = machine__findnew_thread(machine, event->fork.ppid,
730 event->fork.ptid);
731
732 if (child == NULL || parent == NULL) {
733 pr_debug("thread does not exist on fork event: child %p, parent %p\n",
734 child, parent);
735 return 0;
736 }
727 737
728 if (verbose) { 738 if (verbose) {
729 printf("sched_fork event %p\n", evsel); 739 printf("fork event\n");
730 printf("... parent: %s/%d\n", parent_comm, parent_pid); 740 printf("... parent: %s/%d\n", parent->comm, parent->tid);
731 printf("... child: %s/%d\n", child_comm, child_pid); 741 printf("... child: %s/%d\n", child->comm, child->tid);
732 } 742 }
733 743
734 register_pid(sched, parent_pid, parent_comm); 744 register_pid(sched, parent->tid, parent->comm);
735 register_pid(sched, child_pid, child_comm); 745 register_pid(sched, child->tid, child->comm);
736 return 0; 746 return 0;
737} 747}
738 748
@@ -824,14 +834,6 @@ static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread)
824 return 0; 834 return 0;
825} 835}
826 836
827static int latency_fork_event(struct perf_sched *sched __maybe_unused,
828 struct perf_evsel *evsel __maybe_unused,
829 struct perf_sample *sample __maybe_unused)
830{
831 /* should insert the newcomer */
832 return 0;
833}
834
835static char sched_out_state(u64 prev_state) 837static char sched_out_state(u64 prev_state)
836{ 838{
837 const char *str = TASK_STATE_TO_CHAR_STR; 839 const char *str = TASK_STATE_TO_CHAR_STR;
@@ -934,8 +936,8 @@ static int latency_switch_event(struct perf_sched *sched,
934 return -1; 936 return -1;
935 } 937 }
936 938
937 sched_out = machine__findnew_thread(machine, prev_pid); 939 sched_out = machine__findnew_thread(machine, 0, prev_pid);
938 sched_in = machine__findnew_thread(machine, next_pid); 940 sched_in = machine__findnew_thread(machine, 0, next_pid);
939 941
940 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); 942 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
941 if (!out_events) { 943 if (!out_events) {
@@ -978,7 +980,7 @@ static int latency_runtime_event(struct perf_sched *sched,
978{ 980{
979 const u32 pid = perf_evsel__intval(evsel, sample, "pid"); 981 const u32 pid = perf_evsel__intval(evsel, sample, "pid");
980 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 982 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
981 struct thread *thread = machine__findnew_thread(machine, pid); 983 struct thread *thread = machine__findnew_thread(machine, 0, pid);
982 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); 984 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
983 u64 timestamp = sample->time; 985 u64 timestamp = sample->time;
984 int cpu = sample->cpu; 986 int cpu = sample->cpu;
@@ -1016,7 +1018,7 @@ static int latency_wakeup_event(struct perf_sched *sched,
1016 if (!success) 1018 if (!success)
1017 return 0; 1019 return 0;
1018 1020
1019 wakee = machine__findnew_thread(machine, pid); 1021 wakee = machine__findnew_thread(machine, 0, pid);
1020 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 1022 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
1021 if (!atoms) { 1023 if (!atoms) {
1022 if (thread_atoms_insert(sched, wakee)) 1024 if (thread_atoms_insert(sched, wakee))
@@ -1070,12 +1072,12 @@ static int latency_migrate_task_event(struct perf_sched *sched,
1070 if (sched->profile_cpu == -1) 1072 if (sched->profile_cpu == -1)
1071 return 0; 1073 return 0;
1072 1074
1073 migrant = machine__findnew_thread(machine, pid); 1075 migrant = machine__findnew_thread(machine, 0, pid);
1074 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1076 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1075 if (!atoms) { 1077 if (!atoms) {
1076 if (thread_atoms_insert(sched, migrant)) 1078 if (thread_atoms_insert(sched, migrant))
1077 return -1; 1079 return -1;
1078 register_pid(sched, migrant->pid, migrant->comm); 1080 register_pid(sched, migrant->tid, migrant->comm);
1079 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1081 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
1080 if (!atoms) { 1082 if (!atoms) {
1081 pr_err("migration-event: Internal tree error"); 1083 pr_err("migration-event: Internal tree error");
@@ -1115,7 +1117,7 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
1115 sched->all_runtime += work_list->total_runtime; 1117 sched->all_runtime += work_list->total_runtime;
1116 sched->all_count += work_list->nb_atoms; 1118 sched->all_count += work_list->nb_atoms;
1117 1119
1118 ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid); 1120 ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->tid);
1119 1121
1120 for (i = 0; i < 24 - ret; i++) 1122 for (i = 0; i < 24 - ret; i++)
1121 printf(" "); 1123 printf(" ");
@@ -1131,9 +1133,9 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
1131 1133
1132static int pid_cmp(struct work_atoms *l, struct work_atoms *r) 1134static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
1133{ 1135{
1134 if (l->thread->pid < r->thread->pid) 1136 if (l->thread->tid < r->thread->tid)
1135 return -1; 1137 return -1;
1136 if (l->thread->pid > r->thread->pid) 1138 if (l->thread->tid > r->thread->tid)
1137 return 1; 1139 return 1;
1138 1140
1139 return 0; 1141 return 0;
@@ -1289,8 +1291,8 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1289 return -1; 1291 return -1;
1290 } 1292 }
1291 1293
1292 sched_out = machine__findnew_thread(machine, prev_pid); 1294 sched_out = machine__findnew_thread(machine, 0, prev_pid);
1293 sched_in = machine__findnew_thread(machine, next_pid); 1295 sched_in = machine__findnew_thread(machine, 0, next_pid);
1294 1296
1295 sched->curr_thread[this_cpu] = sched_in; 1297 sched->curr_thread[this_cpu] = sched_in;
1296 1298
@@ -1321,7 +1323,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1321 printf("*"); 1323 printf("*");
1322 1324
1323 if (sched->curr_thread[cpu]) { 1325 if (sched->curr_thread[cpu]) {
1324 if (sched->curr_thread[cpu]->pid) 1326 if (sched->curr_thread[cpu]->tid)
1325 printf("%2s ", sched->curr_thread[cpu]->shortname); 1327 printf("%2s ", sched->curr_thread[cpu]->shortname);
1326 else 1328 else
1327 printf(". "); 1329 printf(". ");
@@ -1332,7 +1334,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1332 printf(" %12.6f secs ", (double)timestamp/1e9); 1334 printf(" %12.6f secs ", (double)timestamp/1e9);
1333 if (new_shortname) { 1335 if (new_shortname) {
1334 printf("%s => %s:%d\n", 1336 printf("%s => %s:%d\n",
1335 sched_in->shortname, sched_in->comm, sched_in->pid); 1337 sched_in->shortname, sched_in->comm, sched_in->tid);
1336 } else { 1338 } else {
1337 printf("\n"); 1339 printf("\n");
1338 } 1340 }
@@ -1379,25 +1381,20 @@ static int process_sched_runtime_event(struct perf_tool *tool,
1379 return 0; 1381 return 0;
1380} 1382}
1381 1383
1382static int process_sched_fork_event(struct perf_tool *tool, 1384static int perf_sched__process_fork_event(struct perf_tool *tool,
1383 struct perf_evsel *evsel, 1385 union perf_event *event,
1384 struct perf_sample *sample, 1386 struct perf_sample *sample,
1385 struct machine *machine __maybe_unused) 1387 struct machine *machine)
1386{ 1388{
1387 struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 1389 struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
1388 1390
1389 if (sched->tp_handler->fork_event) 1391 /* run the fork event through the perf machineruy */
1390 return sched->tp_handler->fork_event(sched, evsel, sample); 1392 perf_event__process_fork(tool, event, sample, machine);
1391 1393
1392 return 0; 1394 /* and then run additional processing needed for this command */
1393} 1395 if (sched->tp_handler->fork_event)
1396 return sched->tp_handler->fork_event(sched, event, machine);
1394 1397
1395static int process_sched_exit_event(struct perf_tool *tool __maybe_unused,
1396 struct perf_evsel *evsel,
1397 struct perf_sample *sample __maybe_unused,
1398 struct machine *machine __maybe_unused)
1399{
1400 pr_debug("sched_exit event %p\n", evsel);
1401 return 0; 1398 return 0;
1402} 1399}
1403 1400
@@ -1425,15 +1422,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
1425 struct perf_evsel *evsel, 1422 struct perf_evsel *evsel,
1426 struct machine *machine) 1423 struct machine *machine)
1427{ 1424{
1428 struct thread *thread = machine__findnew_thread(machine, sample->tid);
1429 int err = 0; 1425 int err = 0;
1430 1426
1431 if (thread == NULL) {
1432 pr_debug("problem processing %s event, skipping it.\n",
1433 perf_evsel__name(evsel));
1434 return -1;
1435 }
1436
1437 evsel->hists.stats.total_period += sample->period; 1427 evsel->hists.stats.total_period += sample->period;
1438 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 1428 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
1439 1429
@@ -1445,7 +1435,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
1445 return err; 1435 return err;
1446} 1436}
1447 1437
1448static int perf_sched__read_events(struct perf_sched *sched, bool destroy, 1438static int perf_sched__read_events(struct perf_sched *sched,
1449 struct perf_session **psession) 1439 struct perf_session **psession)
1450{ 1440{
1451 const struct perf_evsel_str_handler handlers[] = { 1441 const struct perf_evsel_str_handler handlers[] = {
@@ -1453,8 +1443,6 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
1453 { "sched:sched_stat_runtime", process_sched_runtime_event, }, 1443 { "sched:sched_stat_runtime", process_sched_runtime_event, },
1454 { "sched:sched_wakeup", process_sched_wakeup_event, }, 1444 { "sched:sched_wakeup", process_sched_wakeup_event, },
1455 { "sched:sched_wakeup_new", process_sched_wakeup_event, }, 1445 { "sched:sched_wakeup_new", process_sched_wakeup_event, },
1456 { "sched:sched_process_fork", process_sched_fork_event, },
1457 { "sched:sched_process_exit", process_sched_exit_event, },
1458 { "sched:sched_migrate_task", process_sched_migrate_task_event, }, 1446 { "sched:sched_migrate_task", process_sched_migrate_task_event, },
1459 }; 1447 };
1460 struct perf_session *session; 1448 struct perf_session *session;
@@ -1480,11 +1468,10 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
1480 sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST]; 1468 sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST];
1481 } 1469 }
1482 1470
1483 if (destroy)
1484 perf_session__delete(session);
1485
1486 if (psession) 1471 if (psession)
1487 *psession = session; 1472 *psession = session;
1473 else
1474 perf_session__delete(session);
1488 1475
1489 return 0; 1476 return 0;
1490 1477
@@ -1529,8 +1516,11 @@ static int perf_sched__lat(struct perf_sched *sched)
1529 struct perf_session *session; 1516 struct perf_session *session;
1530 1517
1531 setup_pager(); 1518 setup_pager();
1532 if (perf_sched__read_events(sched, false, &session)) 1519
1520 /* save session -- references to threads are held in work_list */
1521 if (perf_sched__read_events(sched, &session))
1533 return -1; 1522 return -1;
1523
1534 perf_sched__sort_lat(sched); 1524 perf_sched__sort_lat(sched);
1535 1525
1536 printf("\n ---------------------------------------------------------------------------------------------------------------\n"); 1526 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
@@ -1565,7 +1555,7 @@ static int perf_sched__map(struct perf_sched *sched)
1565 sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); 1555 sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF);
1566 1556
1567 setup_pager(); 1557 setup_pager();
1568 if (perf_sched__read_events(sched, true, NULL)) 1558 if (perf_sched__read_events(sched, NULL))
1569 return -1; 1559 return -1;
1570 print_bad_events(sched); 1560 print_bad_events(sched);
1571 return 0; 1561 return 0;
@@ -1580,7 +1570,7 @@ static int perf_sched__replay(struct perf_sched *sched)
1580 1570
1581 test_calibrations(sched); 1571 test_calibrations(sched);
1582 1572
1583 if (perf_sched__read_events(sched, true, NULL)) 1573 if (perf_sched__read_events(sched, NULL))
1584 return -1; 1574 return -1;
1585 1575
1586 printf("nr_run_events: %ld\n", sched->nr_run_events); 1576 printf("nr_run_events: %ld\n", sched->nr_run_events);
@@ -1632,7 +1622,6 @@ static int __cmd_record(int argc, const char **argv)
1632 "record", 1622 "record",
1633 "-a", 1623 "-a",
1634 "-R", 1624 "-R",
1635 "-f",
1636 "-m", "1024", 1625 "-m", "1024",
1637 "-c", "1", 1626 "-c", "1",
1638 "-e", "sched:sched_switch", 1627 "-e", "sched:sched_switch",
@@ -1640,7 +1629,6 @@ static int __cmd_record(int argc, const char **argv)
1640 "-e", "sched:sched_stat_sleep", 1629 "-e", "sched:sched_stat_sleep",
1641 "-e", "sched:sched_stat_iowait", 1630 "-e", "sched:sched_stat_iowait",
1642 "-e", "sched:sched_stat_runtime", 1631 "-e", "sched:sched_stat_runtime",
1643 "-e", "sched:sched_process_exit",
1644 "-e", "sched:sched_process_fork", 1632 "-e", "sched:sched_process_fork",
1645 "-e", "sched:sched_wakeup", 1633 "-e", "sched:sched_wakeup",
1646 "-e", "sched:sched_migrate_task", 1634 "-e", "sched:sched_migrate_task",
@@ -1663,28 +1651,29 @@ static int __cmd_record(int argc, const char **argv)
1663 return cmd_record(i, rec_argv, NULL); 1651 return cmd_record(i, rec_argv, NULL);
1664} 1652}
1665 1653
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
1666int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) 1675int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1667{ 1676{
1668 const char default_sort_order[] = "avg, max, switch, runtime";
1669 struct perf_sched sched = {
1670 .tool = {
1671 .sample = perf_sched__process_tracepoint_sample,
1672 .comm = perf_event__process_comm,
1673 .lost = perf_event__process_lost,
1674 .fork = perf_event__process_fork,
1675 .ordered_samples = true,
1676 },
1677 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
1678 .sort_list = LIST_HEAD_INIT(sched.sort_list),
1679 .start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
1680 .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
1681 .curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
1682 .sort_order = default_sort_order,
1683 .replay_repeat = 10,
1684 .profile_cpu = -1,
1685 .next_shortname1 = 'A',
1686 .next_shortname2 = '0',
1687 };
1688 const struct option latency_options[] = { 1677 const struct option latency_options[] = {
1689 OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", 1678 OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
1690 "sort by key(s): runtime, switch, avg, max"), 1679 "sort by key(s): runtime, switch, avg, max"),
@@ -1730,7 +1719,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1730 .wakeup_event = latency_wakeup_event, 1719 .wakeup_event = latency_wakeup_event,
1731 .switch_event = latency_switch_event, 1720 .switch_event = latency_switch_event,
1732 .runtime_event = latency_runtime_event, 1721 .runtime_event = latency_runtime_event,
1733 .fork_event = latency_fork_event,
1734 .migrate_task_event = latency_migrate_task_event, 1722 .migrate_task_event = latency_migrate_task_event,
1735 }; 1723 };
1736 struct trace_sched_handler map_ops = { 1724 struct trace_sched_handler map_ops = {
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 92d4658f56fb..9c333ff3dfeb 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -24,6 +24,7 @@ static u64 last_timestamp;
24static u64 nr_unordered; 24static u64 nr_unordered;
25extern const struct option record_options[]; 25extern const struct option record_options[];
26static bool no_callchain; 26static bool no_callchain;
27static bool latency_format;
27static bool system_wide; 28static bool system_wide;
28static const char *cpu_list; 29static const char *cpu_list;
29static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 30static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
@@ -65,6 +66,7 @@ struct output_option {
65static struct { 66static struct {
66 bool user_set; 67 bool user_set;
67 bool wildcard_set; 68 bool wildcard_set;
69 unsigned int print_ip_opts;
68 u64 fields; 70 u64 fields;
69 u64 invalid_fields; 71 u64 invalid_fields;
70} output[PERF_TYPE_MAX] = { 72} output[PERF_TYPE_MAX] = {
@@ -234,6 +236,7 @@ static int perf_session__check_output_opt(struct perf_session *session)
234{ 236{
235 int j; 237 int j;
236 struct perf_evsel *evsel; 238 struct perf_evsel *evsel;
239 struct perf_event_attr *attr;
237 240
238 for (j = 0; j < PERF_TYPE_MAX; ++j) { 241 for (j = 0; j < PERF_TYPE_MAX; ++j) {
239 evsel = perf_session__find_first_evtype(session, j); 242 evsel = perf_session__find_first_evtype(session, j);
@@ -252,6 +255,24 @@ static int perf_session__check_output_opt(struct perf_session *session)
252 if (evsel && output[j].fields && 255 if (evsel && output[j].fields &&
253 perf_evsel__check_attr(evsel, session)) 256 perf_evsel__check_attr(evsel, session))
254 return -1; 257 return -1;
258
259 if (evsel == NULL)
260 continue;
261
262 attr = &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;
255 } 276 }
256 277
257 return 0; 278 return 0;
@@ -381,8 +402,8 @@ static void print_sample_bts(union perf_event *event,
381 else 402 else
382 printf("\n"); 403 printf("\n");
383 perf_evsel__print_ip(evsel, event, sample, machine, 404 perf_evsel__print_ip(evsel, event, sample, machine,
384 PRINT_FIELD(SYM), PRINT_FIELD(DSO), 405 output[attr->type].print_ip_opts,
385 PRINT_FIELD(SYMOFFSET)); 406 PERF_MAX_STACK_DEPTH);
386 } 407 }
387 408
388 printf(" => "); 409 printf(" => ");
@@ -396,10 +417,10 @@ static void print_sample_bts(union perf_event *event,
396 417
397static void process_event(union perf_event *event, struct perf_sample *sample, 418static void process_event(union perf_event *event, struct perf_sample *sample,
398 struct perf_evsel *evsel, struct machine *machine, 419 struct perf_evsel *evsel, struct machine *machine,
399 struct addr_location *al) 420 struct thread *thread,
421 struct addr_location *al __maybe_unused)
400{ 422{
401 struct perf_event_attr *attr = &evsel->attr; 423 struct perf_event_attr *attr = &evsel->attr;
402 struct thread *thread = al->thread;
403 424
404 if (output[attr->type].fields == 0) 425 if (output[attr->type].fields == 0)
405 return; 426 return;
@@ -422,9 +443,10 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
422 printf(" "); 443 printf(" ");
423 else 444 else
424 printf("\n"); 445 printf("\n");
446
425 perf_evsel__print_ip(evsel, event, sample, machine, 447 perf_evsel__print_ip(evsel, event, sample, machine,
426 PRINT_FIELD(SYM), PRINT_FIELD(DSO), 448 output[attr->type].print_ip_opts,
427 PRINT_FIELD(SYMOFFSET)); 449 PERF_MAX_STACK_DEPTH);
428 } 450 }
429 451
430 printf("\n"); 452 printf("\n");
@@ -479,7 +501,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
479 struct machine *machine) 501 struct machine *machine)
480{ 502{
481 struct addr_location al; 503 struct addr_location al;
482 struct thread *thread = machine__findnew_thread(machine, event->ip.tid); 504 struct thread *thread = machine__findnew_thread(machine, sample->pid,
505 sample->tid);
483 506
484 if (thread == NULL) { 507 if (thread == NULL) {
485 pr_debug("problem processing %d event, skipping it.\n", 508 pr_debug("problem processing %d event, skipping it.\n",
@@ -498,7 +521,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
498 return 0; 521 return 0;
499 } 522 }
500 523
501 if (perf_event__preprocess_sample(event, machine, &al, sample, 0) < 0) { 524 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
502 pr_err("problem processing %d event, skipping it.\n", 525 pr_err("problem processing %d event, skipping it.\n",
503 event->header.type); 526 event->header.type);
504 return -1; 527 return -1;
@@ -510,7 +533,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
510 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 533 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
511 return 0; 534 return 0;
512 535
513 scripting_ops->process_event(event, sample, evsel, machine, &al); 536 scripting_ops->process_event(event, sample, evsel, machine, thread, &al);
514 537
515 evsel->hists.stats.total_period += sample->period; 538 evsel->hists.stats.total_period += sample->period;
516 return 0; 539 return 0;
@@ -519,19 +542,17 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
519static struct perf_tool perf_script = { 542static struct perf_tool perf_script = {
520 .sample = process_sample_event, 543 .sample = process_sample_event,
521 .mmap = perf_event__process_mmap, 544 .mmap = perf_event__process_mmap,
545 .mmap2 = perf_event__process_mmap2,
522 .comm = perf_event__process_comm, 546 .comm = perf_event__process_comm,
523 .exit = perf_event__process_exit, 547 .exit = perf_event__process_exit,
524 .fork = perf_event__process_fork, 548 .fork = perf_event__process_fork,
525 .attr = perf_event__process_attr, 549 .attr = perf_event__process_attr,
526 .event_type = perf_event__process_event_type,
527 .tracing_data = perf_event__process_tracing_data, 550 .tracing_data = perf_event__process_tracing_data,
528 .build_id = perf_event__process_build_id, 551 .build_id = perf_event__process_build_id,
529 .ordered_samples = true, 552 .ordered_samples = true,
530 .ordering_requires_timestamps = true, 553 .ordering_requires_timestamps = true,
531}; 554};
532 555
533extern volatile int session_done;
534
535static void sig_handler(int sig __maybe_unused) 556static void sig_handler(int sig __maybe_unused)
536{ 557{
537 session_done = 1; 558 session_done = 1;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 7e910bab1097..f686d5ff594e 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -87,7 +87,7 @@ static int run_count = 1;
87static bool no_inherit = false; 87static bool no_inherit = false;
88static bool scale = true; 88static bool scale = true;
89static enum aggr_mode aggr_mode = AGGR_GLOBAL; 89static enum aggr_mode aggr_mode = AGGR_GLOBAL;
90static pid_t child_pid = -1; 90static volatile pid_t child_pid = -1;
91static bool null_run = false; 91static bool null_run = false;
92static int detailed_run = 0; 92static int detailed_run = 0;
93static bool big_num = true; 93static bool big_num = true;
@@ -100,6 +100,7 @@ static const char *pre_cmd = NULL;
100static const char *post_cmd = NULL; 100static const char *post_cmd = NULL;
101static bool sync_run = false; 101static bool sync_run = false;
102static unsigned int interval = 0; 102static unsigned int interval = 0;
103static unsigned int initial_delay = 0;
103static bool forever = false; 104static bool forever = false;
104static struct timespec ref_time; 105static struct timespec ref_time;
105static struct cpu_map *aggr_map; 106static struct cpu_map *aggr_map;
@@ -254,7 +255,8 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
254 if (!perf_target__has_task(&target) && 255 if (!perf_target__has_task(&target) &&
255 perf_evsel__is_group_leader(evsel)) { 256 perf_evsel__is_group_leader(evsel)) {
256 attr->disabled = 1; 257 attr->disabled = 1;
257 attr->enable_on_exec = 1; 258 if (!initial_delay)
259 attr->enable_on_exec = 1;
258 } 260 }
259 261
260 return perf_evsel__open_per_thread(evsel, evsel_list->threads); 262 return perf_evsel__open_per_thread(evsel, evsel_list->threads);
@@ -414,6 +416,22 @@ static void print_interval(void)
414 list_for_each_entry(counter, &evsel_list->entries, node) 416 list_for_each_entry(counter, &evsel_list->entries, node)
415 print_counter_aggr(counter, prefix); 417 print_counter_aggr(counter, prefix);
416 } 418 }
419
420 fflush(output);
421}
422
423static void handle_initial_delay(void)
424{
425 struct perf_evsel *counter;
426
427 if (initial_delay) {
428 const int ncpus = cpu_map__nr(evsel_list->cpus),
429 nthreads = thread_map__nr(evsel_list->threads);
430
431 usleep(initial_delay * 1000);
432 list_for_each_entry(counter, &evsel_list->entries, node)
433 perf_evsel__enable(counter, ncpus, nthreads);
434 }
417} 435}
418 436
419static int __run_perf_stat(int argc, const char **argv) 437static int __run_perf_stat(int argc, const char **argv)
@@ -486,6 +504,7 @@ static int __run_perf_stat(int argc, const char **argv)
486 504
487 if (forks) { 505 if (forks) {
488 perf_evlist__start_workload(evsel_list); 506 perf_evlist__start_workload(evsel_list);
507 handle_initial_delay();
489 508
490 if (interval) { 509 if (interval) {
491 while (!waitpid(child_pid, &status, WNOHANG)) { 510 while (!waitpid(child_pid, &status, WNOHANG)) {
@@ -497,6 +516,7 @@ static int __run_perf_stat(int argc, const char **argv)
497 if (WIFSIGNALED(status)) 516 if (WIFSIGNALED(status))
498 psignal(WTERMSIG(status), argv[0]); 517 psignal(WTERMSIG(status), argv[0]);
499 } else { 518 } else {
519 handle_initial_delay();
500 while (!done) { 520 while (!done) {
501 nanosleep(&ts, NULL); 521 nanosleep(&ts, NULL);
502 if (interval) 522 if (interval)
@@ -924,7 +944,7 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
924static void print_aggr(char *prefix) 944static void print_aggr(char *prefix)
925{ 945{
926 struct perf_evsel *counter; 946 struct perf_evsel *counter;
927 int cpu, s, s2, id, nr; 947 int cpu, cpu2, s, s2, id, nr;
928 u64 ena, run, val; 948 u64 ena, run, val;
929 949
930 if (!(aggr_map || aggr_get_id)) 950 if (!(aggr_map || aggr_get_id))
@@ -936,7 +956,8 @@ static void print_aggr(char *prefix)
936 val = ena = run = 0; 956 val = ena = run = 0;
937 nr = 0; 957 nr = 0;
938 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 958 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
939 s2 = aggr_get_id(evsel_list->cpus, cpu); 959 cpu2 = perf_evsel__cpus(counter)->map[cpu];
960 s2 = aggr_get_id(evsel_list->cpus, cpu2);
940 if (s2 != id) 961 if (s2 != id)
941 continue; 962 continue;
942 val += counter->counts->cpu[cpu].val; 963 val += counter->counts->cpu[cpu].val;
@@ -948,7 +969,7 @@ static void print_aggr(char *prefix)
948 fprintf(output, "%s", prefix); 969 fprintf(output, "%s", prefix);
949 970
950 if (run == 0 || ena == 0) { 971 if (run == 0 || ena == 0) {
951 aggr_printout(counter, cpu, nr); 972 aggr_printout(counter, id, nr);
952 973
953 fprintf(output, "%*s%s%*s", 974 fprintf(output, "%*s%s%*s",
954 csv_output ? 0 : 18, 975 csv_output ? 0 : 18,
@@ -1148,13 +1169,34 @@ static void skip_signal(int signo)
1148 done = 1; 1169 done = 1;
1149 1170
1150 signr = signo; 1171 signr = signo;
1172 /*
1173 * render child_pid harmless
1174 * won't send SIGTERM to a random
1175 * process in case of race condition
1176 * and fast PID recycling
1177 */
1178 child_pid = -1;
1151} 1179}
1152 1180
1153static void sig_atexit(void) 1181static void sig_atexit(void)
1154{ 1182{
1183 sigset_t set, oset;
1184
1185 /*
1186 * avoid race condition with SIGCHLD handler
1187 * in skip_signal() which is modifying child_pid
1188 * goal is to avoid send SIGTERM to a random
1189 * process
1190 */
1191 sigemptyset(&set);
1192 sigaddset(&set, SIGCHLD);
1193 sigprocmask(SIG_BLOCK, &set, &oset);
1194
1155 if (child_pid != -1) 1195 if (child_pid != -1)
1156 kill(child_pid, SIGTERM); 1196 kill(child_pid, SIGTERM);
1157 1197
1198 sigprocmask(SIG_SETMASK, &oset, NULL);
1199
1158 if (signr == -1) 1200 if (signr == -1)
1159 return; 1201 return;
1160 1202
@@ -1397,6 +1439,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1397 "aggregate counts per processor socket", AGGR_SOCKET), 1439 "aggregate counts per processor socket", AGGR_SOCKET),
1398 OPT_SET_UINT(0, "per-core", &aggr_mode, 1440 OPT_SET_UINT(0, "per-core", &aggr_mode,
1399 "aggregate counts per physical processor core", AGGR_CORE), 1441 "aggregate counts per physical processor core", AGGR_CORE),
1442 OPT_UINTEGER('D', "delay", &initial_delay,
1443 "ms to wait before starting measurement after program start"),
1400 OPT_END() 1444 OPT_END()
1401 }; 1445 };
1402 const char * const stat_usage[] = { 1446 const char * const stat_usage[] = {
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index ab4cf232b852..c2e02319347a 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -12,6 +12,8 @@
12 * of the License. 12 * of the License.
13 */ 13 */
14 14
15#include <traceevent/event-parse.h>
16
15#include "builtin.h" 17#include "builtin.h"
16 18
17#include "util/util.h" 19#include "util/util.h"
@@ -19,6 +21,7 @@
19#include "util/color.h" 21#include "util/color.h"
20#include <linux/list.h> 22#include <linux/list.h>
21#include "util/cache.h" 23#include "util/cache.h"
24#include "util/evlist.h"
22#include "util/evsel.h" 25#include "util/evsel.h"
23#include <linux/rbtree.h> 26#include <linux/rbtree.h>
24#include "util/symbol.h" 27#include "util/symbol.h"
@@ -328,25 +331,6 @@ struct wakeup_entry {
328 int success; 331 int success;
329}; 332};
330 333
331/*
332 * trace_flag_type is an enumeration that holds different
333 * states when a trace occurs. These are:
334 * IRQS_OFF - interrupts were disabled
335 * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags
336 * NEED_RESCED - reschedule is requested
337 * HARDIRQ - inside an interrupt handler
338 * SOFTIRQ - inside a softirq handler
339 */
340enum trace_flag_type {
341 TRACE_FLAG_IRQS_OFF = 0x01,
342 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
343 TRACE_FLAG_NEED_RESCHED = 0x04,
344 TRACE_FLAG_HARDIRQ = 0x08,
345 TRACE_FLAG_SOFTIRQ = 0x10,
346};
347
348
349
350struct sched_switch { 334struct sched_switch {
351 struct trace_entry te; 335 struct trace_entry te;
352 char prev_comm[TASK_COMM_LEN]; 336 char prev_comm[TASK_COMM_LEN];
@@ -479,6 +463,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
479 } 463 }
480} 464}
481 465
466typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
467 struct perf_sample *sample);
482 468
483static int process_sample_event(struct perf_tool *tool __maybe_unused, 469static int process_sample_event(struct perf_tool *tool __maybe_unused,
484 union perf_event *event __maybe_unused, 470 union perf_event *event __maybe_unused,
@@ -486,8 +472,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
486 struct perf_evsel *evsel, 472 struct perf_evsel *evsel,
487 struct machine *machine __maybe_unused) 473 struct machine *machine __maybe_unused)
488{ 474{
489 struct trace_entry *te;
490
491 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { 475 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
492 if (!first_time || first_time > sample->time) 476 if (!first_time || first_time > sample->time)
493 first_time = sample->time; 477 first_time = sample->time;
@@ -495,69 +479,90 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
495 last_time = sample->time; 479 last_time = sample->time;
496 } 480 }
497 481
498 te = (void *)sample->raw_data; 482 if (sample->cpu > numcpus)
499 if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) { 483 numcpus = sample->cpu;
500 char *event_str; 484
501#ifdef SUPPORT_OLD_POWER_EVENTS 485 if (evsel->handler.func != NULL) {
502 struct power_entry_old *peo; 486 tracepoint_handler f = evsel->handler.func;
503 peo = (void *)te; 487 return f(evsel, sample);
504#endif 488 }
505 /* 489
506 * FIXME: use evsel, its already mapped from id to perf_evsel, 490 return 0;
507 * remove perf_header__find_event infrastructure bits. 491}
508 * Mapping all these "power:cpu_idle" strings to the tracepoint 492
509 * ID and then just comparing against evsel->attr.config. 493static int
510 * 494process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused,
511 * e.g.: 495 struct perf_sample *sample)
512 * 496{
513 * if (evsel->attr.config == power_cpu_idle_id) 497 struct power_processor_entry *ppe = sample->raw_data;
514 */ 498
515 event_str = perf_header__find_event(te->type); 499 if (ppe->state == (u32) PWR_EVENT_EXIT)
516 500 c_state_end(ppe->cpu_id, sample->time);
517 if (!event_str) 501 else
518 return 0; 502 c_state_start(ppe->cpu_id, sample->time, ppe->state);
519 503 return 0;
520 if (sample->cpu > numcpus) 504}
521 numcpus = sample->cpu; 505
522 506static int
523 if (strcmp(event_str, "power:cpu_idle") == 0) { 507process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused,
524 struct power_processor_entry *ppe = (void *)te; 508 struct perf_sample *sample)
525 if (ppe->state == (u32)PWR_EVENT_EXIT) 509{
526 c_state_end(ppe->cpu_id, sample->time); 510 struct power_processor_entry *ppe = sample->raw_data;
527 else 511
528 c_state_start(ppe->cpu_id, sample->time, 512 p_state_change(ppe->cpu_id, sample->time, ppe->state);
529 ppe->state); 513 return 0;
530 } 514}
531 else if (strcmp(event_str, "power:cpu_frequency") == 0) { 515
532 struct power_processor_entry *ppe = (void *)te; 516static int
533 p_state_change(ppe->cpu_id, sample->time, ppe->state); 517process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused,
534 } 518 struct perf_sample *sample)
519{
520 struct trace_entry *te = sample->raw_data;
521
522 sched_wakeup(sample->cpu, sample->time, sample->pid, te);
523 return 0;
524}
535 525
536 else if (strcmp(event_str, "sched:sched_wakeup") == 0) 526static int
537 sched_wakeup(sample->cpu, sample->time, sample->pid, te); 527process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused,
528 struct perf_sample *sample)
529{
530 struct trace_entry *te = sample->raw_data;
538 531
539 else if (strcmp(event_str, "sched:sched_switch") == 0) 532 sched_switch(sample->cpu, sample->time, te);
540 sched_switch(sample->cpu, sample->time, te); 533 return 0;
534}
541 535
542#ifdef SUPPORT_OLD_POWER_EVENTS 536#ifdef SUPPORT_OLD_POWER_EVENTS
543 if (use_old_power_events) { 537static int
544 if (strcmp(event_str, "power:power_start") == 0) 538process_sample_power_start(struct perf_evsel *evsel __maybe_unused,
545 c_state_start(peo->cpu_id, sample->time, 539 struct perf_sample *sample)
546 peo->value); 540{
547 541 struct power_entry_old *peo = sample->raw_data;
548 else if (strcmp(event_str, "power:power_end") == 0) 542
549 c_state_end(sample->cpu, sample->time); 543 c_state_start(peo->cpu_id, sample->time, peo->value);
550
551 else if (strcmp(event_str,
552 "power:power_frequency") == 0)
553 p_state_change(peo->cpu_id, sample->time,
554 peo->value);
555 }
556#endif
557 }
558 return 0; 544 return 0;
559} 545}
560 546
547static int
548process_sample_power_end(struct perf_evsel *evsel __maybe_unused,
549 struct perf_sample *sample)
550{
551 c_state_end(sample->cpu, sample->time);
552 return 0;
553}
554
555static int
556process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused,
557 struct perf_sample *sample)
558{
559 struct power_entry_old *peo = sample->raw_data;
560
561 p_state_change(peo->cpu_id, sample->time, peo->value);
562 return 0;
563}
564#endif /* SUPPORT_OLD_POWER_EVENTS */
565
561/* 566/*
562 * After the last sample we need to wrap up the current C/P state 567 * After the last sample we need to wrap up the current C/P state
563 * and close out each CPU for these. 568 * and close out each CPU for these.
@@ -974,6 +979,17 @@ static int __cmd_timechart(const char *output_name)
974 .sample = process_sample_event, 979 .sample = process_sample_event,
975 .ordered_samples = true, 980 .ordered_samples = true,
976 }; 981 };
982 const struct perf_evsel_str_handler power_tracepoints[] = {
983 { "power:cpu_idle", process_sample_cpu_idle },
984 { "power:cpu_frequency", process_sample_cpu_frequency },
985 { "sched:sched_wakeup", process_sample_sched_wakeup },
986 { "sched:sched_switch", process_sample_sched_switch },
987#ifdef SUPPORT_OLD_POWER_EVENTS
988 { "power:power_start", process_sample_power_start },
989 { "power:power_end", process_sample_power_end },
990 { "power:power_frequency", process_sample_power_frequency },
991#endif
992 };
977 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 993 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
978 0, false, &perf_timechart); 994 0, false, &perf_timechart);
979 int ret = -EINVAL; 995 int ret = -EINVAL;
@@ -984,6 +1000,12 @@ static int __cmd_timechart(const char *output_name)
984 if (!perf_session__has_traces(session, "timechart record")) 1000 if (!perf_session__has_traces(session, "timechart record"))
985 goto out_delete; 1001 goto out_delete;
986 1002
1003 if (perf_session__set_tracepoints_handlers(session,
1004 power_tracepoints)) {
1005 pr_err("Initializing session tracepoint handlers failed\n");
1006 goto out_delete;
1007 }
1008
987 ret = perf_session__process_events(session, &perf_timechart); 1009 ret = perf_session__process_events(session, &perf_timechart);
988 if (ret) 1010 if (ret)
989 goto out_delete; 1011 goto out_delete;
@@ -1005,7 +1027,7 @@ static int __cmd_record(int argc, const char **argv)
1005{ 1027{
1006#ifdef SUPPORT_OLD_POWER_EVENTS 1028#ifdef SUPPORT_OLD_POWER_EVENTS
1007 const char * const record_old_args[] = { 1029 const char * const record_old_args[] = {
1008 "record", "-a", "-R", "-f", "-c", "1", 1030 "record", "-a", "-R", "-c", "1",
1009 "-e", "power:power_start", 1031 "-e", "power:power_start",
1010 "-e", "power:power_end", 1032 "-e", "power:power_end",
1011 "-e", "power:power_frequency", 1033 "-e", "power:power_frequency",
@@ -1014,7 +1036,7 @@ static int __cmd_record(int argc, const char **argv)
1014 }; 1036 };
1015#endif 1037#endif
1016 const char * const record_new_args[] = { 1038 const char * const record_new_args[] = {
1017 "record", "-a", "-R", "-f", "-c", "1", 1039 "record", "-a", "-R", "-c", "1",
1018 "-e", "power:cpu_frequency", 1040 "-e", "power:cpu_frequency",
1019 "-e", "power:cpu_idle", 1041 "-e", "power:cpu_idle",
1020 "-e", "sched:sched_wakeup", 1042 "-e", "sched:sched_wakeup",
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 67bdb9f14ad6..212214162bb2 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -40,6 +40,7 @@
40#include "util/xyarray.h" 40#include "util/xyarray.h"
41#include "util/sort.h" 41#include "util/sort.h"
42#include "util/intlist.h" 42#include "util/intlist.h"
43#include "arch/common.h"
43 44
44#include "util/debug.h" 45#include "util/debug.h"
45 46
@@ -70,10 +71,11 @@
70 71
71static volatile int done; 72static volatile int done;
72 73
74#define HEADER_LINE_NR 5
75
73static void perf_top__update_print_entries(struct perf_top *top) 76static void perf_top__update_print_entries(struct perf_top *top)
74{ 77{
75 if (top->print_entries > 9) 78 top->print_entries = top->winsize.ws_row - HEADER_LINE_NR;
76 top->print_entries -= 9;
77} 79}
78 80
79static void perf_top__sig_winch(int sig __maybe_unused, 81static void perf_top__sig_winch(int sig __maybe_unused,
@@ -82,13 +84,6 @@ static void perf_top__sig_winch(int sig __maybe_unused,
82 struct perf_top *top = arg; 84 struct perf_top *top = arg;
83 85
84 get_term_dimensions(&top->winsize); 86 get_term_dimensions(&top->winsize);
85 if (!top->print_entries
86 || (top->print_entries+4) > top->winsize.ws_row) {
87 top->print_entries = top->winsize.ws_row;
88 } else {
89 top->print_entries += 4;
90 top->winsize.ws_row = top->print_entries;
91 }
92 perf_top__update_print_entries(top); 87 perf_top__update_print_entries(top);
93} 88}
94 89
@@ -108,7 +103,8 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
108 /* 103 /*
109 * We can't annotate with just /proc/kallsyms 104 * We can't annotate with just /proc/kallsyms
110 */ 105 */
111 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { 106 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
107 !dso__is_kcore(map->dso)) {
112 pr_err("Can't annotate %s: No vmlinux file was found in the " 108 pr_err("Can't annotate %s: No vmlinux file was found in the "
113 "path\n", sym->name); 109 "path\n", sym->name);
114 sleep(1); 110 sleep(1);
@@ -243,16 +239,17 @@ out_unlock:
243 pthread_mutex_unlock(&notes->lock); 239 pthread_mutex_unlock(&notes->lock);
244} 240}
245 241
246static const char CONSOLE_CLEAR[] = "";
247
248static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, 242static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
249 struct addr_location *al, 243 struct addr_location *al,
250 struct perf_sample *sample) 244 struct perf_sample *sample)
251{ 245{
252 struct hist_entry *he; 246 struct hist_entry *he;
253 247
248 pthread_mutex_lock(&evsel->hists.lock);
254 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period, 249 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period,
255 sample->weight); 250 sample->weight);
251 pthread_mutex_unlock(&evsel->hists.lock);
252
256 if (he == NULL) 253 if (he == NULL)
257 return NULL; 254 return NULL;
258 255
@@ -290,16 +287,17 @@ static void perf_top__print_sym_table(struct perf_top *top)
290 return; 287 return;
291 } 288 }
292 289
293 hists__collapse_resort_threaded(&top->sym_evsel->hists); 290 hists__collapse_resort(&top->sym_evsel->hists);
294 hists__output_resort_threaded(&top->sym_evsel->hists); 291 hists__output_resort(&top->sym_evsel->hists);
295 hists__decay_entries_threaded(&top->sym_evsel->hists, 292 hists__decay_entries(&top->sym_evsel->hists,
296 top->hide_user_symbols, 293 top->hide_user_symbols,
297 top->hide_kernel_symbols); 294 top->hide_kernel_symbols);
298 hists__output_recalc_col_len(&top->sym_evsel->hists, 295 hists__output_recalc_col_len(&top->sym_evsel->hists,
299 top->winsize.ws_row - 3); 296 top->print_entries - printed);
300 putchar('\n'); 297 putchar('\n');
301 hists__fprintf(&top->sym_evsel->hists, false, 298 hists__fprintf(&top->sym_evsel->hists, false,
302 top->winsize.ws_row - 4 - printed, win_width, stdout); 299 top->print_entries - printed, win_width,
300 top->min_percent, stdout);
303} 301}
304 302
305static void prompt_integer(int *target, const char *msg) 303static void prompt_integer(int *target, const char *msg)
@@ -477,7 +475,6 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
477 perf_top__sig_winch(SIGWINCH, NULL, top); 475 perf_top__sig_winch(SIGWINCH, NULL, top);
478 sigaction(SIGWINCH, &act, NULL); 476 sigaction(SIGWINCH, &act, NULL);
479 } else { 477 } else {
480 perf_top__sig_winch(SIGWINCH, NULL, top);
481 signal(SIGWINCH, SIG_DFL); 478 signal(SIGWINCH, SIG_DFL);
482 } 479 }
483 break; 480 break;
@@ -556,11 +553,11 @@ static void perf_top__sort_new_samples(void *arg)
556 if (t->evlist->selected != NULL) 553 if (t->evlist->selected != NULL)
557 t->sym_evsel = t->evlist->selected; 554 t->sym_evsel = t->evlist->selected;
558 555
559 hists__collapse_resort_threaded(&t->sym_evsel->hists); 556 hists__collapse_resort(&t->sym_evsel->hists);
560 hists__output_resort_threaded(&t->sym_evsel->hists); 557 hists__output_resort(&t->sym_evsel->hists);
561 hists__decay_entries_threaded(&t->sym_evsel->hists, 558 hists__decay_entries(&t->sym_evsel->hists,
562 t->hide_user_symbols, 559 t->hide_user_symbols,
563 t->hide_kernel_symbols); 560 t->hide_kernel_symbols);
564} 561}
565 562
566static void *display_thread_tui(void *arg) 563static void *display_thread_tui(void *arg)
@@ -584,7 +581,7 @@ static void *display_thread_tui(void *arg)
584 list_for_each_entry(pos, &top->evlist->entries, node) 581 list_for_each_entry(pos, &top->evlist->entries, node)
585 pos->hists.uid_filter_str = top->record_opts.target.uid_str; 582 pos->hists.uid_filter_str = top->record_opts.target.uid_str;
586 583
587 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, 584 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
588 &top->session->header.env); 585 &top->session->header.env);
589 586
590 done = 1; 587 done = 1;
@@ -692,7 +689,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
692{ 689{
693 struct perf_top *top = container_of(tool, struct perf_top, tool); 690 struct perf_top *top = container_of(tool, struct perf_top, tool);
694 struct symbol *parent = NULL; 691 struct symbol *parent = NULL;
695 u64 ip = event->ip.ip; 692 u64 ip = sample->ip;
696 struct addr_location al; 693 struct addr_location al;
697 int err; 694 int err;
698 695
@@ -702,10 +699,10 @@ static void perf_event__process_sample(struct perf_tool *tool,
702 if (!seen) 699 if (!seen)
703 seen = intlist__new(NULL); 700 seen = intlist__new(NULL);
704 701
705 if (!intlist__has_entry(seen, event->ip.pid)) { 702 if (!intlist__has_entry(seen, sample->pid)) {
706 pr_err("Can't find guest [%d]'s kernel information\n", 703 pr_err("Can't find guest [%d]'s kernel information\n",
707 event->ip.pid); 704 sample->pid);
708 intlist__add(seen, event->ip.pid); 705 intlist__add(seen, sample->pid);
709 } 706 }
710 return; 707 return;
711 } 708 }
@@ -719,8 +716,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
719 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) 716 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
720 top->exact_samples++; 717 top->exact_samples++;
721 718
722 if (perf_event__preprocess_sample(event, machine, &al, sample, 719 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0 ||
723 symbol_filter) < 0 ||
724 al.filtered) 720 al.filtered)
725 return; 721 return;
726 722
@@ -775,8 +771,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
775 sample->callchain) { 771 sample->callchain) {
776 err = machine__resolve_callchain(machine, evsel, 772 err = machine__resolve_callchain(machine, evsel,
777 al.thread, sample, 773 al.thread, sample,
778 &parent); 774 &parent, &al);
779
780 if (err) 775 if (err)
781 return; 776 return;
782 } 777 }
@@ -794,7 +789,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
794 return; 789 return;
795 } 790 }
796 791
797 if (top->sort_has_symbols) 792 if (sort__has_sym)
798 perf_top__record_precise_ip(top, he, evsel->idx, ip); 793 perf_top__record_precise_ip(top, he, evsel->idx, ip);
799 } 794 }
800 795
@@ -841,7 +836,8 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
841 break; 836 break;
842 case PERF_RECORD_MISC_GUEST_KERNEL: 837 case PERF_RECORD_MISC_GUEST_KERNEL:
843 ++top->guest_kernel_samples; 838 ++top->guest_kernel_samples;
844 machine = perf_session__find_machine(session, event->ip.pid); 839 machine = perf_session__find_machine(session,
840 sample.pid);
845 break; 841 break;
846 case PERF_RECORD_MISC_GUEST_USER: 842 case PERF_RECORD_MISC_GUEST_USER:
847 ++top->guest_us_samples; 843 ++top->guest_us_samples;
@@ -912,9 +908,9 @@ out_err:
912 return -1; 908 return -1;
913} 909}
914 910
915static int perf_top__setup_sample_type(struct perf_top *top) 911static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused)
916{ 912{
917 if (!top->sort_has_symbols) { 913 if (!sort__has_sym) {
918 if (symbol_conf.use_callchain) { 914 if (symbol_conf.use_callchain) {
919 ui__error("Selected -g but \"sym\" not present in --sort/-s."); 915 ui__error("Selected -g but \"sym\" not present in --sort/-s.");
920 return -EINVAL; 916 return -EINVAL;
@@ -942,6 +938,14 @@ static int __cmd_top(struct perf_top *top)
942 if (top->session == NULL) 938 if (top->session == NULL)
943 return -ENOMEM; 939 return -ENOMEM;
944 940
941 machines__set_symbol_filter(&top->session->machines, symbol_filter);
942
943 if (!objdump_path) {
944 ret = perf_session_env__lookup_objdump(&top->session->header.env);
945 if (ret)
946 goto out_delete;
947 }
948
945 ret = perf_top__setup_sample_type(top); 949 ret = perf_top__setup_sample_type(top);
946 if (ret) 950 if (ret)
947 goto out_delete; 951 goto out_delete;
@@ -1025,6 +1029,16 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1025 return record_parse_callchain_opt(opt, arg, unset); 1029 return record_parse_callchain_opt(opt, arg, unset);
1026} 1030}
1027 1031
1032static int
1033parse_percent_limit(const struct option *opt, const char *arg,
1034 int unset __maybe_unused)
1035{
1036 struct perf_top *top = opt->value;
1037
1038 top->min_percent = strtof(arg, NULL);
1039 return 0;
1040}
1041
1028int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) 1042int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1029{ 1043{
1030 int status; 1044 int status;
@@ -1095,6 +1109,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1095 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, 1109 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
1096 "mode[,dump_size]", record_callchain_help, 1110 "mode[,dump_size]", record_callchain_help,
1097 &parse_callchain_opt, "fp"), 1111 &parse_callchain_opt, "fp"),
1112 OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
1113 "ignore callees of these functions in call graphs",
1114 report_parse_ignore_callees_opt),
1098 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 1115 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1099 "Show a column with the sum of periods"), 1116 "Show a column with the sum of periods"),
1100 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 1117 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
@@ -1107,9 +1124,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1107 "Interleave source code with assembly code (default)"), 1124 "Interleave source code with assembly code (default)"),
1108 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, 1125 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
1109 "Display raw encoding of assembly instructions (default)"), 1126 "Display raw encoding of assembly instructions (default)"),
1127 OPT_STRING(0, "objdump", &objdump_path, "path",
1128 "objdump binary to use for disassembly and annotations"),
1110 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1129 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1111 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1130 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1112 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), 1131 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
1132 OPT_CALLBACK(0, "percent-limit", &top, "percent",
1133 "Don't show entries under that percent", parse_percent_limit),
1113 OPT_END() 1134 OPT_END()
1114 }; 1135 };
1115 const char * const top_usage[] = { 1136 const char * const top_usage[] = {
@@ -1121,8 +1142,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1121 if (top.evlist == NULL) 1142 if (top.evlist == NULL)
1122 return -ENOMEM; 1143 return -ENOMEM;
1123 1144
1124 symbol_conf.exclude_other = false;
1125
1126 argc = parse_options(argc, argv, options, top_usage, 0); 1145 argc = parse_options(argc, argv, options, top_usage, 0);
1127 if (argc) 1146 if (argc)
1128 usage_with_options(top_usage, options); 1147 usage_with_options(top_usage, options);
@@ -1133,6 +1152,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1133 if (setup_sorting() < 0) 1152 if (setup_sorting() < 0)
1134 usage_with_options(top_usage, options); 1153 usage_with_options(top_usage, options);
1135 1154
1155 /* display thread wants entries to be collapsed in a different tree */
1156 sort__need_collapse = 1;
1157
1136 if (top.use_stdio) 1158 if (top.use_stdio)
1137 use_browser = 0; 1159 use_browser = 0;
1138 else if (top.use_tui) 1160 else if (top.use_tui)
@@ -1200,15 +1222,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1200 if (symbol__init() < 0) 1222 if (symbol__init() < 0)
1201 return -1; 1223 return -1;
1202 1224
1203 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout); 1225 sort__setup_elide(stdout);
1204 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1205 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1206
1207 /*
1208 * Avoid annotation data structures overhead when symbols aren't on the
1209 * sort list.
1210 */
1211 top.sort_has_symbols = sort_sym.list.next != NULL;
1212 1226
1213 get_term_dimensions(&top.winsize); 1227 get_term_dimensions(&top.winsize);
1214 if (top.print_entries == 0) { 1228 if (top.print_entries == 0) {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index ab3ed4af1466..71aa3e35406b 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1,34 +1,350 @@
1#include <traceevent/event-parse.h>
1#include "builtin.h" 2#include "builtin.h"
2#include "util/color.h" 3#include "util/color.h"
4#include "util/debug.h"
3#include "util/evlist.h" 5#include "util/evlist.h"
4#include "util/machine.h" 6#include "util/machine.h"
7#include "util/session.h"
5#include "util/thread.h" 8#include "util/thread.h"
6#include "util/parse-options.h" 9#include "util/parse-options.h"
10#include "util/strlist.h"
11#include "util/intlist.h"
7#include "util/thread_map.h" 12#include "util/thread_map.h"
8#include "event-parse.h"
9 13
10#include <libaudit.h> 14#include <libaudit.h>
11#include <stdlib.h> 15#include <stdlib.h>
16#include <sys/mman.h>
17#include <linux/futex.h>
18
19/* For older distros: */
20#ifndef MAP_STACK
21# define MAP_STACK 0x20000
22#endif
23
24#ifndef MADV_HWPOISON
25# define MADV_HWPOISON 100
26#endif
27
28#ifndef MADV_MERGEABLE
29# define MADV_MERGEABLE 12
30#endif
31
32#ifndef MADV_UNMERGEABLE
33# define MADV_UNMERGEABLE 13
34#endif
35
36static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
37 unsigned long arg,
38 u8 arg_idx __maybe_unused,
39 u8 *arg_mask __maybe_unused)
40{
41 return scnprintf(bf, size, "%#lx", arg);
42}
43
44#define SCA_HEX syscall_arg__scnprintf_hex
45
46static size_t syscall_arg__scnprintf_whence(char *bf, size_t size,
47 unsigned long arg,
48 u8 arg_idx __maybe_unused,
49 u8 *arg_mask __maybe_unused)
50{
51 int whence = arg;
52
53 switch (whence) {
54#define P_WHENCE(n) case SEEK_##n: return scnprintf(bf, size, #n)
55 P_WHENCE(SET);
56 P_WHENCE(CUR);
57 P_WHENCE(END);
58#ifdef SEEK_DATA
59 P_WHENCE(DATA);
60#endif
61#ifdef SEEK_HOLE
62 P_WHENCE(HOLE);
63#endif
64#undef P_WHENCE
65 default: break;
66 }
67
68 return scnprintf(bf, size, "%#x", whence);
69}
70
71#define SCA_WHENCE syscall_arg__scnprintf_whence
72
73static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
74 unsigned long arg,
75 u8 arg_idx __maybe_unused,
76 u8 *arg_mask __maybe_unused)
77{
78 int printed = 0, prot = arg;
79
80 if (prot == PROT_NONE)
81 return scnprintf(bf, size, "NONE");
82#define P_MMAP_PROT(n) \
83 if (prot & PROT_##n) { \
84 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
85 prot &= ~PROT_##n; \
86 }
87
88 P_MMAP_PROT(EXEC);
89 P_MMAP_PROT(READ);
90 P_MMAP_PROT(WRITE);
91#ifdef PROT_SEM
92 P_MMAP_PROT(SEM);
93#endif
94 P_MMAP_PROT(GROWSDOWN);
95 P_MMAP_PROT(GROWSUP);
96#undef P_MMAP_PROT
97
98 if (prot)
99 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
100
101 return printed;
102}
103
104#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
105
106static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
107 unsigned long arg, u8 arg_idx __maybe_unused,
108 u8 *arg_mask __maybe_unused)
109{
110 int printed = 0, flags = arg;
111
112#define P_MMAP_FLAG(n) \
113 if (flags & MAP_##n) { \
114 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
115 flags &= ~MAP_##n; \
116 }
117
118 P_MMAP_FLAG(SHARED);
119 P_MMAP_FLAG(PRIVATE);
120#ifdef MAP_32BIT
121 P_MMAP_FLAG(32BIT);
122#endif
123 P_MMAP_FLAG(ANONYMOUS);
124 P_MMAP_FLAG(DENYWRITE);
125 P_MMAP_FLAG(EXECUTABLE);
126 P_MMAP_FLAG(FILE);
127 P_MMAP_FLAG(FIXED);
128 P_MMAP_FLAG(GROWSDOWN);
129#ifdef MAP_HUGETLB
130 P_MMAP_FLAG(HUGETLB);
131#endif
132 P_MMAP_FLAG(LOCKED);
133 P_MMAP_FLAG(NONBLOCK);
134 P_MMAP_FLAG(NORESERVE);
135 P_MMAP_FLAG(POPULATE);
136 P_MMAP_FLAG(STACK);
137#ifdef MAP_UNINITIALIZED
138 P_MMAP_FLAG(UNINITIALIZED);
139#endif
140#undef P_MMAP_FLAG
141
142 if (flags)
143 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
144
145 return printed;
146}
147
148#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
149
150static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
151 unsigned long arg, u8 arg_idx __maybe_unused,
152 u8 *arg_mask __maybe_unused)
153{
154 int behavior = arg;
155
156 switch (behavior) {
157#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
158 P_MADV_BHV(NORMAL);
159 P_MADV_BHV(RANDOM);
160 P_MADV_BHV(SEQUENTIAL);
161 P_MADV_BHV(WILLNEED);
162 P_MADV_BHV(DONTNEED);
163 P_MADV_BHV(REMOVE);
164 P_MADV_BHV(DONTFORK);
165 P_MADV_BHV(DOFORK);
166 P_MADV_BHV(HWPOISON);
167#ifdef MADV_SOFT_OFFLINE
168 P_MADV_BHV(SOFT_OFFLINE);
169#endif
170 P_MADV_BHV(MERGEABLE);
171 P_MADV_BHV(UNMERGEABLE);
172#ifdef MADV_HUGEPAGE
173 P_MADV_BHV(HUGEPAGE);
174#endif
175#ifdef MADV_NOHUGEPAGE
176 P_MADV_BHV(NOHUGEPAGE);
177#endif
178#ifdef MADV_DONTDUMP
179 P_MADV_BHV(DONTDUMP);
180#endif
181#ifdef MADV_DODUMP
182 P_MADV_BHV(DODUMP);
183#endif
184#undef P_MADV_PHV
185 default: break;
186 }
187
188 return scnprintf(bf, size, "%#x", behavior);
189}
190
191#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
192
193static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned long arg,
194 u8 arg_idx __maybe_unused, u8 *arg_mask)
195{
196 enum syscall_futex_args {
197 SCF_UADDR = (1 << 0),
198 SCF_OP = (1 << 1),
199 SCF_VAL = (1 << 2),
200 SCF_TIMEOUT = (1 << 3),
201 SCF_UADDR2 = (1 << 4),
202 SCF_VAL3 = (1 << 5),
203 };
204 int op = arg;
205 int cmd = op & FUTEX_CMD_MASK;
206 size_t printed = 0;
207
208 switch (cmd) {
209#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;
211 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;
213 P_FUTEX_OP(REQUEUE); *arg_mask |= SCF_VAL3|SCF_TIMEOUT; break;
214 P_FUTEX_OP(CMP_REQUEUE); *arg_mask |= SCF_TIMEOUT; break;
215 P_FUTEX_OP(CMP_REQUEUE_PI); *arg_mask |= SCF_TIMEOUT; break;
216 P_FUTEX_OP(WAKE_OP); break;
217 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;
219 P_FUTEX_OP(TRYLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2; break;
220 P_FUTEX_OP(WAIT_BITSET); *arg_mask |= SCF_UADDR2; break;
221 P_FUTEX_OP(WAKE_BITSET); *arg_mask |= SCF_UADDR2; break;
222 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
223 default: printed = scnprintf(bf, size, "%#x", cmd); break;
224 }
225
226 if (op & FUTEX_PRIVATE_FLAG)
227 printed += scnprintf(bf + printed, size - printed, "|PRIV");
228
229 if (op & FUTEX_CLOCK_REALTIME)
230 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
231
232 return printed;
233}
234
235#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
236
237static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
238 unsigned long arg,
239 u8 arg_idx, u8 *arg_mask)
240{
241 int printed = 0, flags = arg;
242
243 if (!(flags & O_CREAT))
244 *arg_mask |= 1 << (arg_idx + 1); /* Mask the mode parm */
245
246 if (flags == 0)
247 return scnprintf(bf, size, "RDONLY");
248#define P_FLAG(n) \
249 if (flags & O_##n) { \
250 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
251 flags &= ~O_##n; \
252 }
253
254 P_FLAG(APPEND);
255 P_FLAG(ASYNC);
256 P_FLAG(CLOEXEC);
257 P_FLAG(CREAT);
258 P_FLAG(DIRECT);
259 P_FLAG(DIRECTORY);
260 P_FLAG(EXCL);
261 P_FLAG(LARGEFILE);
262 P_FLAG(NOATIME);
263 P_FLAG(NOCTTY);
264#ifdef O_NONBLOCK
265 P_FLAG(NONBLOCK);
266#elif O_NDELAY
267 P_FLAG(NDELAY);
268#endif
269#ifdef O_PATH
270 P_FLAG(PATH);
271#endif
272 P_FLAG(RDWR);
273#ifdef O_DSYNC
274 if ((flags & O_SYNC) == O_SYNC)
275 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
276 else {
277 P_FLAG(DSYNC);
278 }
279#else
280 P_FLAG(SYNC);
281#endif
282 P_FLAG(TRUNC);
283 P_FLAG(WRONLY);
284#undef P_FLAG
285
286 if (flags)
287 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
288
289 return printed;
290}
291
292#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
12 293
13static struct syscall_fmt { 294static struct syscall_fmt {
14 const char *name; 295 const char *name;
15 const char *alias; 296 const char *alias;
297 size_t (*arg_scnprintf[6])(char *bf, size_t size, unsigned long arg, u8 arg_idx, u8 *arg_mask);
16 bool errmsg; 298 bool errmsg;
17 bool timeout; 299 bool timeout;
300 bool hexret;
18} syscall_fmts[] = { 301} syscall_fmts[] = {
19 { .name = "access", .errmsg = true, }, 302 { .name = "access", .errmsg = true, },
20 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, 303 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
304 { .name = "brk", .hexret = true,
305 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
306 { .name = "mmap", .hexret = true, },
307 { .name = "connect", .errmsg = true, },
21 { .name = "fstat", .errmsg = true, .alias = "newfstat", }, 308 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
22 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, 309 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
23 { .name = "futex", .errmsg = true, }, 310 { .name = "futex", .errmsg = true,
24 { .name = "open", .errmsg = true, }, 311 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
312 { .name = "ioctl", .errmsg = true,
313 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
314 { .name = "lseek", .errmsg = true,
315 .arg_scnprintf = { [2] = SCA_WHENCE, /* whence */ }, },
316 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
317 { .name = "madvise", .errmsg = true,
318 .arg_scnprintf = { [0] = SCA_HEX, /* start */
319 [2] = SCA_MADV_BHV, /* behavior */ }, },
320 { .name = "mmap", .hexret = true,
321 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
322 [2] = SCA_MMAP_PROT, /* prot */
323 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
324 { .name = "mprotect", .errmsg = true,
325 .arg_scnprintf = { [0] = SCA_HEX, /* start */
326 [2] = SCA_MMAP_PROT, /* prot */ }, },
327 { .name = "mremap", .hexret = true,
328 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
329 [4] = SCA_HEX, /* new_addr */ }, },
330 { .name = "munmap", .errmsg = true,
331 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
332 { .name = "open", .errmsg = true,
333 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
334 { .name = "open_by_handle_at", .errmsg = true,
335 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
336 { .name = "openat", .errmsg = true,
337 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
25 { .name = "poll", .errmsg = true, .timeout = true, }, 338 { .name = "poll", .errmsg = true, .timeout = true, },
26 { .name = "ppoll", .errmsg = true, .timeout = true, }, 339 { .name = "ppoll", .errmsg = true, .timeout = true, },
340 { .name = "pread", .errmsg = true, .alias = "pread64", },
341 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
27 { .name = "read", .errmsg = true, }, 342 { .name = "read", .errmsg = true, },
28 { .name = "recvfrom", .errmsg = true, }, 343 { .name = "recvfrom", .errmsg = true, },
29 { .name = "select", .errmsg = true, .timeout = true, }, 344 { .name = "select", .errmsg = true, .timeout = true, },
30 { .name = "socket", .errmsg = true, }, 345 { .name = "socket", .errmsg = true, },
31 { .name = "stat", .errmsg = true, .alias = "newstat", }, 346 { .name = "stat", .errmsg = true, .alias = "newstat", },
347 { .name = "uname", .errmsg = true, .alias = "newuname", },
32}; 348};
33 349
34static int syscall_fmt__cmp(const void *name, const void *fmtp) 350static int syscall_fmt__cmp(const void *name, const void *fmtp)
@@ -46,7 +362,10 @@ static struct syscall_fmt *syscall_fmt__find(const char *name)
46struct syscall { 362struct syscall {
47 struct event_format *tp_format; 363 struct event_format *tp_format;
48 const char *name; 364 const char *name;
365 bool filtered;
49 struct syscall_fmt *fmt; 366 struct syscall_fmt *fmt;
367 size_t (**arg_scnprintf)(char *bf, size_t size,
368 unsigned long arg, u8 arg_idx, u8 *args_mask);
50}; 369};
51 370
52static size_t fprintf_duration(unsigned long t, FILE *fp) 371static size_t fprintf_duration(unsigned long t, FILE *fp)
@@ -60,7 +379,7 @@ static size_t fprintf_duration(unsigned long t, FILE *fp)
60 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration); 379 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
61 else 380 else
62 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration); 381 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
63 return printed + fprintf(stdout, "): "); 382 return printed + fprintf(fp, "): ");
64} 383}
65 384
66struct thread_trace { 385struct thread_trace {
@@ -77,7 +396,7 @@ static struct thread_trace *thread_trace__new(void)
77 return zalloc(sizeof(struct thread_trace)); 396 return zalloc(sizeof(struct thread_trace));
78} 397}
79 398
80static struct thread_trace *thread__trace(struct thread *thread) 399static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
81{ 400{
82 struct thread_trace *ttrace; 401 struct thread_trace *ttrace;
83 402
@@ -95,12 +414,13 @@ static struct thread_trace *thread__trace(struct thread *thread)
95 414
96 return ttrace; 415 return ttrace;
97fail: 416fail:
98 color_fprintf(stdout, PERF_COLOR_RED, 417 color_fprintf(fp, PERF_COLOR_RED,
99 "WARNING: not enough memory, dropping samples!\n"); 418 "WARNING: not enough memory, dropping samples!\n");
100 return NULL; 419 return NULL;
101} 420}
102 421
103struct trace { 422struct trace {
423 struct perf_tool tool;
104 int audit_machine; 424 int audit_machine;
105 struct { 425 struct {
106 int max; 426 int max;
@@ -109,7 +429,12 @@ struct trace {
109 struct perf_record_opts opts; 429 struct perf_record_opts opts;
110 struct machine host; 430 struct machine host;
111 u64 base_time; 431 u64 base_time;
432 FILE *output;
112 unsigned long nr_events; 433 unsigned long nr_events;
434 struct strlist *ev_qualifier;
435 bool not_ev_qualifier;
436 struct intlist *tid_list;
437 struct intlist *pid_list;
113 bool sched; 438 bool sched;
114 bool multiple_threads; 439 bool multiple_threads;
115 double duration_filter; 440 double duration_filter;
@@ -142,18 +467,19 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
142 printed += fprintf_duration(duration, fp); 467 printed += fprintf_duration(duration, fp);
143 468
144 if (trace->multiple_threads) 469 if (trace->multiple_threads)
145 printed += fprintf(fp, "%d ", thread->pid); 470 printed += fprintf(fp, "%d ", thread->tid);
146 471
147 return printed; 472 return printed;
148} 473}
149 474
150static int trace__process_event(struct machine *machine, union perf_event *event) 475static int trace__process_event(struct trace *trace, struct machine *machine,
476 union perf_event *event)
151{ 477{
152 int ret = 0; 478 int ret = 0;
153 479
154 switch (event->header.type) { 480 switch (event->header.type) {
155 case PERF_RECORD_LOST: 481 case PERF_RECORD_LOST:
156 color_fprintf(stdout, PERF_COLOR_RED, 482 color_fprintf(trace->output, PERF_COLOR_RED,
157 "LOST %" PRIu64 " events!\n", event->lost.lost); 483 "LOST %" PRIu64 " events!\n", event->lost.lost);
158 ret = machine__process_lost_event(machine, event); 484 ret = machine__process_lost_event(machine, event);
159 default: 485 default:
@@ -164,12 +490,13 @@ static int trace__process_event(struct machine *machine, union perf_event *event
164 return ret; 490 return ret;
165} 491}
166 492
167static int trace__tool_process(struct perf_tool *tool __maybe_unused, 493static int trace__tool_process(struct perf_tool *tool,
168 union perf_event *event, 494 union perf_event *event,
169 struct perf_sample *sample __maybe_unused, 495 struct perf_sample *sample __maybe_unused,
170 struct machine *machine) 496 struct machine *machine)
171{ 497{
172 return trace__process_event(machine, event); 498 struct trace *trace = container_of(tool, struct trace, tool);
499 return trace__process_event(trace, machine, event);
173} 500}
174 501
175static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) 502static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
@@ -183,11 +510,11 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
183 machine__create_kernel_maps(&trace->host); 510 machine__create_kernel_maps(&trace->host);
184 511
185 if (perf_target__has_task(&trace->opts.target)) { 512 if (perf_target__has_task(&trace->opts.target)) {
186 err = perf_event__synthesize_thread_map(NULL, evlist->threads, 513 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
187 trace__tool_process, 514 trace__tool_process,
188 &trace->host); 515 &trace->host);
189 } else { 516 } else {
190 err = perf_event__synthesize_threads(NULL, trace__tool_process, 517 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
191 &trace->host); 518 &trace->host);
192 } 519 }
193 520
@@ -197,6 +524,26 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
197 return err; 524 return err;
198} 525}
199 526
527static int syscall__set_arg_fmts(struct syscall *sc)
528{
529 struct format_field *field;
530 int idx = 0;
531
532 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
533 if (sc->arg_scnprintf == NULL)
534 return -1;
535
536 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
537 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
538 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
539 else if (field->flags & FIELD_IS_POINTER)
540 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
541 ++idx;
542 }
543
544 return 0;
545}
546
200static int trace__read_syscall_info(struct trace *trace, int id) 547static int trace__read_syscall_info(struct trace *trace, int id)
201{ 548{
202 char tp_name[128]; 549 char tp_name[128];
@@ -225,6 +572,20 @@ static int trace__read_syscall_info(struct trace *trace, int id)
225 572
226 sc = trace->syscalls.table + id; 573 sc = trace->syscalls.table + id;
227 sc->name = name; 574 sc->name = name;
575
576 if (trace->ev_qualifier) {
577 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
578
579 if (!(in ^ trace->not_ev_qualifier)) {
580 sc->filtered = true;
581 /*
582 * No need to do read tracepoint information since this will be
583 * filtered out.
584 */
585 return 0;
586 }
587 }
588
228 sc->fmt = syscall_fmt__find(sc->name); 589 sc->fmt = syscall_fmt__find(sc->name);
229 590
230 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); 591 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
@@ -235,7 +596,10 @@ static int trace__read_syscall_info(struct trace *trace, int id)
235 sc->tp_format = event_format__new("syscalls", tp_name); 596 sc->tp_format = event_format__new("syscalls", tp_name);
236 } 597 }
237 598
238 return sc->tp_format != NULL ? 0 : -1; 599 if (sc->tp_format == NULL)
600 return -1;
601
602 return syscall__set_arg_fmts(sc);
239} 603}
240 604
241static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, 605static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
@@ -246,11 +610,23 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
246 610
247 if (sc->tp_format != NULL) { 611 if (sc->tp_format != NULL) {
248 struct format_field *field; 612 struct format_field *field;
613 u8 mask = 0, bit = 1;
614
615 for (field = sc->tp_format->format.fields->next; field;
616 field = field->next, ++i, bit <<= 1) {
617 if (mask & bit)
618 continue;
249 619
250 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
251 printed += scnprintf(bf + printed, size - printed, 620 printed += scnprintf(bf + printed, size - printed,
252 "%s%s: %ld", printed ? ", " : "", 621 "%s%s: ", printed ? ", " : "", field->name);
253 field->name, args[i++]); 622
623 if (sc->arg_scnprintf && sc->arg_scnprintf[i]) {
624 printed += sc->arg_scnprintf[i](bf + printed, size - printed,
625 args[i], i, &mask);
626 } else {
627 printed += scnprintf(bf + printed, size - printed,
628 "%ld", args[i]);
629 }
254 } 630 }
255 } else { 631 } else {
256 while (i < 6) { 632 while (i < 6) {
@@ -274,7 +650,22 @@ static struct syscall *trace__syscall_info(struct trace *trace,
274 int id = perf_evsel__intval(evsel, sample, "id"); 650 int id = perf_evsel__intval(evsel, sample, "id");
275 651
276 if (id < 0) { 652 if (id < 0) {
277 printf("Invalid syscall %d id, skipping...\n", id); 653
654 /*
655 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
656 * before that, leaving at a higher verbosity level till that is
657 * explained. Reproduced with plain ftrace with:
658 *
659 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
660 * grep "NR -1 " /t/trace_pipe
661 *
662 * After generating some load on the machine.
663 */
664 if (verbose > 1) {
665 static u64 n;
666 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
667 id, perf_evsel__name(evsel), ++n);
668 }
278 return NULL; 669 return NULL;
279 } 670 }
280 671
@@ -288,10 +679,12 @@ static struct syscall *trace__syscall_info(struct trace *trace,
288 return &trace->syscalls.table[id]; 679 return &trace->syscalls.table[id];
289 680
290out_cant_read: 681out_cant_read:
291 printf("Problems reading syscall %d", id); 682 if (verbose) {
292 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL) 683 fprintf(trace->output, "Problems reading syscall %d", id);
293 printf("(%s)", trace->syscalls.table[id].name); 684 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
294 puts(" information"); 685 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
686 fputs(" information\n", trace->output);
687 }
295 return NULL; 688 return NULL;
296} 689}
297 690
@@ -301,16 +694,25 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
301 char *msg; 694 char *msg;
302 void *args; 695 void *args;
303 size_t printed = 0; 696 size_t printed = 0;
304 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid); 697 struct thread *thread;
305 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 698 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
306 struct thread_trace *ttrace = thread__trace(thread); 699 struct thread_trace *ttrace;
307 700
308 if (ttrace == NULL || sc == NULL) 701 if (sc == NULL)
702 return -1;
703
704 if (sc->filtered)
705 return 0;
706
707 thread = machine__findnew_thread(&trace->host, sample->pid,
708 sample->tid);
709 ttrace = thread__trace(thread, trace->output);
710 if (ttrace == NULL)
309 return -1; 711 return -1;
310 712
311 args = perf_evsel__rawptr(evsel, sample, "args"); 713 args = perf_evsel__rawptr(evsel, sample, "args");
312 if (args == NULL) { 714 if (args == NULL) {
313 printf("Problems reading syscall arguments\n"); 715 fprintf(trace->output, "Problems reading syscall arguments\n");
314 return -1; 716 return -1;
315 } 717 }
316 718
@@ -330,8 +732,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
330 732
331 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { 733 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
332 if (!trace->duration_filter) { 734 if (!trace->duration_filter) {
333 trace__fprintf_entry_head(trace, thread, 1, sample->time, stdout); 735 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
334 printf("%-70s\n", ttrace->entry_str); 736 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
335 } 737 }
336 } else 738 } else
337 ttrace->entry_pending = true; 739 ttrace->entry_pending = true;
@@ -344,11 +746,20 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
344{ 746{
345 int ret; 747 int ret;
346 u64 duration = 0; 748 u64 duration = 0;
347 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid); 749 struct thread *thread;
348 struct thread_trace *ttrace = thread__trace(thread);
349 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 750 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
751 struct thread_trace *ttrace;
350 752
351 if (ttrace == NULL || sc == NULL) 753 if (sc == NULL)
754 return -1;
755
756 if (sc->filtered)
757 return 0;
758
759 thread = machine__findnew_thread(&trace->host, sample->pid,
760 sample->tid);
761 ttrace = thread__trace(thread, trace->output);
762 if (ttrace == NULL)
352 return -1; 763 return -1;
353 764
354 ret = perf_evsel__intval(evsel, sample, "ret"); 765 ret = perf_evsel__intval(evsel, sample, "ret");
@@ -364,28 +775,33 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
364 } else if (trace->duration_filter) 775 } else if (trace->duration_filter)
365 goto out; 776 goto out;
366 777
367 trace__fprintf_entry_head(trace, thread, duration, sample->time, stdout); 778 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
368 779
369 if (ttrace->entry_pending) { 780 if (ttrace->entry_pending) {
370 printf("%-70s", ttrace->entry_str); 781 fprintf(trace->output, "%-70s", ttrace->entry_str);
371 } else { 782 } else {
372 printf(" ... ["); 783 fprintf(trace->output, " ... [");
373 color_fprintf(stdout, PERF_COLOR_YELLOW, "continued"); 784 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
374 printf("]: %s()", sc->name); 785 fprintf(trace->output, "]: %s()", sc->name);
375 } 786 }
376 787
377 if (ret < 0 && sc->fmt && sc->fmt->errmsg) { 788 if (sc->fmt == NULL) {
789signed_print:
790 fprintf(trace->output, ") = %d", ret);
791 } else if (ret < 0 && sc->fmt->errmsg) {
378 char bf[256]; 792 char bf[256];
379 const char *emsg = strerror_r(-ret, bf, sizeof(bf)), 793 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
380 *e = audit_errno_to_name(-ret); 794 *e = audit_errno_to_name(-ret);
381 795
382 printf(") = -1 %s %s", e, emsg); 796 fprintf(trace->output, ") = -1 %s %s", e, emsg);
383 } else if (ret == 0 && sc->fmt && sc->fmt->timeout) 797 } else if (ret == 0 && sc->fmt->timeout)
384 printf(") = 0 Timeout"); 798 fprintf(trace->output, ") = 0 Timeout");
799 else if (sc->fmt->hexret)
800 fprintf(trace->output, ") = %#x", ret);
385 else 801 else
386 printf(") = %d", ret); 802 goto signed_print;
387 803
388 putchar('\n'); 804 fputc('\n', trace->output);
389out: 805out:
390 ttrace->entry_pending = false; 806 ttrace->entry_pending = false;
391 807
@@ -397,8 +813,10 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs
397{ 813{
398 u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 814 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
399 double runtime_ms = (double)runtime / NSEC_PER_MSEC; 815 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
400 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid); 816 struct thread *thread = machine__findnew_thread(&trace->host,
401 struct thread_trace *ttrace = thread__trace(thread); 817 sample->pid,
818 sample->tid);
819 struct thread_trace *ttrace = thread__trace(thread, trace->output);
402 820
403 if (ttrace == NULL) 821 if (ttrace == NULL)
404 goto out_dump; 822 goto out_dump;
@@ -408,7 +826,7 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs
408 return 0; 826 return 0;
409 827
410out_dump: 828out_dump:
411 printf("%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n", 829 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
412 evsel->name, 830 evsel->name,
413 perf_evsel__strval(evsel, sample, "comm"), 831 perf_evsel__strval(evsel, sample, "comm"),
414 (pid_t)perf_evsel__intval(evsel, sample, "pid"), 832 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
@@ -417,6 +835,72 @@ out_dump:
417 return 0; 835 return 0;
418} 836}
419 837
838static bool skip_sample(struct trace *trace, struct perf_sample *sample)
839{
840 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
841 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
842 return false;
843
844 if (trace->pid_list || trace->tid_list)
845 return true;
846
847 return false;
848}
849
850static int trace__process_sample(struct perf_tool *tool,
851 union perf_event *event __maybe_unused,
852 struct perf_sample *sample,
853 struct perf_evsel *evsel,
854 struct machine *machine __maybe_unused)
855{
856 struct trace *trace = container_of(tool, struct trace, tool);
857 int err = 0;
858
859 tracepoint_handler handler = evsel->handler.func;
860
861 if (skip_sample(trace, sample))
862 return 0;
863
864 if (trace->base_time == 0)
865 trace->base_time = sample->time;
866
867 if (handler)
868 handler(trace, evsel, sample);
869
870 return err;
871}
872
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)
884{
885 if (trace->opts.target.pid) {
886 trace->pid_list = intlist__new(trace->opts.target.pid);
887 if (trace->pid_list == NULL) {
888 pr_err("Error parsing process id string\n");
889 return -EINVAL;
890 }
891 }
892
893 if (trace->opts.target.tid) {
894 trace->tid_list = intlist__new(trace->opts.target.tid);
895 if (trace->tid_list == NULL) {
896 pr_err("Error parsing thread id string\n");
897 return -EINVAL;
898 }
899 }
900
901 return 0;
902}
903
420static int trace__run(struct trace *trace, int argc, const char **argv) 904static int trace__run(struct trace *trace, int argc, const char **argv)
421{ 905{
422 struct perf_evlist *evlist = perf_evlist__new(); 906 struct perf_evlist *evlist = perf_evlist__new();
@@ -426,32 +910,32 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
426 const bool forks = argc > 0; 910 const bool forks = argc > 0;
427 911
428 if (evlist == NULL) { 912 if (evlist == NULL) {
429 printf("Not enough memory to run!\n"); 913 fprintf(trace->output, "Not enough memory to run!\n");
430 goto out; 914 goto out;
431 } 915 }
432 916
433 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || 917 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
434 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) { 918 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
435 printf("Couldn't read the raw_syscalls tracepoints information!\n"); 919 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
436 goto out_delete_evlist; 920 goto out_delete_evlist;
437 } 921 }
438 922
439 if (trace->sched && 923 if (trace->sched &&
440 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 924 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
441 trace__sched_stat_runtime)) { 925 trace__sched_stat_runtime)) {
442 printf("Couldn't read the sched_stat_runtime tracepoint information!\n"); 926 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
443 goto out_delete_evlist; 927 goto out_delete_evlist;
444 } 928 }
445 929
446 err = perf_evlist__create_maps(evlist, &trace->opts.target); 930 err = perf_evlist__create_maps(evlist, &trace->opts.target);
447 if (err < 0) { 931 if (err < 0) {
448 printf("Problems parsing the target to trace, check your options!\n"); 932 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
449 goto out_delete_evlist; 933 goto out_delete_evlist;
450 } 934 }
451 935
452 err = trace__symbols_init(trace, evlist); 936 err = trace__symbols_init(trace, evlist);
453 if (err < 0) { 937 if (err < 0) {
454 printf("Problems initializing symbol libraries!\n"); 938 fprintf(trace->output, "Problems initializing symbol libraries!\n");
455 goto out_delete_maps; 939 goto out_delete_maps;
456 } 940 }
457 941
@@ -464,20 +948,20 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
464 err = perf_evlist__prepare_workload(evlist, &trace->opts.target, 948 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
465 argv, false, false); 949 argv, false, false);
466 if (err < 0) { 950 if (err < 0) {
467 printf("Couldn't run the workload!\n"); 951 fprintf(trace->output, "Couldn't run the workload!\n");
468 goto out_delete_maps; 952 goto out_delete_maps;
469 } 953 }
470 } 954 }
471 955
472 err = perf_evlist__open(evlist); 956 err = perf_evlist__open(evlist);
473 if (err < 0) { 957 if (err < 0) {
474 printf("Couldn't create the events: %s\n", strerror(errno)); 958 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
475 goto out_delete_maps; 959 goto out_delete_maps;
476 } 960 }
477 961
478 err = perf_evlist__mmap(evlist, UINT_MAX, false); 962 err = perf_evlist__mmap(evlist, UINT_MAX, false);
479 if (err < 0) { 963 if (err < 0) {
480 printf("Couldn't mmap the events: %s\n", strerror(errno)); 964 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
481 goto out_close_evlist; 965 goto out_close_evlist;
482 } 966 }
483 967
@@ -502,7 +986,7 @@ again:
502 986
503 err = perf_evlist__parse_sample(evlist, event, &sample); 987 err = perf_evlist__parse_sample(evlist, event, &sample);
504 if (err) { 988 if (err) {
505 printf("Can't parse sample, err = %d, skipping...\n", err); 989 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
506 continue; 990 continue;
507 } 991 }
508 992
@@ -510,18 +994,18 @@ again:
510 trace->base_time = sample.time; 994 trace->base_time = sample.time;
511 995
512 if (type != PERF_RECORD_SAMPLE) { 996 if (type != PERF_RECORD_SAMPLE) {
513 trace__process_event(&trace->host, event); 997 trace__process_event(trace, &trace->host, event);
514 continue; 998 continue;
515 } 999 }
516 1000
517 evsel = perf_evlist__id2evsel(evlist, sample.id); 1001 evsel = perf_evlist__id2evsel(evlist, sample.id);
518 if (evsel == NULL) { 1002 if (evsel == NULL) {
519 printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); 1003 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
520 continue; 1004 continue;
521 } 1005 }
522 1006
523 if (sample.raw_data == NULL) { 1007 if (sample.raw_data == NULL) {
524 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 1008 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
525 perf_evsel__name(evsel), sample.tid, 1009 perf_evsel__name(evsel), sample.tid,
526 sample.cpu, sample.raw_size); 1010 sample.cpu, sample.raw_size);
527 continue; 1011 continue;
@@ -529,6 +1013,9 @@ again:
529 1013
530 handler = evsel->handler.func; 1014 handler = evsel->handler.func;
531 handler(trace, evsel, &sample); 1015 handler(trace, evsel, &sample);
1016
1017 if (done)
1018 goto out_unmap_evlist;
532 } 1019 }
533 } 1020 }
534 1021
@@ -556,6 +1043,70 @@ out:
556 return err; 1043 return err;
557} 1044}
558 1045
1046static int trace__replay(struct trace *trace)
1047{
1048 const struct perf_evsel_str_handler handlers[] = {
1049 { "raw_syscalls:sys_enter", trace__sys_enter, },
1050 { "raw_syscalls:sys_exit", trace__sys_exit, },
1051 };
1052
1053 struct perf_session *session;
1054 int err = -1;
1055
1056 trace->tool.sample = trace__process_sample;
1057 trace->tool.mmap = perf_event__process_mmap;
1058 trace->tool.mmap2 = perf_event__process_mmap2;
1059 trace->tool.comm = perf_event__process_comm;
1060 trace->tool.exit = perf_event__process_exit;
1061 trace->tool.fork = perf_event__process_fork;
1062 trace->tool.attr = perf_event__process_attr;
1063 trace->tool.tracing_data = perf_event__process_tracing_data;
1064 trace->tool.build_id = perf_event__process_build_id;
1065
1066 trace->tool.ordered_samples = true;
1067 trace->tool.ordering_requires_timestamps = true;
1068
1069 /* add tid to output */
1070 trace->multiple_threads = true;
1071
1072 if (symbol__init() < 0)
1073 return -1;
1074
1075 session = perf_session__new(input_name, O_RDONLY, 0, false,
1076 &trace->tool);
1077 if (session == NULL)
1078 return -ENOMEM;
1079
1080 err = perf_session__set_tracepoints_handlers(session, handlers);
1081 if (err)
1082 goto out;
1083
1084 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1085 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1086 goto out;
1087 }
1088
1089 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1090 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1091 goto out;
1092 }
1093
1094 err = parse_target_str(trace);
1095 if (err != 0)
1096 goto out;
1097
1098 setup_pager();
1099
1100 err = perf_session__process_events(session, &trace->tool);
1101 if (err)
1102 pr_err("Failed to process events, error %d", err);
1103
1104out:
1105 perf_session__delete(session);
1106
1107 return err;
1108}
1109
559static size_t trace__fprintf_threads_header(FILE *fp) 1110static size_t trace__fprintf_threads_header(FILE *fp)
560{ 1111{
561 size_t printed; 1112 size_t printed;
@@ -593,7 +1144,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
593 color = PERF_COLOR_YELLOW; 1144 color = PERF_COLOR_YELLOW;
594 1145
595 printed += color_fprintf(fp, color, "%20s", thread->comm); 1146 printed += color_fprintf(fp, color, "%20s", thread->comm);
596 printed += fprintf(fp, " - %-5d :%11lu [", thread->pid, ttrace->nr_events); 1147 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
597 printed += color_fprintf(fp, color, "%5.1f%%", ratio); 1148 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
598 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); 1149 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
599 } 1150 }
@@ -610,6 +1161,23 @@ static int trace__set_duration(const struct option *opt, const char *str,
610 return 0; 1161 return 0;
611} 1162}
612 1163
1164static int trace__open_output(struct trace *trace, const char *filename)
1165{
1166 struct stat st;
1167
1168 if (!stat(filename, &st) && st.st_size) {
1169 char oldname[PATH_MAX];
1170
1171 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1172 unlink(oldname);
1173 rename(filename, oldname);
1174 }
1175
1176 trace->output = fopen(filename, "w");
1177
1178 return trace->output == NULL ? -errno : 0;
1179}
1180
613int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) 1181int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
614{ 1182{
615 const char * const trace_usage[] = { 1183 const char * const trace_usage[] = {
@@ -632,26 +1200,34 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
632 .no_delay = true, 1200 .no_delay = true,
633 .mmap_pages = 1024, 1201 .mmap_pages = 1024,
634 }, 1202 },
1203 .output = stdout,
635 }; 1204 };
1205 const char *output_name = NULL;
1206 const char *ev_qualifier_str = NULL;
636 const struct option trace_options[] = { 1207 const struct option trace_options[] = {
1208 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1209 "list of events to trace"),
1210 OPT_STRING('o', "output", &output_name, "file", "output file name"),
1211 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
637 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid", 1212 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
638 "trace events on existing process id"), 1213 "trace events on existing process id"),
639 OPT_STRING(0, "tid", &trace.opts.target.tid, "tid", 1214 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
640 "trace events on existing thread id"), 1215 "trace events on existing thread id"),
641 OPT_BOOLEAN(0, "all-cpus", &trace.opts.target.system_wide, 1216 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
642 "system-wide collection from all CPUs"), 1217 "system-wide collection from all CPUs"),
643 OPT_STRING(0, "cpu", &trace.opts.target.cpu_list, "cpu", 1218 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
644 "list of cpus to monitor"), 1219 "list of cpus to monitor"),
645 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit, 1220 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
646 "child tasks do not inherit counters"), 1221 "child tasks do not inherit counters"),
647 OPT_UINTEGER(0, "mmap-pages", &trace.opts.mmap_pages, 1222 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
648 "number of mmap data pages"), 1223 "number of mmap data pages"),
649 OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user", 1224 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
650 "user to profile"), 1225 "user to profile"),
651 OPT_CALLBACK(0, "duration", &trace, "float", 1226 OPT_CALLBACK(0, "duration", &trace, "float",
652 "show only events with duration > N.M ms", 1227 "show only events with duration > N.M ms",
653 trace__set_duration), 1228 trace__set_duration),
654 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"), 1229 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
1230 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
655 OPT_END() 1231 OPT_END()
656 }; 1232 };
657 int err; 1233 int err;
@@ -659,27 +1235,57 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
659 1235
660 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 1236 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
661 1237
1238 if (output_name != NULL) {
1239 err = trace__open_output(&trace, output_name);
1240 if (err < 0) {
1241 perror("failed to create output file");
1242 goto out;
1243 }
1244 }
1245
1246 if (ev_qualifier_str != NULL) {
1247 const char *s = ev_qualifier_str;
1248
1249 trace.not_ev_qualifier = *s == '!';
1250 if (trace.not_ev_qualifier)
1251 ++s;
1252 trace.ev_qualifier = strlist__new(true, s);
1253 if (trace.ev_qualifier == NULL) {
1254 fputs("Not enough memory to parse event qualifier",
1255 trace.output);
1256 err = -ENOMEM;
1257 goto out_close;
1258 }
1259 }
1260
662 err = perf_target__validate(&trace.opts.target); 1261 err = perf_target__validate(&trace.opts.target);
663 if (err) { 1262 if (err) {
664 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 1263 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
665 printf("%s", bf); 1264 fprintf(trace.output, "%s", bf);
666 return err; 1265 goto out_close;
667 } 1266 }
668 1267
669 err = perf_target__parse_uid(&trace.opts.target); 1268 err = perf_target__parse_uid(&trace.opts.target);
670 if (err) { 1269 if (err) {
671 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 1270 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
672 printf("%s", bf); 1271 fprintf(trace.output, "%s", bf);
673 return err; 1272 goto out_close;
674 } 1273 }
675 1274
676 if (!argc && perf_target__none(&trace.opts.target)) 1275 if (!argc && perf_target__none(&trace.opts.target))
677 trace.opts.target.system_wide = true; 1276 trace.opts.target.system_wide = true;
678 1277
679 err = trace__run(&trace, argc, argv); 1278 if (input_name)
1279 err = trace__replay(&trace);
1280 else
1281 err = trace__run(&trace, argc, argv);
680 1282
681 if (trace.sched && !err) 1283 if (trace.sched && !err)
682 trace__fprintf_thread_summary(&trace, stdout); 1284 trace__fprintf_thread_summary(&trace, trace.output);
683 1285
1286out_close:
1287 if (output_name != NULL)
1288 fclose(trace.output);
1289out:
684 return err; 1290 return err;
685} 1291}
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
new file mode 100644
index 000000000000..5f6f9b3271bb
--- /dev/null
+++ b/tools/perf/config/Makefile
@@ -0,0 +1,481 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not)
2
3ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
4 -e s/arm.*/arm/ -e s/sa110/arm/ \
5 -e s/s390x/s390/ -e s/parisc64/parisc/ \
6 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
7 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
8NO_PERF_REGS := 1
9CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
10
11# Additional ARCH settings for x86
12ifeq ($(ARCH),i386)
13 override ARCH := x86
14 NO_PERF_REGS := 0
15 LIBUNWIND_LIBS = -lunwind -lunwind-x86
16endif
17
18ifeq ($(ARCH),x86_64)
19 override ARCH := x86
20 IS_X86_64 := 0
21 ifeq (, $(findstring m32,$(CFLAGS)))
22 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1)
23 endif
24 ifeq (${IS_X86_64}, 1)
25 RAW_ARCH := x86_64
26 CFLAGS += -DARCH_X86_64
27 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
28 endif
29 NO_PERF_REGS := 0
30 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
31endif
32
33ifeq ($(NO_PERF_REGS),0)
34 CFLAGS += -DHAVE_PERF_REGS
35endif
36
37ifeq ($(src-perf),)
38src-perf := $(srctree)/tools/perf
39endif
40
41ifeq ($(obj-perf),)
42obj-perf := $(OUTPUT)
43endif
44
45ifneq ($(obj-perf),)
46obj-perf := $(abspath $(obj-perf))/
47endif
48
49LIB_INCLUDE := $(srctree)/tools/lib/
50
51# include ARCH specific config
52-include $(src-perf)/arch/$(ARCH)/Makefile
53
54include $(src-perf)/config/feature-tests.mak
55include $(src-perf)/config/utilities.mak
56
57ifeq ($(call get-executable,$(FLEX)),)
58 dummy := $(error Error: $(FLEX) is missing on this system, please install it)
59endif
60
61ifeq ($(call get-executable,$(BISON)),)
62 dummy := $(error Error: $(BISON) is missing on this system, please install it)
63endif
64
65# Treat warnings as errors unless directed not to
66ifneq ($(WERROR),0)
67 CFLAGS += -Werror
68endif
69
70ifeq ("$(origin DEBUG)", "command line")
71 PERF_DEBUG = $(DEBUG)
72endif
73ifndef PERF_DEBUG
74 CFLAGS += -O6
75endif
76
77ifdef PARSER_DEBUG
78 PARSER_DEBUG_BISON := -t
79 PARSER_DEBUG_FLEX := -d
80 CFLAGS += -DPARSER_DEBUG
81endif
82
83CFLAGS += -fno-omit-frame-pointer
84CFLAGS += -ggdb3
85CFLAGS += -funwind-tables
86CFLAGS += -Wall
87CFLAGS += -Wextra
88CFLAGS += -std=gnu99
89
90EXTLIBS = -lelf -lpthread -lrt -lm -ldl
91
92ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
93 CFLAGS += -fstack-protector-all
94endif
95
96ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y)
97 CFLAGS += -Wstack-protector
98endif
99
100ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y)
101 CFLAGS += -Wvolatile-register-var
102endif
103
104ifndef PERF_DEBUG
105 ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -D_FORTIFY_SOURCE=2,-D_FORTIFY_SOURCE=2),y)
106 CFLAGS += -D_FORTIFY_SOURCE=2
107 endif
108endif
109
110CFLAGS += -I$(src-perf)/util/include
111CFLAGS += -I$(src-perf)/arch/$(ARCH)/include
112CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi
113CFLAGS += -I$(srctree)/arch/$(ARCH)/include
114CFLAGS += -I$(srctree)/include/uapi
115CFLAGS += -I$(srctree)/include
116
117# $(obj-perf) for generated common-cmds.h
118# $(obj-perf)/util for generated bison/flex headers
119ifneq ($(OUTPUT),)
120CFLAGS += -I$(obj-perf)/util
121CFLAGS += -I$(obj-perf)
122endif
123
124CFLAGS += -I$(src-perf)/util
125CFLAGS += -I$(src-perf)
126CFLAGS += -I$(LIB_INCLUDE)
127
128CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
129
130ifndef NO_BIONIC
131ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
132 BIONIC := 1
133 EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
134 EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
135endif
136endif # NO_BIONIC
137
138ifdef NO_LIBELF
139 NO_DWARF := 1
140 NO_DEMANGLE := 1
141 NO_LIBUNWIND := 1
142else
143FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
144ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
145 FLAGS_GLIBC=$(CFLAGS) $(LDFLAGS)
146 ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
147 LIBC_SUPPORT := 1
148 endif
149 ifeq ($(BIONIC),1)
150 LIBC_SUPPORT := 1
151 endif
152 ifeq ($(LIBC_SUPPORT),1)
153 msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
154
155 NO_LIBELF := 1
156 NO_DWARF := 1
157 NO_DEMANGLE := 1
158 else
159 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
160 endif
161else
162 # for linking with debug library, run like:
163 # make DEBUG=1 LIBDW_DIR=/opt/libdw/
164 ifdef LIBDW_DIR
165 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
166 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
167 endif
168
169 FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lz -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS)
170 ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
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);
172 NO_DWARF := 1
173 endif # Dwarf support
174endif # SOURCE_LIBELF
175endif # NO_LIBELF
176
177ifndef NO_LIBELF
178CFLAGS += -DLIBELF_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
187# include ARCH specific config
188-include $(src-perf)/arch/$(ARCH)/Makefile
189
190ifndef NO_DWARF
191ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
192 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
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
201endif # NO_LIBELF
202
203ifndef NO_LIBELF
204CFLAGS += -DLIBELF_SUPPORT
205FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
206ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
207 CFLAGS += -DLIBELF_MMAP
208endif # try-cc
209endif # NO_LIBELF
210
211# There's only x86 (both 32 and 64) support for CFI unwind so far
212ifneq ($(ARCH),x86)
213 NO_LIBUNWIND := 1
214endif
215
216ifndef NO_LIBUNWIND
217# for linking with debug library, run like:
218# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
219ifdef LIBUNWIND_DIR
220 LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
221 LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
222endif
223
224FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(CFLAGS) $(LIBUNWIND_LDFLAGS) $(LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
225ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
226 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
227 NO_LIBUNWIND := 1
228endif # Libunwind support
229endif # NO_LIBUNWIND
230
231ifndef NO_LIBUNWIND
232 CFLAGS += -DLIBUNWIND_SUPPORT
233 EXTLIBS += $(LIBUNWIND_LIBS)
234 CFLAGS += $(LIBUNWIND_CFLAGS)
235 LDFLAGS += $(LIBUNWIND_LDFLAGS)
236endif # NO_LIBUNWIND
237
238ifndef NO_LIBAUDIT
239 FLAGS_LIBAUDIT = $(CFLAGS) $(LDFLAGS) -laudit
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);
242 NO_LIBAUDIT := 1
243 else
244 CFLAGS += -DLIBAUDIT_SUPPORT
245 EXTLIBS += -laudit
246 endif
247endif
248
249ifdef NO_NEWT
250 NO_SLANG=1
251endif
252
253ifndef NO_SLANG
254 FLAGS_SLANG=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang
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);
257 NO_SLANG := 1
258 else
259 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
260 CFLAGS += -I/usr/include/slang
261 CFLAGS += -DSLANG_SUPPORT
262 EXTLIBS += -lslang
263 endif
264endif
265
266ifndef NO_GTK2
267 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)
269 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
270 NO_GTK2 := 1
271 else
272 ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y)
273 CFLAGS += -DHAVE_GTK_INFO_BAR
274 endif
275 CFLAGS += -DGTK2_SUPPORT
276 CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
277 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
278 endif
279endif
280
281grep-libs = $(filter -l%,$(1))
282strip-libs = $(filter-out -l%,$(1))
283
284ifdef NO_LIBPERL
285 CFLAGS += -DNO_LIBPERL
286else
287 PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
288 PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
289 PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
290 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
291 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
292
293 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y)
294 CFLAGS += -DNO_LIBPERL
295 NO_LIBPERL := 1
296 else
297 LDFLAGS += $(PERL_EMBED_LDFLAGS)
298 EXTLIBS += $(PERL_EMBED_LIBADD)
299 endif
300endif
301
302disable-python = $(eval $(disable-python_code))
303define disable-python_code
304 CFLAGS += -DNO_LIBPYTHON
305 $(if $(1),$(warning No $(1) was found))
306 $(warning Python support will not be built)
307 NO_LIBPYTHON := 1
308endef
309
310override PYTHON := \
311 $(call get-executable-or-default,PYTHON,python)
312
313ifndef PYTHON
314 $(call disable-python,python interpreter)
315else
316
317 PYTHON_WORD := $(call shell-wordify,$(PYTHON))
318
319 ifdef NO_LIBPYTHON
320 $(call disable-python)
321 else
322
323 override PYTHON_CONFIG := \
324 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
325
326 ifndef PYTHON_CONFIG
327 $(call disable-python,python-config tool)
328 else
329
330 PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
331
332 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
333 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
334 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
335 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
336 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
337
338 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y)
339 $(call disable-python,Python.h (for Python 2.x))
340 else
341
342 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y)
343 $(warning Python 3 is not yet supported; please set)
344 $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
345 $(warning If you also have Python 2 installed, then)
346 $(warning try something like:)
347 $(warning $(and ,))
348 $(warning $(and ,) make PYTHON=python2)
349 $(warning $(and ,))
350 $(warning Otherwise, disable Python support entirely:)
351 $(warning $(and ,))
352 $(warning $(and ,) make NO_LIBPYTHON=1)
353 $(warning $(and ,))
354 $(error $(and ,))
355 else
356 LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
357 EXTLIBS += $(PYTHON_EMBED_LIBADD)
358 LANG_BINDINGS += $(obj-perf)python/perf.so
359 endif
360 endif
361 endif
362 endif
363endif
364
365ifdef NO_DEMANGLE
366 CFLAGS += -DNO_DEMANGLE
367else
368 ifdef HAVE_CPLUS_DEMANGLE
369 EXTLIBS += -liberty
370 CFLAGS += -DHAVE_CPLUS_DEMANGLE
371 else
372 FLAGS_BFD=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
373 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd)
374 ifeq ($(has_bfd),y)
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
381 else
382 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
383 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz)
384 ifeq ($(has_bfd_iberty_z),y)
385 EXTLIBS += -lbfd -liberty -lz
386 else
387 FLAGS_CPLUS_DEMANGLE=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -liberty
388 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle)
389 ifeq ($(has_cplus_demangle),y)
390 EXTLIBS += -liberty
391 CFLAGS += -DHAVE_CPLUS_DEMANGLE
392 else
393 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
394 CFLAGS += -DNO_DEMANGLE
395 endif
396 endif
397 endif
398 endif
399 endif
400endif
401
402ifndef NO_STRLCPY
403 ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y)
404 CFLAGS += -DHAVE_STRLCPY
405 endif
406endif
407
408ifndef NO_ON_EXIT
409 ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y)
410 CFLAGS += -DHAVE_ON_EXIT
411 endif
412endif
413
414ifndef NO_BACKTRACE
415 ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y)
416 CFLAGS += -DBACKTRACE_SUPPORT
417 endif
418endif
419
420ifndef NO_LIBNUMA
421 FLAGS_LIBNUMA = $(CFLAGS) $(LDFLAGS) -lnuma
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);
424 NO_LIBNUMA := 1
425 else
426 CFLAGS += -DLIBNUMA_SUPPORT
427 EXTLIBS += -lnuma
428 endif
429endif
430
431# Among the variables below, these:
432# perfexecdir
433# template_dir
434# mandir
435# infodir
436# htmldir
437# ETC_PERFCONFIG (but not sysconfdir)
438# can be specified as a relative path some/where/else;
439# this is interpreted as relative to $(prefix) and "perf" at
440# runtime figures out where they are based on the path to the executable.
441# This can help installing the suite in a relocatable way.
442
443# Make the path relative to DESTDIR, not to prefix
444ifndef DESTDIR
445prefix = $(HOME)
446endif
447bindir_relative = bin
448bindir = $(prefix)/$(bindir_relative)
449mandir = share/man
450infodir = share/info
451perfexecdir = libexec/perf-core
452sharedir = $(prefix)/share
453template_dir = share/perf-core/templates
454htmldir = share/doc/perf-doc
455ifeq ($(prefix),/usr)
456sysconfdir = /etc
457ETC_PERFCONFIG = $(sysconfdir)/perfconfig
458else
459sysconfdir = $(prefix)/etc
460ETC_PERFCONFIG = etc/perfconfig
461endif
462lib = lib
463
464# Shell quote (do not use $(call) to accommodate ancient setups);
465ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
466DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
467bindir_SQ = $(subst ','\'',$(bindir))
468mandir_SQ = $(subst ','\'',$(mandir))
469infodir_SQ = $(subst ','\'',$(infodir))
470perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
471template_dir_SQ = $(subst ','\'',$(template_dir))
472htmldir_SQ = $(subst ','\'',$(htmldir))
473prefix_SQ = $(subst ','\'',$(prefix))
474sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
475
476ifneq ($(filter /%,$(firstword $(perfexecdir))),)
477perfexec_instdir = $(perfexecdir)
478else
479perfexec_instdir = $(prefix)/$(perfexecdir)
480endif
481perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index 708fb8e9822a..d5a8dd44945f 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -61,6 +61,15 @@ int main(void)
61} 61}
62endef 62endef
63 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
64ifndef NO_SLANG 73ifndef NO_SLANG
65define SOURCE_SLANG 74define SOURCE_SLANG
66#include <slang.h> 75#include <slang.h>
@@ -210,6 +219,7 @@ define SOURCE_LIBAUDIT
210 219
211int main(void) 220int main(void)
212{ 221{
222 printf(\"error message: %s\n\", audit_errno_to_name(0));
213 return audit_open(); 223 return audit_open();
214} 224}
215endef 225endef
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index 8ef3bd30a549..94d2d4f9c35d 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -173,7 +173,7 @@ _ge-abspath = $(if $(is-executable),$(1))
173# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default) 173# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
174# 174#
175define get-executable-or-default 175define get-executable-or-default
176$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2),$(1))) 176$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
177endef 177endef
178_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2))) 178_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2)))
179_gea_warn = $(warning The path '$(1)' is not executable.) 179_gea_warn = $(warning The path '$(1)' is not executable.)
@@ -181,7 +181,7 @@ _gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
181 181
182# try-cc 182# try-cc
183# Usage: option = $(call try-cc, source-to-build, cc-options, msg) 183# Usage: option = $(call try-cc, source-to-build, cc-options, msg)
184ifndef V 184ifneq ($(V),1)
185TRY_CC_OUTPUT= > /dev/null 2>&1 185TRY_CC_OUTPUT= > /dev/null 2>&1
186endif 186endif
187TRY_CC_MSG=echo " CHK $(3)" 1>&2; 187TRY_CC_MSG=echo " CHK $(3)" 1>&2;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 32bd102c32b6..cf20187eee0a 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -125,6 +125,9 @@
125#ifndef NSEC_PER_SEC 125#ifndef NSEC_PER_SEC
126# define NSEC_PER_SEC 1000000000ULL 126# define NSEC_PER_SEC 1000000000ULL
127#endif 127#endif
128#ifndef NSEC_PER_USEC
129# define NSEC_PER_USEC 1000ULL
130#endif
128 131
129static inline unsigned long long rdclock(void) 132static inline unsigned long long rdclock(void)
130{ 133{
diff --git a/tools/perf/python/twatch.py b/tools/perf/python/twatch.py
index b11cca584238..2225162ee1fc 100755
--- a/tools/perf/python/twatch.py
+++ b/tools/perf/python/twatch.py
@@ -21,7 +21,7 @@ def main():
21 evsel = perf.evsel(task = 1, comm = 1, mmap = 0, 21 evsel = perf.evsel(task = 1, comm = 1, mmap = 0,
22 wakeup_events = 1, watermark = 1, 22 wakeup_events = 1, watermark = 1,
23 sample_id_all = 1, 23 sample_id_all = 1,
24 sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_TID) 24 sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU)
25 evsel.open(cpus = cpus, threads = threads); 25 evsel.open(cpus = cpus, threads = threads);
26 evlist = perf.evlist(cpus, threads) 26 evlist = perf.evlist(cpus, threads)
27 evlist.add(evsel) 27 evlist.add(evsel)
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
index c1e2ed1ed34e..8c7ea42444d1 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
@@ -23,7 +23,7 @@
23#include "perl.h" 23#include "perl.h"
24#include "XSUB.h" 24#include "XSUB.h"
25#include "../../../perf.h" 25#include "../../../perf.h"
26#include "../../../util/script-event.h" 26#include "../../../util/trace-event.h"
27 27
28MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context 28MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context
29PROTOTYPES: ENABLE 29PROTOTYPES: ENABLE
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record
index b4fc835de607..e9bd6391f2ae 100644
--- a/tools/perf/tests/attr/base-record
+++ b/tools/perf/tests/attr/base-record
@@ -27,8 +27,8 @@ watermark=0
27precise_ip=0 27precise_ip=0
28mmap_data=0 28mmap_data=0
29sample_id_all=1 29sample_id_all=1
30exclude_host=0 30exclude_host=0|1
31exclude_guest=1 31exclude_guest=0|1
32exclude_callchain_kernel=0 32exclude_callchain_kernel=0
33exclude_callchain_user=0 33exclude_callchain_user=0
34wakeup_events=0 34wakeup_events=0
diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat
index 748ee949a204..91cd48b399f3 100644
--- a/tools/perf/tests/attr/base-stat
+++ b/tools/perf/tests/attr/base-stat
@@ -27,8 +27,8 @@ watermark=0
27precise_ip=0 27precise_ip=0
28mmap_data=0 28mmap_data=0
29sample_id_all=0 29sample_id_all=0
30exclude_host=0 30exclude_host=0|1
31exclude_guest=1 31exclude_guest=0|1
32exclude_callchain_kernel=0 32exclude_callchain_kernel=0
33exclude_callchain_user=0 33exclude_callchain_user=0
34wakeup_events=0 34wakeup_events=0
diff --git a/tools/perf/tests/attr/test-record-data b/tools/perf/tests/attr/test-record-data
index 6627c3e7534a..716e143b5291 100644
--- a/tools/perf/tests/attr/test-record-data
+++ b/tools/perf/tests/attr/test-record-data
@@ -4,5 +4,8 @@ args = -d kill >/dev/null 2>&1
4 4
5[event:base-record] 5[event:base-record]
6sample_period=4000 6sample_period=4000
7sample_type=271 7
8# sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
9# PERF_SAMPLE_ADDR | PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC
10sample_type=33039
8mmap_data=1 11mmap_data=1
diff --git a/tools/perf/tests/attr/test-record-group-sampling b/tools/perf/tests/attr/test-record-group-sampling
new file mode 100644
index 000000000000..658f5d60c873
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-group-sampling
@@ -0,0 +1,36 @@
1[config]
2command = record
3args = -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
4
5[event-1:base-record]
6fd=1
7group_fd=-1
8sample_type=343
9read_format=12
10inherit=0
11
12[event-2:base-record]
13fd=2
14group_fd=1
15
16# cache-misses
17type=0
18config=3
19
20# default | PERF_SAMPLE_READ
21sample_type=343
22
23# PERF_FORMAT_ID | PERF_FORMAT_GROUP
24read_format=12
25
26mmap=0
27comm=0
28enable_on_exec=0
29disabled=0
30
31# inherit is disabled for group sampling
32inherit=0
33
34# sampling disabled
35sample_freq=0
36sample_period=0
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index 68daa289e94c..aba095489193 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -4,6 +4,12 @@
4 * (git://github.com/deater/perf_event_tests) 4 * (git://github.com/deater/perf_event_tests)
5 */ 5 */
6 6
7/*
8 * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
9 * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
10 */
11#define __SANE_USERSPACE_TYPES__
12
7#include <stdlib.h> 13#include <stdlib.h>
8#include <stdio.h> 14#include <stdio.h>
9#include <unistd.h> 15#include <unistd.h>
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c
index fe7ed28815f8..44ac82179708 100644
--- a/tools/perf/tests/bp_signal_overflow.c
+++ b/tools/perf/tests/bp_signal_overflow.c
@@ -3,6 +3,12 @@
3 * perf_event_tests (git://github.com/deater/perf_event_tests) 3 * perf_event_tests (git://github.com/deater/perf_event_tests)
4 */ 4 */
5 5
6/*
7 * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
8 * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
9 */
10#define __SANE_USERSPACE_TYPES__
11
6#include <stdlib.h> 12#include <stdlib.h>
7#include <stdio.h> 13#include <stdio.h>
8#include <unistd.h> 14#include <unistd.h>
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 0918ada4cc41..1e67437fb4ca 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -70,7 +70,7 @@ static struct test {
70 .func = test__attr, 70 .func = test__attr,
71 }, 71 },
72 { 72 {
73 .desc = "Test matching and linking mutliple hists", 73 .desc = "Test matching and linking multiple hists",
74 .func = test__hists_link, 74 .func = test__hists_link,
75 }, 75 },
76 { 76 {
@@ -93,6 +93,28 @@ static struct test {
93 .desc = "Test software clock events have valid period values", 93 .desc = "Test software clock events have valid period values",
94 .func = test__sw_clock_freq, 94 .func = test__sw_clock_freq,
95 }, 95 },
96#if defined(__x86_64__) || defined(__i386__)
97 {
98 .desc = "Test converting perf time to TSC",
99 .func = test__perf_time_to_tsc,
100 },
101#endif
102 {
103 .desc = "Test object code reading",
104 .func = test__code_reading,
105 },
106 {
107 .desc = "Test sample parsing",
108 .func = test__sample_parsing,
109 },
110 {
111 .desc = "Test using a dummy software event to keep tracking",
112 .func = test__keep_tracking,
113 },
114 {
115 .desc = "Test parsing with no sample_id_all bit set",
116 .func = test__parse_no_sample_id_all,
117 },
96 { 118 {
97 .func = NULL, 119 .func = NULL,
98 }, 120 },
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
new file mode 100644
index 000000000000..6fb781d5586c
--- /dev/null
+++ b/tools/perf/tests/code-reading.c
@@ -0,0 +1,572 @@
1#include <sys/types.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <stdio.h>
5#include <inttypes.h>
6#include <ctype.h>
7#include <string.h>
8
9#include "parse-events.h"
10#include "evlist.h"
11#include "evsel.h"
12#include "thread_map.h"
13#include "cpumap.h"
14#include "machine.h"
15#include "event.h"
16#include "thread.h"
17
18#include "tests.h"
19
20#define BUFSZ 1024
21#define READLEN 128
22
23struct state {
24 u64 done[1024];
25 size_t done_cnt;
26};
27
28static unsigned int hex(char c)
29{
30 if (c >= '0' && c <= '9')
31 return c - '0';
32 if (c >= 'a' && c <= 'f')
33 return c - 'a' + 10;
34 return c - 'A' + 10;
35}
36
37static void read_objdump_line(const char *line, size_t line_len, void **buf,
38 size_t *len)
39{
40 const char *p;
41 size_t i;
42
43 /* Skip to a colon */
44 p = strchr(line, ':');
45 if (!p)
46 return;
47 i = p + 1 - line;
48
49 /* Read bytes */
50 while (*len) {
51 char c1, c2;
52
53 /* Skip spaces */
54 for (; i < line_len; i++) {
55 if (!isspace(line[i]))
56 break;
57 }
58 /* Get 2 hex digits */
59 if (i >= line_len || !isxdigit(line[i]))
60 break;
61 c1 = line[i++];
62 if (i >= line_len || !isxdigit(line[i]))
63 break;
64 c2 = line[i++];
65 /* Followed by a space */
66 if (i < line_len && line[i] && !isspace(line[i]))
67 break;
68 /* Store byte */
69 *(unsigned char *)*buf = (hex(c1) << 4) | hex(c2);
70 *buf += 1;
71 *len -= 1;
72 }
73}
74
75static int read_objdump_output(FILE *f, void **buf, size_t *len)
76{
77 char *line = NULL;
78 size_t line_len;
79 ssize_t ret;
80 int err = 0;
81
82 while (1) {
83 ret = getline(&line, &line_len, f);
84 if (feof(f))
85 break;
86 if (ret < 0) {
87 pr_debug("getline failed\n");
88 err = -1;
89 break;
90 }
91 read_objdump_line(line, ret, buf, len);
92 }
93
94 free(line);
95
96 return err;
97}
98
99static int read_via_objdump(const char *filename, u64 addr, void *buf,
100 size_t len)
101{
102 char cmd[PATH_MAX * 2];
103 const char *fmt;
104 FILE *f;
105 int ret;
106
107 fmt = "%s -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";
108 ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len,
109 filename);
110 if (ret <= 0 || (size_t)ret >= sizeof(cmd))
111 return -1;
112
113 pr_debug("Objdump command is: %s\n", cmd);
114
115 /* Ignore objdump errors */
116 strcat(cmd, " 2>/dev/null");
117
118 f = popen(cmd, "r");
119 if (!f) {
120 pr_debug("popen failed\n");
121 return -1;
122 }
123
124 ret = read_objdump_output(f, &buf, &len);
125 if (len) {
126 pr_debug("objdump read too few bytes\n");
127 if (!ret)
128 ret = len;
129 }
130
131 pclose(f);
132
133 return ret;
134}
135
136static int read_object_code(u64 addr, size_t len, u8 cpumode,
137 struct thread *thread, struct machine *machine,
138 struct state *state)
139{
140 struct addr_location al;
141 unsigned char buf1[BUFSZ];
142 unsigned char buf2[BUFSZ];
143 size_t ret_len;
144 u64 objdump_addr;
145 int ret;
146
147 pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
148
149 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, addr,
150 &al);
151 if (!al.map || !al.map->dso) {
152 pr_debug("thread__find_addr_map failed\n");
153 return -1;
154 }
155
156 pr_debug("File is: %s\n", al.map->dso->long_name);
157
158 if (al.map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
159 !dso__is_kcore(al.map->dso)) {
160 pr_debug("Unexpected kernel address - skipping\n");
161 return 0;
162 }
163
164 pr_debug("On file address is: %#"PRIx64"\n", al.addr);
165
166 if (len > BUFSZ)
167 len = BUFSZ;
168
169 /* Do not go off the map */
170 if (addr + len > al.map->end)
171 len = al.map->end - addr;
172
173 /* Read the object code using perf */
174 ret_len = dso__data_read_offset(al.map->dso, machine, al.addr, buf1,
175 len);
176 if (ret_len != len) {
177 pr_debug("dso__data_read_offset failed\n");
178 return -1;
179 }
180
181 /*
182 * Converting addresses for use by objdump requires more information.
183 * map__load() does that. See map__rip_2objdump() for details.
184 */
185 if (map__load(al.map, NULL))
186 return -1;
187
188 /* objdump struggles with kcore - try each map only once */
189 if (dso__is_kcore(al.map->dso)) {
190 size_t d;
191
192 for (d = 0; d < state->done_cnt; d++) {
193 if (state->done[d] == al.map->start) {
194 pr_debug("kcore map tested already");
195 pr_debug(" - skipping\n");
196 return 0;
197 }
198 }
199 if (state->done_cnt >= ARRAY_SIZE(state->done)) {
200 pr_debug("Too many kcore maps - skipping\n");
201 return 0;
202 }
203 state->done[state->done_cnt++] = al.map->start;
204 }
205
206 /* Read the object code using objdump */
207 objdump_addr = map__rip_2objdump(al.map, al.addr);
208 ret = read_via_objdump(al.map->dso->long_name, objdump_addr, buf2, len);
209 if (ret > 0) {
210 /*
211 * The kernel maps are inaccurate - assume objdump is right in
212 * that case.
213 */
214 if (cpumode == PERF_RECORD_MISC_KERNEL ||
215 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) {
216 len -= ret;
217 if (len) {
218 pr_debug("Reducing len to %zu\n", len);
219 } else if (dso__is_kcore(al.map->dso)) {
220 /*
221 * objdump cannot handle very large segments
222 * that may be found in kcore.
223 */
224 pr_debug("objdump failed for kcore");
225 pr_debug(" - skipping\n");
226 return 0;
227 } else {
228 return -1;
229 }
230 }
231 }
232 if (ret < 0) {
233 pr_debug("read_via_objdump failed\n");
234 return -1;
235 }
236
237 /* The results should be identical */
238 if (memcmp(buf1, buf2, len)) {
239 pr_debug("Bytes read differ from those read by objdump\n");
240 return -1;
241 }
242 pr_debug("Bytes read match those read by objdump\n");
243
244 return 0;
245}
246
247static int process_sample_event(struct machine *machine,
248 struct perf_evlist *evlist,
249 union perf_event *event, struct state *state)
250{
251 struct perf_sample sample;
252 struct thread *thread;
253 u8 cpumode;
254
255 if (perf_evlist__parse_sample(evlist, event, &sample)) {
256 pr_debug("perf_evlist__parse_sample failed\n");
257 return -1;
258 }
259
260 thread = machine__findnew_thread(machine, sample.pid, sample.pid);
261 if (!thread) {
262 pr_debug("machine__findnew_thread failed\n");
263 return -1;
264 }
265
266 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
267
268 return read_object_code(sample.ip, READLEN, cpumode, thread, machine,
269 state);
270}
271
272static int process_event(struct machine *machine, struct perf_evlist *evlist,
273 union perf_event *event, struct state *state)
274{
275 if (event->header.type == PERF_RECORD_SAMPLE)
276 return process_sample_event(machine, evlist, event, state);
277
278 if (event->header.type < PERF_RECORD_MAX)
279 return machine__process_event(machine, event);
280
281 return 0;
282}
283
284static int process_events(struct machine *machine, struct perf_evlist *evlist,
285 struct state *state)
286{
287 union perf_event *event;
288 int i, ret;
289
290 for (i = 0; i < evlist->nr_mmaps; i++) {
291 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
292 ret = process_event(machine, evlist, event, state);
293 if (ret < 0)
294 return ret;
295 }
296 }
297 return 0;
298}
299
300static int comp(const void *a, const void *b)
301{
302 return *(int *)a - *(int *)b;
303}
304
305static void do_sort_something(void)
306{
307 int buf[40960], i;
308
309 for (i = 0; i < (int)ARRAY_SIZE(buf); i++)
310 buf[i] = ARRAY_SIZE(buf) - i - 1;
311
312 qsort(buf, ARRAY_SIZE(buf), sizeof(int), comp);
313
314 for (i = 0; i < (int)ARRAY_SIZE(buf); i++) {
315 if (buf[i] != i) {
316 pr_debug("qsort failed\n");
317 break;
318 }
319 }
320}
321
322static void sort_something(void)
323{
324 int i;
325
326 for (i = 0; i < 10; i++)
327 do_sort_something();
328}
329
330static void syscall_something(void)
331{
332 int pipefd[2];
333 int i;
334
335 for (i = 0; i < 1000; i++) {
336 if (pipe(pipefd) < 0) {
337 pr_debug("pipe failed\n");
338 break;
339 }
340 close(pipefd[1]);
341 close(pipefd[0]);
342 }
343}
344
345static void fs_something(void)
346{
347 const char *test_file_name = "temp-perf-code-reading-test-file--";
348 FILE *f;
349 int i;
350
351 for (i = 0; i < 1000; i++) {
352 f = fopen(test_file_name, "w+");
353 if (f) {
354 fclose(f);
355 unlink(test_file_name);
356 }
357 }
358}
359
360static void do_something(void)
361{
362 fs_something();
363
364 sort_something();
365
366 syscall_something();
367}
368
369enum {
370 TEST_CODE_READING_OK,
371 TEST_CODE_READING_NO_VMLINUX,
372 TEST_CODE_READING_NO_KCORE,
373 TEST_CODE_READING_NO_ACCESS,
374 TEST_CODE_READING_NO_KERNEL_OBJ,
375};
376
377static int do_test_code_reading(bool try_kcore)
378{
379 struct machines machines;
380 struct machine *machine;
381 struct thread *thread;
382 struct perf_record_opts opts = {
383 .mmap_pages = UINT_MAX,
384 .user_freq = UINT_MAX,
385 .user_interval = ULLONG_MAX,
386 .freq = 4000,
387 .target = {
388 .uses_mmap = true,
389 },
390 };
391 struct state state = {
392 .done_cnt = 0,
393 };
394 struct thread_map *threads = NULL;
395 struct cpu_map *cpus = NULL;
396 struct perf_evlist *evlist = NULL;
397 struct perf_evsel *evsel = NULL;
398 int err = -1, ret;
399 pid_t pid;
400 struct map *map;
401 bool have_vmlinux, have_kcore, excl_kernel = false;
402
403 pid = getpid();
404
405 machines__init(&machines);
406 machine = &machines.host;
407
408 ret = machine__create_kernel_maps(machine);
409 if (ret < 0) {
410 pr_debug("machine__create_kernel_maps failed\n");
411 goto out_err;
412 }
413
414 /* Force the use of kallsyms instead of vmlinux to try kcore */
415 if (try_kcore)
416 symbol_conf.kallsyms_name = "/proc/kallsyms";
417
418 /* Load kernel map */
419 map = machine->vmlinux_maps[MAP__FUNCTION];
420 ret = map__load(map, NULL);
421 if (ret < 0) {
422 pr_debug("map__load failed\n");
423 goto out_err;
424 }
425 have_vmlinux = dso__is_vmlinux(map->dso);
426 have_kcore = dso__is_kcore(map->dso);
427
428 /* 2nd time through we just try kcore */
429 if (try_kcore && !have_kcore)
430 return TEST_CODE_READING_NO_KCORE;
431
432 /* No point getting kernel events if there is no kernel object */
433 if (!have_vmlinux && !have_kcore)
434 excl_kernel = true;
435
436 threads = thread_map__new_by_tid(pid);
437 if (!threads) {
438 pr_debug("thread_map__new_by_tid failed\n");
439 goto out_err;
440 }
441
442 ret = perf_event__synthesize_thread_map(NULL, threads,
443 perf_event__process, machine);
444 if (ret < 0) {
445 pr_debug("perf_event__synthesize_thread_map failed\n");
446 goto out_err;
447 }
448
449 thread = machine__findnew_thread(machine, pid, pid);
450 if (!thread) {
451 pr_debug("machine__findnew_thread failed\n");
452 goto out_err;
453 }
454
455 cpus = cpu_map__new(NULL);
456 if (!cpus) {
457 pr_debug("cpu_map__new failed\n");
458 goto out_err;
459 }
460
461 while (1) {
462 const char *str;
463
464 evlist = perf_evlist__new();
465 if (!evlist) {
466 pr_debug("perf_evlist__new failed\n");
467 goto out_err;
468 }
469
470 perf_evlist__set_maps(evlist, cpus, threads);
471
472 if (excl_kernel)
473 str = "cycles:u";
474 else
475 str = "cycles";
476 pr_debug("Parsing event '%s'\n", str);
477 ret = parse_events(evlist, str);
478 if (ret < 0) {
479 pr_debug("parse_events failed\n");
480 goto out_err;
481 }
482
483 perf_evlist__config(evlist, &opts);
484
485 evsel = perf_evlist__first(evlist);
486
487 evsel->attr.comm = 1;
488 evsel->attr.disabled = 1;
489 evsel->attr.enable_on_exec = 0;
490
491 ret = perf_evlist__open(evlist);
492 if (ret < 0) {
493 if (!excl_kernel) {
494 excl_kernel = true;
495 perf_evlist__delete(evlist);
496 evlist = NULL;
497 continue;
498 }
499 pr_debug("perf_evlist__open failed\n");
500 goto out_err;
501 }
502 break;
503 }
504
505 ret = perf_evlist__mmap(evlist, UINT_MAX, false);
506 if (ret < 0) {
507 pr_debug("perf_evlist__mmap failed\n");
508 goto out_err;
509 }
510
511 perf_evlist__enable(evlist);
512
513 do_something();
514
515 perf_evlist__disable(evlist);
516
517 ret = process_events(machine, evlist, &state);
518 if (ret < 0)
519 goto out_err;
520
521 if (!have_vmlinux && !have_kcore && !try_kcore)
522 err = TEST_CODE_READING_NO_KERNEL_OBJ;
523 else if (!have_vmlinux && !try_kcore)
524 err = TEST_CODE_READING_NO_VMLINUX;
525 else if (excl_kernel)
526 err = TEST_CODE_READING_NO_ACCESS;
527 else
528 err = TEST_CODE_READING_OK;
529out_err:
530 if (evlist) {
531 perf_evlist__munmap(evlist);
532 perf_evlist__close(evlist);
533 perf_evlist__delete(evlist);
534 }
535 if (cpus)
536 cpu_map__delete(cpus);
537 if (threads)
538 thread_map__delete(threads);
539 machines__destroy_kernel_maps(&machines);
540 machine__delete_threads(machine);
541 machines__exit(&machines);
542
543 return err;
544}
545
546int test__code_reading(void)
547{
548 int ret;
549
550 ret = do_test_code_reading(false);
551 if (!ret)
552 ret = do_test_code_reading(true);
553
554 switch (ret) {
555 case TEST_CODE_READING_OK:
556 return 0;
557 case TEST_CODE_READING_NO_VMLINUX:
558 fprintf(stderr, " (no vmlinux)");
559 return 0;
560 case TEST_CODE_READING_NO_KCORE:
561 fprintf(stderr, " (no kcore)");
562 return 0;
563 case TEST_CODE_READING_NO_ACCESS:
564 fprintf(stderr, " (no access)");
565 return 0;
566 case TEST_CODE_READING_NO_KERNEL_OBJ:
567 fprintf(stderr, " (no kernel obj)");
568 return 0;
569 default:
570 return -1;
571 };
572}
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index 5eaffa2de9c5..dffe0551acaa 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -10,14 +10,6 @@
10#include "symbol.h" 10#include "symbol.h"
11#include "tests.h" 11#include "tests.h"
12 12
13#define TEST_ASSERT_VAL(text, cond) \
14do { \
15 if (!(cond)) { \
16 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
17 return -1; \
18 } \
19} while (0)
20
21static char *test_file(int size) 13static char *test_file(int size)
22{ 14{
23 static char buf_templ[] = "/tmp/test-XXXXXX"; 15 static char buf_templ[] = "/tmp/test-XXXXXX";
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index a5d2fcc5ae35..9b98c1554833 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -1,6 +1,6 @@
1#include <traceevent/event-parse.h>
1#include "evsel.h" 2#include "evsel.h"
2#include "tests.h" 3#include "tests.h"
3#include "event-parse.h"
4 4
5static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, 5static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
6 int size, bool should_be_signed) 6 int size, bool should_be_signed)
@@ -49,7 +49,7 @@ int test__perf_evsel__tp_sched_test(void)
49 if (perf_evsel__test_field(evsel, "prev_prio", 4, true)) 49 if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
50 ret = -1; 50 ret = -1;
51 51
52 if (perf_evsel__test_field(evsel, "prev_state", 8, true)) 52 if (perf_evsel__test_field(evsel, "prev_state", sizeof(long), true))
53 ret = -1; 53 ret = -1;
54 54
55 if (perf_evsel__test_field(evsel, "next_comm", 16, true)) 55 if (perf_evsel__test_field(evsel, "next_comm", 16, true))
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 89085a9615e2..4228ffc0d968 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -88,7 +88,8 @@ static struct machine *setup_fake_machine(struct machines *machines)
88 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) { 88 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
89 struct thread *thread; 89 struct thread *thread;
90 90
91 thread = machine__findnew_thread(machine, fake_threads[i].pid); 91 thread = machine__findnew_thread(machine, fake_threads[i].pid,
92 fake_threads[i].pid);
92 if (thread == NULL) 93 if (thread == NULL)
93 goto out; 94 goto out;
94 95
@@ -210,17 +211,15 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
210 list_for_each_entry(evsel, &evlist->entries, node) { 211 list_for_each_entry(evsel, &evlist->entries, node) {
211 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { 212 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
212 const union perf_event event = { 213 const union perf_event event = {
213 .ip = { 214 .header = {
214 .header = { 215 .misc = PERF_RECORD_MISC_USER,
215 .misc = PERF_RECORD_MISC_USER,
216 },
217 .pid = fake_common_samples[k].pid,
218 .ip = fake_common_samples[k].ip,
219 }, 216 },
220 }; 217 };
221 218
219 sample.pid = fake_common_samples[k].pid;
220 sample.ip = fake_common_samples[k].ip;
222 if (perf_event__preprocess_sample(&event, machine, &al, 221 if (perf_event__preprocess_sample(&event, machine, &al,
223 &sample, 0) < 0) 222 &sample) < 0)
224 goto out; 223 goto out;
225 224
226 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); 225 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
@@ -234,17 +233,15 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
234 233
235 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) { 234 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
236 const union perf_event event = { 235 const union perf_event event = {
237 .ip = { 236 .header = {
238 .header = { 237 .misc = PERF_RECORD_MISC_USER,
239 .misc = PERF_RECORD_MISC_USER,
240 },
241 .pid = fake_samples[i][k].pid,
242 .ip = fake_samples[i][k].ip,
243 }, 238 },
244 }; 239 };
245 240
241 sample.pid = fake_samples[i][k].pid;
242 sample.ip = fake_samples[i][k].ip;
246 if (perf_event__preprocess_sample(&event, machine, &al, 243 if (perf_event__preprocess_sample(&event, machine, &al,
247 &sample, 0) < 0) 244 &sample) < 0)
248 goto out; 245 goto out;
249 246
250 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); 247 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
new file mode 100644
index 000000000000..d444ea2c47d9
--- /dev/null
+++ b/tools/perf/tests/keep-tracking.c
@@ -0,0 +1,154 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <sys/prctl.h>
4
5#include "parse-events.h"
6#include "evlist.h"
7#include "evsel.h"
8#include "thread_map.h"
9#include "cpumap.h"
10#include "tests.h"
11
12#define CHECK__(x) { \
13 while ((x) < 0) { \
14 pr_debug(#x " failed!\n"); \
15 goto out_err; \
16 } \
17}
18
19#define CHECK_NOT_NULL__(x) { \
20 while ((x) == NULL) { \
21 pr_debug(#x " failed!\n"); \
22 goto out_err; \
23 } \
24}
25
26static int find_comm(struct perf_evlist *evlist, const char *comm)
27{
28 union perf_event *event;
29 int i, found;
30
31 found = 0;
32 for (i = 0; i < evlist->nr_mmaps; i++) {
33 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
34 if (event->header.type == PERF_RECORD_COMM &&
35 (pid_t)event->comm.pid == getpid() &&
36 (pid_t)event->comm.tid == getpid() &&
37 strcmp(event->comm.comm, comm) == 0)
38 found += 1;
39 }
40 }
41 return found;
42}
43
44/**
45 * test__keep_tracking - test using a dummy software event to keep tracking.
46 *
47 * This function implements a test that checks that tracking events continue
48 * when an event is disabled but a dummy software event is not disabled. If the
49 * test passes %0 is returned, otherwise %-1 is returned.
50 */
51int test__keep_tracking(void)
52{
53 struct perf_record_opts opts = {
54 .mmap_pages = UINT_MAX,
55 .user_freq = UINT_MAX,
56 .user_interval = ULLONG_MAX,
57 .freq = 4000,
58 .target = {
59 .uses_mmap = true,
60 },
61 };
62 struct thread_map *threads = NULL;
63 struct cpu_map *cpus = NULL;
64 struct perf_evlist *evlist = NULL;
65 struct perf_evsel *evsel = NULL;
66 int found, err = -1;
67 const char *comm;
68
69 threads = thread_map__new(-1, getpid(), UINT_MAX);
70 CHECK_NOT_NULL__(threads);
71
72 cpus = cpu_map__new(NULL);
73 CHECK_NOT_NULL__(cpus);
74
75 evlist = perf_evlist__new();
76 CHECK_NOT_NULL__(evlist);
77
78 perf_evlist__set_maps(evlist, cpus, threads);
79
80 CHECK__(parse_events(evlist, "dummy:u"));
81 CHECK__(parse_events(evlist, "cycles:u"));
82
83 perf_evlist__config(evlist, &opts);
84
85 evsel = perf_evlist__first(evlist);
86
87 evsel->attr.comm = 1;
88 evsel->attr.disabled = 1;
89 evsel->attr.enable_on_exec = 0;
90
91 if (perf_evlist__open(evlist) < 0) {
92 fprintf(stderr, " (not supported)");
93 err = 0;
94 goto out_err;
95 }
96
97 CHECK__(perf_evlist__mmap(evlist, UINT_MAX, false));
98
99 /*
100 * First, test that a 'comm' event can be found when the event is
101 * enabled.
102 */
103
104 perf_evlist__enable(evlist);
105
106 comm = "Test COMM 1";
107 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
108
109 perf_evlist__disable(evlist);
110
111 found = find_comm(evlist, comm);
112 if (found != 1) {
113 pr_debug("First time, failed to find tracking event.\n");
114 goto out_err;
115 }
116
117 /*
118 * Secondly, test that a 'comm' event can be found when the event is
119 * disabled with the dummy event still enabled.
120 */
121
122 perf_evlist__enable(evlist);
123
124 evsel = perf_evlist__last(evlist);
125
126 CHECK__(perf_evlist__disable_event(evlist, evsel));
127
128 comm = "Test COMM 2";
129 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
130
131 perf_evlist__disable(evlist);
132
133 found = find_comm(evlist, comm);
134 if (found != 1) {
135 pr_debug("Seconf time, failed to find tracking event.\n");
136 goto out_err;
137 }
138
139 err = 0;
140
141out_err:
142 if (evlist) {
143 perf_evlist__disable(evlist);
144 perf_evlist__munmap(evlist);
145 perf_evlist__close(evlist);
146 perf_evlist__delete(evlist);
147 }
148 if (cpus)
149 cpu_map__delete(cpus);
150 if (threads)
151 thread_map__delete(threads);
152
153 return err;
154}
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
new file mode 100644
index 000000000000..2ca0abf1b2b6
--- /dev/null
+++ b/tools/perf/tests/make
@@ -0,0 +1,189 @@
1PERF := .
2MK := Makefile
3
4has = $(shell which $1 2>/dev/null)
5
6# standard single make variable specified
7make_clean_all := clean all
8make_python_perf_so := python/perf.so
9make_debug := DEBUG=1
10make_no_libperl := NO_LIBPERL=1
11make_no_libpython := NO_LIBPYTHON=1
12make_no_scripts := NO_LIBPYTHON=1 NO_LIBPERL=1
13make_no_newt := NO_NEWT=1
14make_no_slang := NO_SLANG=1
15make_no_gtk2 := NO_GTK2=1
16make_no_ui := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
17make_no_demangle := NO_DEMANGLE=1
18make_no_libelf := NO_LIBELF=1
19make_no_libunwind := NO_LIBUNWIND=1
20make_no_backtrace := NO_BACKTRACE=1
21make_no_libnuma := NO_LIBNUMA=1
22make_no_libaudit := NO_LIBAUDIT=1
23make_no_libbionic := NO_LIBBIONIC=1
24make_tags := tags
25make_cscope := cscope
26make_help := help
27make_doc := doc
28make_perf_o := perf.o
29make_util_map_o := util/map.o
30make_install := install
31make_install_bin := install-bin
32make_install_doc := install-doc
33make_install_man := install-man
34make_install_html := install-html
35make_install_info := install-info
36make_install_pdf := install-pdf
37
38# all the NO_* variable combined
39make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
40make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
41make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
42
43# $(run) contains all available tests
44run := make_pure
45run += make_clean_all
46run += make_python_perf_so
47run += make_debug
48run += make_no_libperl
49run += make_no_libpython
50run += make_no_scripts
51run += make_no_newt
52run += make_no_slang
53run += make_no_gtk2
54run += make_no_ui
55run += make_no_demangle
56run += make_no_libelf
57run += make_no_libunwind
58run += make_no_backtrace
59run += make_no_libnuma
60run += make_no_libaudit
61run += make_no_libbionic
62run += make_help
63run += make_doc
64run += make_perf_o
65run += make_util_map_o
66run += make_install
67run += make_install_bin
68# FIXME 'install-*' commented out till they're fixed
69# run += make_install_doc
70# run += make_install_man
71# run += make_install_html
72# run += make_install_info
73# run += make_install_pdf
74run += make_minimal
75
76ifneq ($(call has,ctags),)
77run += make_tags
78endif
79ifneq ($(call has,cscope),)
80run += make_cscope
81endif
82
83# $(run_O) contains same portion of $(run) tests with '_O' attached
84# to distinguish O=... tests
85run_O := $(addsuffix _O,$(run))
86
87# disable some tests for O=...
88run_O := $(filter-out make_python_perf_so_O,$(run_O))
89
90# define test for each compile as 'test_NAME' variable
91# with the test itself as a value
92test_make_tags = test -f tags
93test_make_cscope = test -f cscope.out
94
95test_make_tags_O := $(test_make_tags)
96test_make_cscope_O := $(test_make_cscope)
97
98test_ok := true
99test_make_help := $(test_ok)
100test_make_doc := $(test_ok)
101test_make_help_O := $(test_ok)
102test_make_doc_O := $(test_ok)
103
104test_make_python_perf_so := test -f $(PERF)/python/perf.so
105
106test_make_perf_o := test -f $(PERF)/perf.o
107test_make_util_map_o := test -f $(PERF)/util/map.o
108
109test_make_install := test -x $$TMP_DEST/bin/perf
110test_make_install_O := $(test_make_install)
111test_make_install_bin := $(test_make_install)
112test_make_install_bin_O := $(test_make_install)
113
114# FIXME nothing gets installed
115test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1
116test_make_install_man_O := $(test_make_install_man)
117
118# FIXME nothing gets installed
119test_make_install_doc := $(test_ok)
120test_make_install_doc_O := $(test_ok)
121
122# FIXME nothing gets installed
123test_make_install_html := $(test_ok)
124test_make_install_html_O := $(test_ok)
125
126# FIXME nothing gets installed
127test_make_install_info := $(test_ok)
128test_make_install_info_O := $(test_ok)
129
130# FIXME nothing gets installed
131test_make_install_pdf := $(test_ok)
132test_make_install_pdf_O := $(test_ok)
133
134# Kbuild tests only
135#test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so
136#test_make_perf_o_O := test -f $$TMP/tools/perf/perf.o
137#test_make_util_map_o_O := test -f $$TMP/tools/perf/util/map.o
138
139test_make_perf_o_O := true
140test_make_util_map_o_O := true
141
142test_default = test -x $(PERF)/perf
143test = $(if $(test_$1),$(test_$1),$(test_default))
144
145test_default_O = test -x $$TMP_O/perf
146test_O = $(if $(test_$1),$(test_$1),$(test_default_O))
147
148all:
149
150ifdef DEBUG
151d := $(info run $(run))
152d := $(info run_O $(run_O))
153endif
154
155MAKEFLAGS := --no-print-directory
156
157clean := @(cd $(PERF); make -s -f $(MK) clean >/dev/null)
158
159$(run):
160 $(call clean)
161 @TMP_DEST=$$(mktemp -d); \
162 cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \
163 echo "- $@: $$cmd" && echo $$cmd > $@ && \
164 ( eval $$cmd ) >> $@ 2>&1; \
165 echo " test: $(call test,$@)"; \
166 $(call test,$@) && \
167 rm -f $@ \
168 rm -rf $$TMP_DEST
169
170$(run_O):
171 $(call clean)
172 @TMP_O=$$(mktemp -d); \
173 TMP_DEST=$$(mktemp -d); \
174 cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \
175 echo "- $@: $$cmd" && echo $$cmd > $@ && \
176 ( eval $$cmd ) >> $@ 2>&1 && \
177 echo " test: $(call test_O,$@)"; \
178 $(call test_O,$@) && \
179 rm -f $@ && \
180 rm -rf $$TMP_O \
181 rm -rf $$TMP_DEST
182
183all: $(run) $(run_O)
184 @echo OK
185
186out: $(run_O)
187 @echo OK
188
189.PHONY: all $(run) $(run_O) clean
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 5b1b5aba722b..c4185b9aeb80 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -72,7 +72,7 @@ int test__basic_mmap(void)
72 } 72 }
73 73
74 evsels[i]->attr.wakeup_events = 1; 74 evsels[i]->attr.wakeup_events = 1;
75 perf_evsel__set_sample_id(evsels[i]); 75 perf_evsel__set_sample_id(evsels[i], false);
76 76
77 perf_evlist__add(evlist, evsels[i]); 77 perf_evlist__add(evlist, evsels[i]);
78 78
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 0275bab4ea9e..48114d164e9f 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -7,14 +7,6 @@
7#include "tests.h" 7#include "tests.h"
8#include <linux/hw_breakpoint.h> 8#include <linux/hw_breakpoint.h>
9 9
10#define TEST_ASSERT_VAL(text, cond) \
11do { \
12 if (!(cond)) { \
13 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
14 return -1; \
15 } \
16} while (0)
17
18#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ 10#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
19 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) 11 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
20 12
@@ -460,6 +452,7 @@ static int test__checkevent_pmu_events(struct perf_evlist *evlist)
460 evsel->attr.exclude_kernel); 452 evsel->attr.exclude_kernel);
461 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); 453 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
462 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 454 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
455 TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned);
463 456
464 return 0; 457 return 0;
465} 458}
@@ -528,6 +521,7 @@ static int test__group1(struct perf_evlist *evlist)
528 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 521 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
529 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 522 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
530 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 523 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
524 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
531 525
532 /* cycles:upp */ 526 /* cycles:upp */
533 evsel = perf_evsel__next(evsel); 527 evsel = perf_evsel__next(evsel);
@@ -543,6 +537,7 @@ static int test__group1(struct perf_evlist *evlist)
543 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); 537 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
544 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 538 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
545 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 539 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
540 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
546 541
547 return 0; 542 return 0;
548} 543}
@@ -568,6 +563,7 @@ static int test__group2(struct perf_evlist *evlist)
568 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 563 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
569 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 564 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
570 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 565 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
566 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
571 567
572 /* cache-references + :u modifier */ 568 /* cache-references + :u modifier */
573 evsel = perf_evsel__next(evsel); 569 evsel = perf_evsel__next(evsel);
@@ -582,6 +578,7 @@ static int test__group2(struct perf_evlist *evlist)
582 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 578 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
583 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 579 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
584 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 580 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
581 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
585 582
586 /* cycles:k */ 583 /* cycles:k */
587 evsel = perf_evsel__next(evsel); 584 evsel = perf_evsel__next(evsel);
@@ -595,6 +592,7 @@ static int test__group2(struct perf_evlist *evlist)
595 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 592 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
596 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 593 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
597 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 594 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
595 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
598 596
599 return 0; 597 return 0;
600} 598}
@@ -623,6 +621,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
623 !strcmp(leader->group_name, "group1")); 621 !strcmp(leader->group_name, "group1"));
624 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 622 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
625 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 623 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
624 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
626 625
627 /* group1 cycles:kppp */ 626 /* group1 cycles:kppp */
628 evsel = perf_evsel__next(evsel); 627 evsel = perf_evsel__next(evsel);
@@ -639,6 +638,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
639 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 638 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
640 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 639 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
641 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 640 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
641 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
642 642
643 /* group2 cycles + G modifier */ 643 /* group2 cycles + G modifier */
644 evsel = leader = perf_evsel__next(evsel); 644 evsel = leader = perf_evsel__next(evsel);
@@ -656,6 +656,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
656 !strcmp(leader->group_name, "group2")); 656 !strcmp(leader->group_name, "group2"));
657 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 657 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
658 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 658 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
659 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
659 660
660 /* group2 1:3 + G modifier */ 661 /* group2 1:3 + G modifier */
661 evsel = perf_evsel__next(evsel); 662 evsel = perf_evsel__next(evsel);
@@ -669,6 +670,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
669 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 670 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
670 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 671 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
671 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 672 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
673 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
672 674
673 /* instructions:u */ 675 /* instructions:u */
674 evsel = perf_evsel__next(evsel); 676 evsel = perf_evsel__next(evsel);
@@ -682,6 +684,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
682 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 684 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
683 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 685 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
684 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 686 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
687 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
685 688
686 return 0; 689 return 0;
687} 690}
@@ -709,6 +712,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
709 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 712 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
710 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 713 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
711 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 714 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
715 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
712 716
713 /* instructions:kp + p */ 717 /* instructions:kp + p */
714 evsel = perf_evsel__next(evsel); 718 evsel = perf_evsel__next(evsel);
@@ -724,6 +728,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
724 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); 728 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
725 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 729 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
726 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 730 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
731 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
727 732
728 return 0; 733 return 0;
729} 734}
@@ -750,6 +755,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
750 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 755 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
751 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 756 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
752 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 757 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
758 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
753 759
754 /* instructions + G */ 760 /* instructions + G */
755 evsel = perf_evsel__next(evsel); 761 evsel = perf_evsel__next(evsel);
@@ -764,6 +770,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
764 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 770 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
765 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 771 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
766 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); 772 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
773 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
767 774
768 /* cycles:G */ 775 /* cycles:G */
769 evsel = leader = perf_evsel__next(evsel); 776 evsel = leader = perf_evsel__next(evsel);
@@ -780,6 +787,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
780 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); 787 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
781 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); 788 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
782 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); 789 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
790 TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
783 791
784 /* instructions:G */ 792 /* instructions:G */
785 evsel = perf_evsel__next(evsel); 793 evsel = perf_evsel__next(evsel);
@@ -971,6 +979,142 @@ static int test__group_gh4(struct perf_evlist *evlist)
971 return 0; 979 return 0;
972} 980}
973 981
982static int test__leader_sample1(struct perf_evlist *evlist)
983{
984 struct perf_evsel *evsel, *leader;
985
986 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
987
988 /* cycles - sampling group leader */
989 evsel = leader = perf_evlist__first(evlist);
990 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
991 TEST_ASSERT_VAL("wrong config",
992 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
993 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
994 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
995 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
996 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
997 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
998 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
999 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1000 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1001 TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
1002
1003 /* cache-misses - not sampling */
1004 evsel = perf_evsel__next(evsel);
1005 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1006 TEST_ASSERT_VAL("wrong config",
1007 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
1008 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
1009 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
1010 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
1011 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
1012 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
1013 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
1014 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1015 TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
1016
1017 /* branch-misses - not sampling */
1018 evsel = perf_evsel__next(evsel);
1019 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1020 TEST_ASSERT_VAL("wrong config",
1021 PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config);
1022 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
1023 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
1024 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
1025 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
1026 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
1027 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
1028 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1029 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1030 TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
1031
1032 return 0;
1033}
1034
1035static int test__leader_sample2(struct perf_evlist *evlist __maybe_unused)
1036{
1037 struct perf_evsel *evsel, *leader;
1038
1039 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
1040
1041 /* instructions - sampling group leader */
1042 evsel = leader = perf_evlist__first(evlist);
1043 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1044 TEST_ASSERT_VAL("wrong config",
1045 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
1046 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
1047 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
1048 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
1049 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
1050 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
1051 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
1052 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1053 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1054 TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
1055
1056 /* branch-misses - not sampling */
1057 evsel = perf_evsel__next(evsel);
1058 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1059 TEST_ASSERT_VAL("wrong config",
1060 PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config);
1061 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
1062 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
1063 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
1064 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
1065 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
1066 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
1067 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1068 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1069 TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
1070
1071 return 0;
1072}
1073
1074static int test__checkevent_pinned_modifier(struct perf_evlist *evlist)
1075{
1076 struct perf_evsel *evsel = perf_evlist__first(evlist);
1077
1078 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
1079 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
1080 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
1081 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
1082 TEST_ASSERT_VAL("wrong pinned", evsel->attr.pinned);
1083
1084 return test__checkevent_symbolic_name(evlist);
1085}
1086
1087static int test__pinned_group(struct perf_evlist *evlist)
1088{
1089 struct perf_evsel *evsel, *leader;
1090
1091 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
1092
1093 /* cycles - group leader */
1094 evsel = leader = perf_evlist__first(evlist);
1095 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1096 TEST_ASSERT_VAL("wrong config",
1097 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
1098 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1099 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
1100 TEST_ASSERT_VAL("wrong pinned", evsel->attr.pinned);
1101
1102 /* cache-misses - can not be pinned, but will go on with the leader */
1103 evsel = perf_evsel__next(evsel);
1104 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
1105 TEST_ASSERT_VAL("wrong config",
1106 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
1107 TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned);
1108
1109 /* branch-misses - ditto */
1110 evsel = perf_evsel__next(evsel);
1111 TEST_ASSERT_VAL("wrong config",
1112 PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config);
1113 TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned);
1114
1115 return 0;
1116}
1117
974static int count_tracepoints(void) 1118static int count_tracepoints(void)
975{ 1119{
976 char events_path[PATH_MAX]; 1120 char events_path[PATH_MAX];
@@ -1187,6 +1331,22 @@ static struct evlist_test test__events[] = {
1187 .name = "{cycles:G,cache-misses:H}:uG", 1331 .name = "{cycles:G,cache-misses:H}:uG",
1188 .check = test__group_gh4, 1332 .check = test__group_gh4,
1189 }, 1333 },
1334 [38] = {
1335 .name = "{cycles,cache-misses,branch-misses}:S",
1336 .check = test__leader_sample1,
1337 },
1338 [39] = {
1339 .name = "{instructions,branch-misses}:Su",
1340 .check = test__leader_sample2,
1341 },
1342 [40] = {
1343 .name = "instructions:uDp",
1344 .check = test__checkevent_pinned_modifier,
1345 },
1346 [41] = {
1347 .name = "{cycles,cache-misses,branch-misses}:D",
1348 .check = test__pinned_group,
1349 },
1190}; 1350};
1191 1351
1192static struct evlist_test test__events_pmu[] = { 1352static struct evlist_test test__events_pmu[] = {
@@ -1254,24 +1414,20 @@ static int test_events(struct evlist_test *events, unsigned cnt)
1254 1414
1255static int test_term(struct terms_test *t) 1415static int test_term(struct terms_test *t)
1256{ 1416{
1257 struct list_head *terms; 1417 struct list_head terms;
1258 int ret; 1418 int ret;
1259 1419
1260 terms = malloc(sizeof(*terms)); 1420 INIT_LIST_HEAD(&terms);
1261 if (!terms)
1262 return -ENOMEM;
1263
1264 INIT_LIST_HEAD(terms);
1265 1421
1266 ret = parse_events_terms(terms, t->str); 1422 ret = parse_events_terms(&terms, t->str);
1267 if (ret) { 1423 if (ret) {
1268 pr_debug("failed to parse terms '%s', err %d\n", 1424 pr_debug("failed to parse terms '%s', err %d\n",
1269 t->str , ret); 1425 t->str , ret);
1270 return ret; 1426 return ret;
1271 } 1427 }
1272 1428
1273 ret = t->check(terms); 1429 ret = t->check(&terms);
1274 parse_events__free_terms(terms); 1430 parse_events__free_terms(&terms);
1275 1431
1276 return ret; 1432 return ret;
1277} 1433}
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
new file mode 100644
index 000000000000..e117b6c6a248
--- /dev/null
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -0,0 +1,108 @@
1#include <sys/types.h>
2#include <stddef.h>
3
4#include "tests.h"
5
6#include "event.h"
7#include "evlist.h"
8#include "header.h"
9#include "util.h"
10
11static int process_event(struct perf_evlist **pevlist, union perf_event *event)
12{
13 struct perf_sample sample;
14
15 if (event->header.type == PERF_RECORD_HEADER_ATTR) {
16 if (perf_event__process_attr(NULL, event, pevlist)) {
17 pr_debug("perf_event__process_attr failed\n");
18 return -1;
19 }
20 return 0;
21 }
22
23 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
24 return -1;
25
26 if (!*pevlist)
27 return -1;
28
29 if (perf_evlist__parse_sample(*pevlist, event, &sample)) {
30 pr_debug("perf_evlist__parse_sample failed\n");
31 return -1;
32 }
33
34 return 0;
35}
36
37static int process_events(union perf_event **events, size_t count)
38{
39 struct perf_evlist *evlist = NULL;
40 int err = 0;
41 size_t i;
42
43 for (i = 0; i < count && !err; i++)
44 err = process_event(&evlist, events[i]);
45
46 if (evlist)
47 perf_evlist__delete(evlist);
48
49 return err;
50}
51
52struct test_attr_event {
53 struct attr_event attr;
54 u64 id;
55};
56
57/**
58 * test__parse_no_sample_id_all - test parsing with no sample_id_all bit set.
59 *
60 * This function tests parsing data produced on kernel's that do not support the
61 * sample_id_all bit. Without the sample_id_all bit, non-sample events (such as
62 * mmap events) do not have an id sample appended, and consequently logic
63 * designed to determine the id will not work. That case happens when there is
64 * more than one selected event, so this test processes three events: 2
65 * attributes representing the selected events and one mmap event.
66 *
67 * Return: %0 on success, %-1 if the test fails.
68 */
69int test__parse_no_sample_id_all(void)
70{
71 int err;
72
73 struct test_attr_event event1 = {
74 .attr = {
75 .header = {
76 .type = PERF_RECORD_HEADER_ATTR,
77 .size = sizeof(struct test_attr_event),
78 },
79 },
80 .id = 1,
81 };
82 struct test_attr_event event2 = {
83 .attr = {
84 .header = {
85 .type = PERF_RECORD_HEADER_ATTR,
86 .size = sizeof(struct test_attr_event),
87 },
88 },
89 .id = 2,
90 };
91 struct mmap_event event3 = {
92 .header = {
93 .type = PERF_RECORD_MMAP,
94 .size = sizeof(struct mmap_event),
95 },
96 };
97 union perf_event *events[] = {
98 (union perf_event *)&event1,
99 (union perf_event *)&event2,
100 (union perf_event *)&event3,
101 };
102
103 err = process_events(events, ARRAY_SIZE(events));
104 if (err)
105 return -1;
106
107 return 0;
108}
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 72d8881873b0..b8a7056519ac 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -50,7 +50,7 @@ int test__PERF_RECORD(void)
50 struct perf_sample sample; 50 struct perf_sample sample;
51 const char *cmd = "sleep"; 51 const char *cmd = "sleep";
52 const char *argv[] = { cmd, "1", NULL, }; 52 const char *argv[] = { cmd, "1", NULL, };
53 char *bname; 53 char *bname, *mmap_filename;
54 u64 prev_time = 0; 54 u64 prev_time = 0;
55 bool found_cmd_mmap = false, 55 bool found_cmd_mmap = false,
56 found_libc_mmap = false, 56 found_libc_mmap = false,
@@ -212,6 +212,7 @@ int test__PERF_RECORD(void)
212 212
213 if ((type == PERF_RECORD_COMM || 213 if ((type == PERF_RECORD_COMM ||
214 type == PERF_RECORD_MMAP || 214 type == PERF_RECORD_MMAP ||
215 type == PERF_RECORD_MMAP2 ||
215 type == PERF_RECORD_FORK || 216 type == PERF_RECORD_FORK ||
216 type == PERF_RECORD_EXIT) && 217 type == PERF_RECORD_EXIT) &&
217 (pid_t)event->comm.pid != evlist->workload.pid) { 218 (pid_t)event->comm.pid != evlist->workload.pid) {
@@ -220,7 +221,8 @@ int test__PERF_RECORD(void)
220 } 221 }
221 222
222 if ((type == PERF_RECORD_COMM || 223 if ((type == PERF_RECORD_COMM ||
223 type == PERF_RECORD_MMAP) && 224 type == PERF_RECORD_MMAP ||
225 type == PERF_RECORD_MMAP2) &&
224 event->comm.pid != event->comm.tid) { 226 event->comm.pid != event->comm.tid) {
225 pr_debug("%s with different pid/tid!\n", name); 227 pr_debug("%s with different pid/tid!\n", name);
226 ++errs; 228 ++errs;
@@ -236,7 +238,12 @@ int test__PERF_RECORD(void)
236 case PERF_RECORD_EXIT: 238 case PERF_RECORD_EXIT:
237 goto found_exit; 239 goto found_exit;
238 case PERF_RECORD_MMAP: 240 case PERF_RECORD_MMAP:
239 bname = strrchr(event->mmap.filename, '/'); 241 mmap_filename = event->mmap.filename;
242 goto check_bname;
243 case PERF_RECORD_MMAP2:
244 mmap_filename = event->mmap2.filename;
245 check_bname:
246 bname = strrchr(mmap_filename, '/');
240 if (bname != NULL) { 247 if (bname != NULL) {
241 if (!found_cmd_mmap) 248 if (!found_cmd_mmap)
242 found_cmd_mmap = !strcmp(bname + 1, cmd); 249 found_cmd_mmap = !strcmp(bname + 1, cmd);
@@ -245,7 +252,7 @@ int test__PERF_RECORD(void)
245 if (!found_ld_mmap) 252 if (!found_ld_mmap)
246 found_ld_mmap = !strncmp(bname + 1, "ld", 2); 253 found_ld_mmap = !strncmp(bname + 1, "ld", 2);
247 } else if (!found_vdso_mmap) 254 } else if (!found_vdso_mmap)
248 found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]"); 255 found_vdso_mmap = !strcmp(mmap_filename, "[vdso]");
249 break; 256 break;
250 257
251 case PERF_RECORD_SAMPLE: 258 case PERF_RECORD_SAMPLE:
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
new file mode 100644
index 000000000000..0ab61b1f408e
--- /dev/null
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -0,0 +1,177 @@
1#include <stdio.h>
2#include <sys/types.h>
3#include <unistd.h>
4#include <inttypes.h>
5#include <sys/prctl.h>
6
7#include "parse-events.h"
8#include "evlist.h"
9#include "evsel.h"
10#include "thread_map.h"
11#include "cpumap.h"
12#include "tests.h"
13
14#include "../arch/x86/util/tsc.h"
15
16#define CHECK__(x) { \
17 while ((x) < 0) { \
18 pr_debug(#x " failed!\n"); \
19 goto out_err; \
20 } \
21}
22
23#define CHECK_NOT_NULL__(x) { \
24 while ((x) == NULL) { \
25 pr_debug(#x " failed!\n"); \
26 goto out_err; \
27 } \
28}
29
30static u64 rdtsc(void)
31{
32 unsigned int low, high;
33
34 asm volatile("rdtsc" : "=a" (low), "=d" (high));
35
36 return low | ((u64)high) << 32;
37}
38
39/**
40 * test__perf_time_to_tsc - test converting perf time to TSC.
41 *
42 * This function implements a test that checks that the conversion of perf time
43 * to and from TSC is consistent with the order of events. If the test passes
44 * %0 is returned, otherwise %-1 is returned. If TSC conversion is not
45 * supported then then the test passes but " (not supported)" is printed.
46 */
47int test__perf_time_to_tsc(void)
48{
49 struct perf_record_opts opts = {
50 .mmap_pages = UINT_MAX,
51 .user_freq = UINT_MAX,
52 .user_interval = ULLONG_MAX,
53 .freq = 4000,
54 .target = {
55 .uses_mmap = true,
56 },
57 .sample_time = true,
58 };
59 struct thread_map *threads = NULL;
60 struct cpu_map *cpus = NULL;
61 struct perf_evlist *evlist = NULL;
62 struct perf_evsel *evsel = NULL;
63 int err = -1, ret, i;
64 const char *comm1, *comm2;
65 struct perf_tsc_conversion tc;
66 struct perf_event_mmap_page *pc;
67 union perf_event *event;
68 u64 test_tsc, comm1_tsc, comm2_tsc;
69 u64 test_time, comm1_time = 0, comm2_time = 0;
70
71 threads = thread_map__new(-1, getpid(), UINT_MAX);
72 CHECK_NOT_NULL__(threads);
73
74 cpus = cpu_map__new(NULL);
75 CHECK_NOT_NULL__(cpus);
76
77 evlist = perf_evlist__new();
78 CHECK_NOT_NULL__(evlist);
79
80 perf_evlist__set_maps(evlist, cpus, threads);
81
82 CHECK__(parse_events(evlist, "cycles:u"));
83
84 perf_evlist__config(evlist, &opts);
85
86 evsel = perf_evlist__first(evlist);
87
88 evsel->attr.comm = 1;
89 evsel->attr.disabled = 1;
90 evsel->attr.enable_on_exec = 0;
91
92 CHECK__(perf_evlist__open(evlist));
93
94 CHECK__(perf_evlist__mmap(evlist, UINT_MAX, false));
95
96 pc = evlist->mmap[0].base;
97 ret = perf_read_tsc_conversion(pc, &tc);
98 if (ret) {
99 if (ret == -EOPNOTSUPP) {
100 fprintf(stderr, " (not supported)");
101 return 0;
102 }
103 goto out_err;
104 }
105
106 perf_evlist__enable(evlist);
107
108 comm1 = "Test COMM 1";
109 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0));
110
111 test_tsc = rdtsc();
112
113 comm2 = "Test COMM 2";
114 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0));
115
116 perf_evlist__disable(evlist);
117
118 for (i = 0; i < evlist->nr_mmaps; i++) {
119 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
120 struct perf_sample sample;
121
122 if (event->header.type != PERF_RECORD_COMM ||
123 (pid_t)event->comm.pid != getpid() ||
124 (pid_t)event->comm.tid != getpid())
125 continue;
126
127 if (strcmp(event->comm.comm, comm1) == 0) {
128 CHECK__(perf_evsel__parse_sample(evsel, event,
129 &sample));
130 comm1_time = sample.time;
131 }
132 if (strcmp(event->comm.comm, comm2) == 0) {
133 CHECK__(perf_evsel__parse_sample(evsel, event,
134 &sample));
135 comm2_time = sample.time;
136 }
137 }
138 }
139
140 if (!comm1_time || !comm2_time)
141 goto out_err;
142
143 test_time = tsc_to_perf_time(test_tsc, &tc);
144 comm1_tsc = perf_time_to_tsc(comm1_time, &tc);
145 comm2_tsc = perf_time_to_tsc(comm2_time, &tc);
146
147 pr_debug("1st event perf time %"PRIu64" tsc %"PRIu64"\n",
148 comm1_time, comm1_tsc);
149 pr_debug("rdtsc time %"PRIu64" tsc %"PRIu64"\n",
150 test_time, test_tsc);
151 pr_debug("2nd event perf time %"PRIu64" tsc %"PRIu64"\n",
152 comm2_time, comm2_tsc);
153
154 if (test_time <= comm1_time ||
155 test_time >= comm2_time)
156 goto out_err;
157
158 if (test_tsc <= comm1_tsc ||
159 test_tsc >= comm2_tsc)
160 goto out_err;
161
162 err = 0;
163
164out_err:
165 if (evlist) {
166 perf_evlist__disable(evlist);
167 perf_evlist__munmap(evlist);
168 perf_evlist__close(evlist);
169 perf_evlist__delete(evlist);
170 }
171 if (cpus)
172 cpu_map__delete(cpus);
173 if (threads)
174 thread_map__delete(threads);
175
176 return err;
177}
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
new file mode 100644
index 000000000000..77f598dbd97a
--- /dev/null
+++ b/tools/perf/tests/sample-parsing.c
@@ -0,0 +1,316 @@
1#include <stdbool.h>
2#include <inttypes.h>
3
4#include "util.h"
5#include "event.h"
6#include "evsel.h"
7
8#include "tests.h"
9
10#define COMP(m) do { \
11 if (s1->m != s2->m) { \
12 pr_debug("Samples differ at '"#m"'\n"); \
13 return false; \
14 } \
15} while (0)
16
17#define MCOMP(m) do { \
18 if (memcmp(&s1->m, &s2->m, sizeof(s1->m))) { \
19 pr_debug("Samples differ at '"#m"'\n"); \
20 return false; \
21 } \
22} while (0)
23
24static bool samples_same(const struct perf_sample *s1,
25 const struct perf_sample *s2, u64 type, u64 regs_user,
26 u64 read_format)
27{
28 size_t i;
29
30 if (type & PERF_SAMPLE_IDENTIFIER)
31 COMP(id);
32
33 if (type & PERF_SAMPLE_IP)
34 COMP(ip);
35
36 if (type & PERF_SAMPLE_TID) {
37 COMP(pid);
38 COMP(tid);
39 }
40
41 if (type & PERF_SAMPLE_TIME)
42 COMP(time);
43
44 if (type & PERF_SAMPLE_ADDR)
45 COMP(addr);
46
47 if (type & PERF_SAMPLE_ID)
48 COMP(id);
49
50 if (type & PERF_SAMPLE_STREAM_ID)
51 COMP(stream_id);
52
53 if (type & PERF_SAMPLE_CPU)
54 COMP(cpu);
55
56 if (type & PERF_SAMPLE_PERIOD)
57 COMP(period);
58
59 if (type & PERF_SAMPLE_READ) {
60 if (read_format & PERF_FORMAT_GROUP)
61 COMP(read.group.nr);
62 else
63 COMP(read.one.value);
64 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
65 COMP(read.time_enabled);
66 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
67 COMP(read.time_running);
68 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
69 if (read_format & PERF_FORMAT_GROUP) {
70 for (i = 0; i < s1->read.group.nr; i++)
71 MCOMP(read.group.values[i]);
72 } else {
73 COMP(read.one.id);
74 }
75 }
76
77 if (type & PERF_SAMPLE_CALLCHAIN) {
78 COMP(callchain->nr);
79 for (i = 0; i < s1->callchain->nr; i++)
80 COMP(callchain->ips[i]);
81 }
82
83 if (type & PERF_SAMPLE_RAW) {
84 COMP(raw_size);
85 if (memcmp(s1->raw_data, s2->raw_data, s1->raw_size)) {
86 pr_debug("Samples differ at 'raw_data'\n");
87 return false;
88 }
89 }
90
91 if (type & PERF_SAMPLE_BRANCH_STACK) {
92 COMP(branch_stack->nr);
93 for (i = 0; i < s1->branch_stack->nr; i++)
94 MCOMP(branch_stack->entries[i]);
95 }
96
97 if (type & PERF_SAMPLE_REGS_USER) {
98 size_t sz = hweight_long(regs_user) * sizeof(u64);
99
100 COMP(user_regs.abi);
101 if (s1->user_regs.abi &&
102 (!s1->user_regs.regs || !s2->user_regs.regs ||
103 memcmp(s1->user_regs.regs, s2->user_regs.regs, sz))) {
104 pr_debug("Samples differ at 'user_regs'\n");
105 return false;
106 }
107 }
108
109 if (type & PERF_SAMPLE_STACK_USER) {
110 COMP(user_stack.size);
111 if (memcmp(s1->user_stack.data, s1->user_stack.data,
112 s1->user_stack.size)) {
113 pr_debug("Samples differ at 'user_stack'\n");
114 return false;
115 }
116 }
117
118 if (type & PERF_SAMPLE_WEIGHT)
119 COMP(weight);
120
121 if (type & PERF_SAMPLE_DATA_SRC)
122 COMP(data_src);
123
124 return true;
125}
126
127static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
128{
129 struct perf_evsel evsel = {
130 .needs_swap = false,
131 .attr = {
132 .sample_type = sample_type,
133 .sample_regs_user = sample_regs_user,
134 .read_format = read_format,
135 },
136 };
137 union perf_event *event;
138 union {
139 struct ip_callchain callchain;
140 u64 data[64];
141 } callchain = {
142 /* 3 ips */
143 .data = {3, 201, 202, 203},
144 };
145 union {
146 struct branch_stack branch_stack;
147 u64 data[64];
148 } branch_stack = {
149 /* 1 branch_entry */
150 .data = {1, 211, 212, 213},
151 };
152 u64 user_regs[64];
153 const u64 raw_data[] = {0x123456780a0b0c0dULL, 0x1102030405060708ULL};
154 const u64 data[] = {0x2211443366558877ULL, 0, 0xaabbccddeeff4321ULL};
155 struct perf_sample sample = {
156 .ip = 101,
157 .pid = 102,
158 .tid = 103,
159 .time = 104,
160 .addr = 105,
161 .id = 106,
162 .stream_id = 107,
163 .period = 108,
164 .weight = 109,
165 .cpu = 110,
166 .raw_size = sizeof(raw_data),
167 .data_src = 111,
168 .raw_data = (void *)raw_data,
169 .callchain = &callchain.callchain,
170 .branch_stack = &branch_stack.branch_stack,
171 .user_regs = {
172 .abi = PERF_SAMPLE_REGS_ABI_64,
173 .regs = user_regs,
174 },
175 .user_stack = {
176 .size = sizeof(data),
177 .data = (void *)data,
178 },
179 .read = {
180 .time_enabled = 0x030a59d664fca7deULL,
181 .time_running = 0x011b6ae553eb98edULL,
182 },
183 };
184 struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},};
185 struct perf_sample sample_out;
186 size_t i, sz, bufsz;
187 int err, ret = -1;
188
189 for (i = 0; i < sizeof(user_regs); i++)
190 *(i + (u8 *)user_regs) = i & 0xfe;
191
192 if (read_format & PERF_FORMAT_GROUP) {
193 sample.read.group.nr = 4;
194 sample.read.group.values = values;
195 } else {
196 sample.read.one.value = 0x08789faeb786aa87ULL;
197 sample.read.one.id = 99;
198 }
199
200 sz = perf_event__sample_event_size(&sample, sample_type,
201 sample_regs_user, read_format);
202 bufsz = sz + 4096; /* Add a bit for overrun checking */
203 event = malloc(bufsz);
204 if (!event) {
205 pr_debug("malloc failed\n");
206 return -1;
207 }
208
209 memset(event, 0xff, bufsz);
210 event->header.type = PERF_RECORD_SAMPLE;
211 event->header.misc = 0;
212 event->header.size = sz;
213
214 err = perf_event__synthesize_sample(event, sample_type,
215 sample_regs_user, read_format,
216 &sample, false);
217 if (err) {
218 pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
219 "perf_event__synthesize_sample", sample_type, err);
220 goto out_free;
221 }
222
223 /* The data does not contain 0xff so we use that to check the size */
224 for (i = bufsz; i > 0; i--) {
225 if (*(i - 1 + (u8 *)event) != 0xff)
226 break;
227 }
228 if (i != sz) {
229 pr_debug("Event size mismatch: actual %zu vs expected %zu\n",
230 i, sz);
231 goto out_free;
232 }
233
234 evsel.sample_size = __perf_evsel__sample_size(sample_type);
235
236 err = perf_evsel__parse_sample(&evsel, event, &sample_out);
237 if (err) {
238 pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
239 "perf_evsel__parse_sample", sample_type, err);
240 goto out_free;
241 }
242
243 if (!samples_same(&sample, &sample_out, sample_type,
244 sample_regs_user, read_format)) {
245 pr_debug("parsing failed for sample_type %#"PRIx64"\n",
246 sample_type);
247 goto out_free;
248 }
249
250 ret = 0;
251out_free:
252 free(event);
253 if (ret && read_format)
254 pr_debug("read_format %#"PRIx64"\n", read_format);
255 return ret;
256}
257
258/**
259 * test__sample_parsing - test sample parsing.
260 *
261 * This function implements a test that synthesizes a sample event, parses it
262 * and then checks that the parsed sample matches the original sample. The test
263 * checks sample format bits separately and together. If the test passes %0 is
264 * returned, otherwise %-1 is returned.
265 */
266int test__sample_parsing(void)
267{
268 const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
269 u64 sample_type;
270 u64 sample_regs_user;
271 size_t i;
272 int err;
273
274 /*
275 * Fail the test if it has not been updated when new sample format bits
276 * were added.
277 */
278 if (PERF_SAMPLE_MAX > PERF_SAMPLE_IDENTIFIER << 1) {
279 pr_debug("sample format has changed - test needs updating\n");
280 return -1;
281 }
282
283 /* Test each sample format bit separately */
284 for (sample_type = 1; sample_type != PERF_SAMPLE_MAX;
285 sample_type <<= 1) {
286 /* Test read_format variations */
287 if (sample_type == PERF_SAMPLE_READ) {
288 for (i = 0; i < ARRAY_SIZE(rf); i++) {
289 err = do_test(sample_type, 0, rf[i]);
290 if (err)
291 return err;
292 }
293 continue;
294 }
295
296 if (sample_type == PERF_SAMPLE_REGS_USER)
297 sample_regs_user = 0x3fff;
298 else
299 sample_regs_user = 0;
300
301 err = do_test(sample_type, sample_regs_user, 0);
302 if (err)
303 return err;
304 }
305
306 /* Test all sample format bits together */
307 sample_type = PERF_SAMPLE_MAX - 1;
308 sample_regs_user = 0x3fff;
309 for (i = 0; i < ARRAY_SIZE(rf); i++) {
310 err = do_test(sample_type, sample_regs_user, rf[i]);
311 if (err)
312 return err;
313 }
314
315 return 0;
316}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index dd7feae2d37b..e0ac713857ba 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -1,6 +1,14 @@
1#ifndef TESTS_H 1#ifndef TESTS_H
2#define TESTS_H 2#define TESTS_H
3 3
4#define TEST_ASSERT_VAL(text, cond) \
5do { \
6 if (!(cond)) { \
7 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
8 return -1; \
9 } \
10} while (0)
11
4enum { 12enum {
5 TEST_OK = 0, 13 TEST_OK = 0,
6 TEST_FAIL = -1, 14 TEST_FAIL = -1,
@@ -27,5 +35,10 @@ int test__bp_signal(void);
27int test__bp_signal_overflow(void); 35int test__bp_signal_overflow(void);
28int test__task_exit(void); 36int test__task_exit(void);
29int test__sw_clock_freq(void); 37int test__sw_clock_freq(void);
38int test__perf_time_to_tsc(void);
39int test__code_reading(void);
40int test__sample_parsing(void);
41int test__keep_tracking(void);
42int test__parse_no_sample_id_all(void);
30 43
31#endif /* TESTS_H */ 44#endif /* TESTS_H */
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 7b4c4d26d1ba..2bd13edcbc17 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -16,6 +16,8 @@ static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
16 return 0; 16 return 0;
17} 17}
18 18
19#define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x))
20
19int test__vmlinux_matches_kallsyms(void) 21int test__vmlinux_matches_kallsyms(void)
20{ 22{
21 int err = -1; 23 int err = -1;
@@ -25,6 +27,7 @@ int test__vmlinux_matches_kallsyms(void)
25 struct machine kallsyms, vmlinux; 27 struct machine kallsyms, vmlinux;
26 enum map_type type = MAP__FUNCTION; 28 enum map_type type = MAP__FUNCTION;
27 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", }; 29 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
30 u64 mem_start, mem_end;
28 31
29 /* 32 /*
30 * Step 1: 33 * Step 1:
@@ -73,7 +76,7 @@ int test__vmlinux_matches_kallsyms(void)
73 goto out; 76 goto out;
74 } 77 }
75 78
76 ref_reloc_sym.addr = sym->start; 79 ref_reloc_sym.addr = UM(sym->start);
77 80
78 /* 81 /*
79 * Step 5: 82 * Step 5:
@@ -123,10 +126,14 @@ int test__vmlinux_matches_kallsyms(void)
123 if (sym->start == sym->end) 126 if (sym->start == sym->end)
124 continue; 127 continue;
125 128
126 first_pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL); 129 mem_start = vmlinux_map->unmap_ip(vmlinux_map, sym->start);
130 mem_end = vmlinux_map->unmap_ip(vmlinux_map, sym->end);
131
132 first_pair = machine__find_kernel_symbol(&kallsyms, type,
133 mem_start, NULL, NULL);
127 pair = first_pair; 134 pair = first_pair;
128 135
129 if (pair && pair->start == sym->start) { 136 if (pair && UM(pair->start) == mem_start) {
130next_pair: 137next_pair:
131 if (strcmp(sym->name, pair->name) == 0) { 138 if (strcmp(sym->name, pair->name) == 0) {
132 /* 139 /*
@@ -138,12 +145,20 @@ next_pair:
138 * off the real size. More than that and we 145 * off the real size. More than that and we
139 * _really_ have a problem. 146 * _really_ have a problem.
140 */ 147 */
141 s64 skew = sym->end - pair->end; 148 s64 skew = mem_end - UM(pair->end);
142 if (llabs(skew) < page_size) 149 if (llabs(skew) >= page_size)
143 continue; 150 pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
151 mem_start, sym->name, mem_end,
152 UM(pair->end));
153
154 /*
155 * Do not count this as a failure, because we
156 * could really find a case where it's not
157 * possible to get proper function end from
158 * kallsyms.
159 */
160 continue;
144 161
145 pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
146 sym->start, sym->name, sym->end, pair->end);
147 } else { 162 } else {
148 struct rb_node *nnd; 163 struct rb_node *nnd;
149detour: 164detour:
@@ -152,7 +167,7 @@ detour:
152 if (nnd) { 167 if (nnd) {
153 struct symbol *next = rb_entry(nnd, struct symbol, rb_node); 168 struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
154 169
155 if (next->start == sym->start) { 170 if (UM(next->start) == mem_start) {
156 pair = next; 171 pair = next;
157 goto next_pair; 172 goto next_pair;
158 } 173 }
@@ -165,10 +180,11 @@ detour:
165 } 180 }
166 181
167 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", 182 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
168 sym->start, sym->name, pair->name); 183 mem_start, sym->name, pair->name);
169 } 184 }
170 } else 185 } else
171 pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name); 186 pr_debug("%#" PRIx64 ": %s not on kallsyms\n",
187 mem_start, sym->name);
172 188
173 err = -1; 189 err = -1;
174 } 190 }
@@ -201,16 +217,19 @@ detour:
201 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) { 217 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
202 struct map *pos = rb_entry(nd, struct map, rb_node), *pair; 218 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
203 219
204 pair = map_groups__find(&kallsyms.kmaps, type, pos->start); 220 mem_start = vmlinux_map->unmap_ip(vmlinux_map, pos->start);
221 mem_end = vmlinux_map->unmap_ip(vmlinux_map, pos->end);
222
223 pair = map_groups__find(&kallsyms.kmaps, type, mem_start);
205 if (pair == NULL || pair->priv) 224 if (pair == NULL || pair->priv)
206 continue; 225 continue;
207 226
208 if (pair->start == pos->start) { 227 if (pair->start == mem_start) {
209 pair->priv = 1; 228 pair->priv = 1;
210 pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", 229 pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
211 pos->start, pos->end, pos->pgoff, pos->dso->name); 230 pos->start, pos->end, pos->pgoff, pos->dso->name);
212 if (pos->pgoff != pair->pgoff || pos->end != pair->end) 231 if (mem_end != pair->end)
213 pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "", 232 pr_info(":\n*%" PRIx64 "-%" PRIx64 " %" PRIx64,
214 pair->start, pair->end, pair->pgoff); 233 pair->start, pair->end, pair->pgoff);
215 pr_info(" %s\n", pair->dso->name); 234 pr_info(" %s\n", pair->dso->name);
216 pair->priv = 1; 235 pair->priv = 1;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index cc64d3f7fc36..08545ae46992 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -428,6 +428,14 @@ static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
428 browser->b.nr_entries = browser->nr_asm_entries; 428 browser->b.nr_entries = browser->nr_asm_entries;
429} 429}
430 430
431#define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
432
433static int sym_title(struct symbol *sym, struct map *map, char *title,
434 size_t sz)
435{
436 return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name);
437}
438
431static bool annotate_browser__callq(struct annotate_browser *browser, 439static bool annotate_browser__callq(struct annotate_browser *browser,
432 struct perf_evsel *evsel, 440 struct perf_evsel *evsel,
433 struct hist_browser_timer *hbt) 441 struct hist_browser_timer *hbt)
@@ -438,6 +446,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
438 struct annotation *notes; 446 struct annotation *notes;
439 struct symbol *target; 447 struct symbol *target;
440 u64 ip; 448 u64 ip;
449 char title[SYM_TITLE_MAX_SIZE];
441 450
442 if (!ins__is_call(dl->ins)) 451 if (!ins__is_call(dl->ins))
443 return false; 452 return false;
@@ -461,7 +470,8 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
461 470
462 pthread_mutex_unlock(&notes->lock); 471 pthread_mutex_unlock(&notes->lock);
463 symbol__tui_annotate(target, ms->map, evsel, hbt); 472 symbol__tui_annotate(target, ms->map, evsel, hbt);
464 ui_browser__show_title(&browser->b, sym->name); 473 sym_title(sym, ms->map, title, sizeof(title));
474 ui_browser__show_title(&browser->b, title);
465 return true; 475 return true;
466} 476}
467 477
@@ -495,7 +505,7 @@ static bool annotate_browser__jump(struct annotate_browser *browser)
495 505
496 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx); 506 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
497 if (dl == NULL) { 507 if (dl == NULL) {
498 ui_helpline__puts("Invallid jump offset"); 508 ui_helpline__puts("Invalid jump offset");
499 return true; 509 return true;
500 } 510 }
501 511
@@ -653,8 +663,10 @@ static int annotate_browser__run(struct annotate_browser *browser,
653 const char *help = "Press 'h' for help on key bindings"; 663 const char *help = "Press 'h' for help on key bindings";
654 int delay_secs = hbt ? hbt->refresh : 0; 664 int delay_secs = hbt ? hbt->refresh : 0;
655 int key; 665 int key;
666 char title[SYM_TITLE_MAX_SIZE];
656 667
657 if (ui_browser__show(&browser->b, sym->name, help) < 0) 668 sym_title(sym, ms->map, title, sizeof(title));
669 if (ui_browser__show(&browser->b, title, help) < 0)
658 return -1; 670 return -1;
659 671
660 annotate_browser__calc_percent(browser, evsel); 672 annotate_browser__calc_percent(browser, evsel);
@@ -720,7 +732,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
720 "s Toggle source code view\n" 732 "s Toggle source code view\n"
721 "/ Search string\n" 733 "/ Search string\n"
722 "r Run available scripts\n" 734 "r Run available scripts\n"
723 "? Search previous string\n"); 735 "? Search string backwards\n");
724 continue; 736 continue;
725 case 'r': 737 case 'r':
726 { 738 {
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index d88a2d0acb6d..7ef36c360471 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -25,7 +25,8 @@ struct hist_browser {
25 struct map_symbol *selection; 25 struct map_symbol *selection;
26 int print_seq; 26 int print_seq;
27 bool show_dso; 27 bool show_dso;
28 bool has_symbols; 28 float min_pcnt;
29 u64 nr_pcnt_entries;
29}; 30};
30 31
31extern void hist_browser__init_hpp(void); 32extern void hist_browser__init_hpp(void);
@@ -309,6 +310,8 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
309 "Or reduce the sampling frequency."); 310 "Or reduce the sampling frequency.");
310} 311}
311 312
313static void hist_browser__update_pcnt_entries(struct hist_browser *hb);
314
312static int hist_browser__run(struct hist_browser *browser, const char *ev_name, 315static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
313 struct hist_browser_timer *hbt) 316 struct hist_browser_timer *hbt)
314{ 317{
@@ -318,6 +321,8 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
318 321
319 browser->b.entries = &browser->hists->entries; 322 browser->b.entries = &browser->hists->entries;
320 browser->b.nr_entries = browser->hists->nr_entries; 323 browser->b.nr_entries = browser->hists->nr_entries;
324 if (browser->min_pcnt)
325 browser->b.nr_entries = browser->nr_pcnt_entries;
321 326
322 hist_browser__refresh_dimensions(browser); 327 hist_browser__refresh_dimensions(browser);
323 hists__browser_title(browser->hists, title, sizeof(title), ev_name); 328 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
@@ -330,9 +335,18 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
330 key = ui_browser__run(&browser->b, delay_secs); 335 key = ui_browser__run(&browser->b, delay_secs);
331 336
332 switch (key) { 337 switch (key) {
333 case K_TIMER: 338 case K_TIMER: {
339 u64 nr_entries;
334 hbt->timer(hbt->arg); 340 hbt->timer(hbt->arg);
335 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 341
342 if (browser->min_pcnt) {
343 hist_browser__update_pcnt_entries(browser);
344 nr_entries = browser->nr_pcnt_entries;
345 } else {
346 nr_entries = browser->hists->nr_entries;
347 }
348
349 ui_browser__update_nr_entries(&browser->b, nr_entries);
336 350
337 if (browser->hists->stats.nr_lost_warned != 351 if (browser->hists->stats.nr_lost_warned !=
338 browser->hists->stats.nr_events[PERF_RECORD_LOST]) { 352 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
@@ -344,6 +358,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
344 hists__browser_title(browser->hists, title, sizeof(title), ev_name); 358 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
345 ui_browser__show_title(&browser->b, title); 359 ui_browser__show_title(&browser->b, title);
346 continue; 360 continue;
361 }
347 case 'D': { /* Debug */ 362 case 'D': { /* Debug */
348 static int seq; 363 static int seq;
349 struct hist_entry *h = rb_entry(browser->b.top, 364 struct hist_entry *h = rb_entry(browser->b.top,
@@ -670,8 +685,10 @@ static u64 __hpp_get_##_field(struct hist_entry *he) \
670 return he->stat._field; \ 685 return he->stat._field; \
671} \ 686} \
672 \ 687 \
673static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \ 688static int \
674 struct hist_entry *he) \ 689hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
690 struct perf_hpp *hpp, \
691 struct hist_entry *he) \
675{ \ 692{ \
676 return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \ 693 return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
677} 694}
@@ -686,8 +703,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
686 703
687void hist_browser__init_hpp(void) 704void hist_browser__init_hpp(void)
688{ 705{
689 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
690
691 perf_hpp__init(); 706 perf_hpp__init();
692 707
693 perf_hpp__format[PERF_HPP__OVERHEAD].color = 708 perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -747,9 +762,9 @@ static int hist_browser__show_entry(struct hist_browser *browser,
747 first = false; 762 first = false;
748 763
749 if (fmt->color) { 764 if (fmt->color) {
750 width -= fmt->color(&hpp, entry); 765 width -= fmt->color(fmt, &hpp, entry);
751 } else { 766 } else {
752 width -= fmt->entry(&hpp, entry); 767 width -= fmt->entry(fmt, &hpp, entry);
753 slsmg_printf("%s", s); 768 slsmg_printf("%s", s);
754 } 769 }
755 } 770 }
@@ -796,10 +811,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
796 811
797 for (nd = browser->top; nd; nd = rb_next(nd)) { 812 for (nd = browser->top; nd; nd = rb_next(nd)) {
798 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 813 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
814 float percent = h->stat.period * 100.0 /
815 hb->hists->stats.total_period;
799 816
800 if (h->filtered) 817 if (h->filtered)
801 continue; 818 continue;
802 819
820 if (percent < hb->min_pcnt)
821 continue;
822
803 row += hist_browser__show_entry(hb, h, row); 823 row += hist_browser__show_entry(hb, h, row);
804 if (row == browser->height) 824 if (row == browser->height)
805 break; 825 break;
@@ -808,10 +828,18 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
808 return row; 828 return row;
809} 829}
810 830
811static struct rb_node *hists__filter_entries(struct rb_node *nd) 831static struct rb_node *hists__filter_entries(struct rb_node *nd,
832 struct hists *hists,
833 float min_pcnt)
812{ 834{
813 while (nd != NULL) { 835 while (nd != NULL) {
814 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 836 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
837 float percent = h->stat.period * 100.0 /
838 hists->stats.total_period;
839
840 if (percent < min_pcnt)
841 return NULL;
842
815 if (!h->filtered) 843 if (!h->filtered)
816 return nd; 844 return nd;
817 845
@@ -821,11 +849,16 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd)
821 return NULL; 849 return NULL;
822} 850}
823 851
824static struct rb_node *hists__filter_prev_entries(struct rb_node *nd) 852static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
853 struct hists *hists,
854 float min_pcnt)
825{ 855{
826 while (nd != NULL) { 856 while (nd != NULL) {
827 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 857 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
828 if (!h->filtered) 858 float percent = h->stat.period * 100.0 /
859 hists->stats.total_period;
860
861 if (!h->filtered && percent >= min_pcnt)
829 return nd; 862 return nd;
830 863
831 nd = rb_prev(nd); 864 nd = rb_prev(nd);
@@ -840,6 +873,9 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
840 struct hist_entry *h; 873 struct hist_entry *h;
841 struct rb_node *nd; 874 struct rb_node *nd;
842 bool first = true; 875 bool first = true;
876 struct hist_browser *hb;
877
878 hb = container_of(browser, struct hist_browser, b);
843 879
844 if (browser->nr_entries == 0) 880 if (browser->nr_entries == 0)
845 return; 881 return;
@@ -848,13 +884,15 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
848 884
849 switch (whence) { 885 switch (whence) {
850 case SEEK_SET: 886 case SEEK_SET:
851 nd = hists__filter_entries(rb_first(browser->entries)); 887 nd = hists__filter_entries(rb_first(browser->entries),
888 hb->hists, hb->min_pcnt);
852 break; 889 break;
853 case SEEK_CUR: 890 case SEEK_CUR:
854 nd = browser->top; 891 nd = browser->top;
855 goto do_offset; 892 goto do_offset;
856 case SEEK_END: 893 case SEEK_END:
857 nd = hists__filter_prev_entries(rb_last(browser->entries)); 894 nd = hists__filter_prev_entries(rb_last(browser->entries),
895 hb->hists, hb->min_pcnt);
858 first = false; 896 first = false;
859 break; 897 break;
860 default: 898 default:
@@ -897,7 +935,8 @@ do_offset:
897 break; 935 break;
898 } 936 }
899 } 937 }
900 nd = hists__filter_entries(rb_next(nd)); 938 nd = hists__filter_entries(rb_next(nd), hb->hists,
939 hb->min_pcnt);
901 if (nd == NULL) 940 if (nd == NULL)
902 break; 941 break;
903 --offset; 942 --offset;
@@ -930,7 +969,8 @@ do_offset:
930 } 969 }
931 } 970 }
932 971
933 nd = hists__filter_prev_entries(rb_prev(nd)); 972 nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
973 hb->min_pcnt);
934 if (nd == NULL) 974 if (nd == NULL)
935 break; 975 break;
936 ++offset; 976 ++offset;
@@ -1099,14 +1139,17 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1099 1139
1100static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1140static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1101{ 1141{
1102 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries)); 1142 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1143 browser->hists,
1144 browser->min_pcnt);
1103 int printed = 0; 1145 int printed = 0;
1104 1146
1105 while (nd) { 1147 while (nd) {
1106 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1148 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1107 1149
1108 printed += hist_browser__fprintf_entry(browser, h, fp); 1150 printed += hist_browser__fprintf_entry(browser, h, fp);
1109 nd = hists__filter_entries(rb_next(nd)); 1151 nd = hists__filter_entries(rb_next(nd), browser->hists,
1152 browser->min_pcnt);
1110 } 1153 }
1111 1154
1112 return printed; 1155 return printed;
@@ -1155,10 +1198,6 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
1155 browser->b.refresh = hist_browser__refresh; 1198 browser->b.refresh = hist_browser__refresh;
1156 browser->b.seek = ui_browser__hists_seek; 1199 browser->b.seek = ui_browser__hists_seek;
1157 browser->b.use_navkeypressed = true; 1200 browser->b.use_navkeypressed = true;
1158 if (sort__branch_mode == 1)
1159 browser->has_symbols = sort_sym_from.list.next != NULL;
1160 else
1161 browser->has_symbols = sort_sym.list.next != NULL;
1162 } 1201 }
1163 1202
1164 return browser; 1203 return browser;
@@ -1217,7 +1256,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1217 printed += scnprintf(bf + printed, size - printed, 1256 printed += scnprintf(bf + printed, size - printed,
1218 ", Thread: %s(%d)", 1257 ", Thread: %s(%d)",
1219 (thread->comm_set ? thread->comm : ""), 1258 (thread->comm_set ? thread->comm : ""),
1220 thread->pid); 1259 thread->tid);
1221 if (dso) 1260 if (dso)
1222 printed += scnprintf(bf + printed, size - printed, 1261 printed += scnprintf(bf + printed, size - printed,
1223 ", DSO: %s", dso->short_name); 1262 ", DSO: %s", dso->short_name);
@@ -1329,11 +1368,25 @@ close_file_and_continue:
1329 return ret; 1368 return ret;
1330} 1369}
1331 1370
1371static void hist_browser__update_pcnt_entries(struct hist_browser *hb)
1372{
1373 u64 nr_entries = 0;
1374 struct rb_node *nd = rb_first(&hb->hists->entries);
1375
1376 while (nd) {
1377 nr_entries++;
1378 nd = hists__filter_entries(rb_next(nd), hb->hists,
1379 hb->min_pcnt);
1380 }
1381
1382 hb->nr_pcnt_entries = nr_entries;
1383}
1332 1384
1333static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1385static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1334 const char *helpline, const char *ev_name, 1386 const char *helpline, const char *ev_name,
1335 bool left_exits, 1387 bool left_exits,
1336 struct hist_browser_timer *hbt, 1388 struct hist_browser_timer *hbt,
1389 float min_pcnt,
1337 struct perf_session_env *env) 1390 struct perf_session_env *env)
1338{ 1391{
1339 struct hists *hists = &evsel->hists; 1392 struct hists *hists = &evsel->hists;
@@ -1350,6 +1403,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1350 if (browser == NULL) 1403 if (browser == NULL)
1351 return -1; 1404 return -1;
1352 1405
1406 if (min_pcnt) {
1407 browser->min_pcnt = min_pcnt;
1408 hist_browser__update_pcnt_entries(browser);
1409 }
1410
1353 fstack = pstack__new(2); 1411 fstack = pstack__new(2);
1354 if (fstack == NULL) 1412 if (fstack == NULL)
1355 goto out; 1413 goto out;
@@ -1386,7 +1444,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1386 */ 1444 */
1387 goto out_free_stack; 1445 goto out_free_stack;
1388 case 'a': 1446 case 'a':
1389 if (!browser->has_symbols) { 1447 if (!sort__has_sym) {
1390 ui_browser__warning(&browser->b, delay_secs * 2, 1448 ui_browser__warning(&browser->b, delay_secs * 2,
1391 "Annotation is only available for symbolic views, " 1449 "Annotation is only available for symbolic views, "
1392 "include \"sym*\" in --sort to use it."); 1450 "include \"sym*\" in --sort to use it.");
@@ -1485,10 +1543,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1485 continue; 1543 continue;
1486 } 1544 }
1487 1545
1488 if (!browser->has_symbols) 1546 if (!sort__has_sym)
1489 goto add_exit_option; 1547 goto add_exit_option;
1490 1548
1491 if (sort__branch_mode == 1) { 1549 if (sort__mode == SORT_MODE__BRANCH) {
1492 bi = browser->he_selection->branch_info; 1550 bi = browser->he_selection->branch_info;
1493 if (browser->selection != NULL && 1551 if (browser->selection != NULL &&
1494 bi && 1552 bi &&
@@ -1521,7 +1579,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1521 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 1579 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
1522 (browser->hists->thread_filter ? "out of" : "into"), 1580 (browser->hists->thread_filter ? "out of" : "into"),
1523 (thread->comm_set ? thread->comm : ""), 1581 (thread->comm_set ? thread->comm : ""),
1524 thread->pid) > 0) 1582 thread->tid) > 0)
1525 zoom_thread = nr_options++; 1583 zoom_thread = nr_options++;
1526 1584
1527 if (dso != NULL && 1585 if (dso != NULL &&
@@ -1644,7 +1702,7 @@ zoom_out_thread:
1644 } else { 1702 } else {
1645 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\"",
1646 thread->comm_set ? thread->comm : "", 1704 thread->comm_set ? thread->comm : "",
1647 thread->pid); 1705 thread->tid);
1648 browser->hists->thread_filter = thread; 1706 browser->hists->thread_filter = thread;
1649 sort_thread.elide = true; 1707 sort_thread.elide = true;
1650 pstack__push(fstack, &browser->hists->thread_filter); 1708 pstack__push(fstack, &browser->hists->thread_filter);
@@ -1689,6 +1747,7 @@ struct perf_evsel_menu {
1689 struct ui_browser b; 1747 struct ui_browser b;
1690 struct perf_evsel *selection; 1748 struct perf_evsel *selection;
1691 bool lost_events, lost_events_warned; 1749 bool lost_events, lost_events_warned;
1750 float min_pcnt;
1692 struct perf_session_env *env; 1751 struct perf_session_env *env;
1693}; 1752};
1694 1753
@@ -1782,6 +1841,7 @@ browse_hists:
1782 ev_name = perf_evsel__name(pos); 1841 ev_name = perf_evsel__name(pos);
1783 key = perf_evsel__hists_browse(pos, nr_events, help, 1842 key = perf_evsel__hists_browse(pos, nr_events, help,
1784 ev_name, true, hbt, 1843 ev_name, true, hbt,
1844 menu->min_pcnt,
1785 menu->env); 1845 menu->env);
1786 ui_browser__show_title(&menu->b, title); 1846 ui_browser__show_title(&menu->b, title);
1787 switch (key) { 1847 switch (key) {
@@ -1843,6 +1903,7 @@ static bool filter_group_entries(struct ui_browser *self __maybe_unused,
1843static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1903static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1844 int nr_entries, const char *help, 1904 int nr_entries, const char *help,
1845 struct hist_browser_timer *hbt, 1905 struct hist_browser_timer *hbt,
1906 float min_pcnt,
1846 struct perf_session_env *env) 1907 struct perf_session_env *env)
1847{ 1908{
1848 struct perf_evsel *pos; 1909 struct perf_evsel *pos;
@@ -1856,6 +1917,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1856 .nr_entries = nr_entries, 1917 .nr_entries = nr_entries,
1857 .priv = evlist, 1918 .priv = evlist,
1858 }, 1919 },
1920 .min_pcnt = min_pcnt,
1859 .env = env, 1921 .env = env,
1860 }; 1922 };
1861 1923
@@ -1874,6 +1936,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1874 1936
1875int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 1937int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1876 struct hist_browser_timer *hbt, 1938 struct hist_browser_timer *hbt,
1939 float min_pcnt,
1877 struct perf_session_env *env) 1940 struct perf_session_env *env)
1878{ 1941{
1879 int nr_entries = evlist->nr_entries; 1942 int nr_entries = evlist->nr_entries;
@@ -1885,7 +1948,8 @@ single_entry:
1885 const char *ev_name = perf_evsel__name(first); 1948 const char *ev_name = perf_evsel__name(first);
1886 1949
1887 return perf_evsel__hists_browse(first, nr_entries, help, 1950 return perf_evsel__hists_browse(first, nr_entries, help,
1888 ev_name, false, hbt, env); 1951 ev_name, false, hbt, min_pcnt,
1952 env);
1889 } 1953 }
1890 1954
1891 if (symbol_conf.event_group) { 1955 if (symbol_conf.event_group) {
@@ -1901,5 +1965,5 @@ single_entry:
1901 } 1965 }
1902 1966
1903 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, 1967 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
1904 hbt, env); 1968 hbt, min_pcnt, env);
1905} 1969}
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 6f259b3d14e2..2ca66cc1160f 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -91,7 +91,8 @@ static u64 he_get_##_field(struct hist_entry *he) \
91 return he->stat._field; \ 91 return he->stat._field; \
92} \ 92} \
93 \ 93 \
94static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \ 94static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
95 struct perf_hpp *hpp, \
95 struct hist_entry *he) \ 96 struct hist_entry *he) \
96{ \ 97{ \
97 return __hpp__color_fmt(hpp, he, he_get_##_field); \ 98 return __hpp__color_fmt(hpp, he, he_get_##_field); \
@@ -108,8 +109,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
108 109
109void perf_gtk__init_hpp(void) 110void perf_gtk__init_hpp(void)
110{ 111{
111 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
112
113 perf_hpp__init(); 112 perf_hpp__init();
114 113
115 perf_hpp__format[PERF_HPP__OVERHEAD].color = 114 perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -124,16 +123,93 @@ void perf_gtk__init_hpp(void)
124 perf_gtk__hpp_color_overhead_guest_us; 123 perf_gtk__hpp_color_overhead_guest_us;
125} 124}
126 125
127static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) 126static void callchain_list__sym_name(struct callchain_list *cl,
127 char *bf, size_t bfsize)
128{
129 if (cl->ms.sym)
130 scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
131 else
132 scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
133}
134
135static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
136 GtkTreeIter *parent, int col, u64 total)
137{
138 struct rb_node *nd;
139 bool has_single_node = (rb_first(root) == rb_last(root));
140
141 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
142 struct callchain_node *node;
143 struct callchain_list *chain;
144 GtkTreeIter iter, new_parent;
145 bool need_new_parent;
146 double percent;
147 u64 hits, child_total;
148
149 node = rb_entry(nd, struct callchain_node, rb_node);
150
151 hits = callchain_cumul_hits(node);
152 percent = 100.0 * hits / total;
153
154 new_parent = *parent;
155 need_new_parent = !has_single_node && (node->val_nr > 1);
156
157 list_for_each_entry(chain, &node->val, list) {
158 char buf[128];
159
160 gtk_tree_store_append(store, &iter, &new_parent);
161
162 scnprintf(buf, sizeof(buf), "%5.2f%%", percent);
163 gtk_tree_store_set(store, &iter, 0, buf, -1);
164
165 callchain_list__sym_name(chain, buf, sizeof(buf));
166 gtk_tree_store_set(store, &iter, col, buf, -1);
167
168 if (need_new_parent) {
169 /*
170 * Only show the top-most symbol in a callchain
171 * if it's not the only callchain.
172 */
173 new_parent = iter;
174 need_new_parent = false;
175 }
176 }
177
178 if (callchain_param.mode == CHAIN_GRAPH_REL)
179 child_total = node->children_hit;
180 else
181 child_total = total;
182
183 /* Now 'iter' contains info of the last callchain_list */
184 perf_gtk__add_callchain(&node->rb_root, store, &iter, col,
185 child_total);
186 }
187}
188
189static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
190 GtkTreeViewColumn *col __maybe_unused,
191 gpointer user_data __maybe_unused)
192{
193 bool expanded = gtk_tree_view_row_expanded(view, path);
194
195 if (expanded)
196 gtk_tree_view_collapse_row(view, path);
197 else
198 gtk_tree_view_expand_row(view, path, FALSE);
199}
200
201static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
202 float min_pcnt)
128{ 203{
129 struct perf_hpp_fmt *fmt; 204 struct perf_hpp_fmt *fmt;
130 GType col_types[MAX_COLUMNS]; 205 GType col_types[MAX_COLUMNS];
131 GtkCellRenderer *renderer; 206 GtkCellRenderer *renderer;
132 struct sort_entry *se; 207 struct sort_entry *se;
133 GtkListStore *store; 208 GtkTreeStore *store;
134 struct rb_node *nd; 209 struct rb_node *nd;
135 GtkWidget *view; 210 GtkWidget *view;
136 int col_idx; 211 int col_idx;
212 int sym_col = -1;
137 int nr_cols; 213 int nr_cols;
138 char s[512]; 214 char s[512];
139 215
@@ -152,10 +228,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
152 if (se->elide) 228 if (se->elide)
153 continue; 229 continue;
154 230
231 if (se == &sort_sym)
232 sym_col = nr_cols;
233
155 col_types[nr_cols++] = G_TYPE_STRING; 234 col_types[nr_cols++] = G_TYPE_STRING;
156 } 235 }
157 236
158 store = gtk_list_store_newv(nr_cols, col_types); 237 store = gtk_tree_store_newv(nr_cols, col_types);
159 238
160 view = gtk_tree_view_new(); 239 view = gtk_tree_view_new();
161 240
@@ -164,7 +243,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
164 col_idx = 0; 243 col_idx = 0;
165 244
166 perf_hpp__for_each_format(fmt) { 245 perf_hpp__for_each_format(fmt) {
167 fmt->header(&hpp); 246 fmt->header(fmt, &hpp);
168 247
169 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 248 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
170 -1, ltrim(s), 249 -1, ltrim(s),
@@ -182,6 +261,18 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
182 col_idx++, NULL); 261 col_idx++, NULL);
183 } 262 }
184 263
264 for (col_idx = 0; col_idx < nr_cols; col_idx++) {
265 GtkTreeViewColumn *column;
266
267 column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
268 gtk_tree_view_column_set_resizable(column, TRUE);
269
270 if (col_idx == sym_col) {
271 gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
272 column);
273 }
274 }
275
185 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); 276 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
186 277
187 g_object_unref(GTK_TREE_MODEL(store)); 278 g_object_unref(GTK_TREE_MODEL(store));
@@ -189,21 +280,26 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
189 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 280 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
190 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 281 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
191 GtkTreeIter iter; 282 GtkTreeIter iter;
283 float percent = h->stat.period * 100.0 /
284 hists->stats.total_period;
192 285
193 if (h->filtered) 286 if (h->filtered)
194 continue; 287 continue;
195 288
196 gtk_list_store_append(store, &iter); 289 if (percent < min_pcnt)
290 continue;
291
292 gtk_tree_store_append(store, &iter, NULL);
197 293
198 col_idx = 0; 294 col_idx = 0;
199 295
200 perf_hpp__for_each_format(fmt) { 296 perf_hpp__for_each_format(fmt) {
201 if (fmt->color) 297 if (fmt->color)
202 fmt->color(&hpp, h); 298 fmt->color(fmt, &hpp, h);
203 else 299 else
204 fmt->entry(&hpp, h); 300 fmt->entry(fmt, &hpp, h);
205 301
206 gtk_list_store_set(store, &iter, col_idx++, s, -1); 302 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
207 } 303 }
208 304
209 list_for_each_entry(se, &hist_entry__sort_list, list) { 305 list_for_each_entry(se, &hist_entry__sort_list, list) {
@@ -213,16 +309,33 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
213 se->se_snprintf(h, s, ARRAY_SIZE(s), 309 se->se_snprintf(h, s, ARRAY_SIZE(s),
214 hists__col_len(hists, se->se_width_idx)); 310 hists__col_len(hists, se->se_width_idx));
215 311
216 gtk_list_store_set(store, &iter, col_idx++, s, -1); 312 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
313 }
314
315 if (symbol_conf.use_callchain && sort__has_sym) {
316 u64 total;
317
318 if (callchain_param.mode == CHAIN_GRAPH_REL)
319 total = h->stat.period;
320 else
321 total = hists->stats.total_period;
322
323 perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
324 sym_col, total);
217 } 325 }
218 } 326 }
219 327
328 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
329
330 g_signal_connect(view, "row-activated",
331 G_CALLBACK(on_row_activated), NULL);
220 gtk_container_add(GTK_CONTAINER(window), view); 332 gtk_container_add(GTK_CONTAINER(window), view);
221} 333}
222 334
223int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, 335int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
224 const char *help, 336 const char *help,
225 struct hist_browser_timer *hbt __maybe_unused) 337 struct hist_browser_timer *hbt __maybe_unused,
338 float min_pcnt)
226{ 339{
227 struct perf_evsel *pos; 340 struct perf_evsel *pos;
228 GtkWidget *vbox; 341 GtkWidget *vbox;
@@ -286,7 +399,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
286 GTK_POLICY_AUTOMATIC, 399 GTK_POLICY_AUTOMATIC,
287 GTK_POLICY_AUTOMATIC); 400 GTK_POLICY_AUTOMATIC);
288 401
289 perf_gtk__show_hists(scrolled_window, hists); 402 perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
290 403
291 tab_label = gtk_label_new(evname); 404 tab_label = gtk_label_new(evname);
292 405
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 4bf91b09d62d..0a193281eba8 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -1,4 +1,5 @@
1#include <math.h> 1#include <math.h>
2#include <linux/compiler.h>
2 3
3#include "../util/hist.h" 4#include "../util/hist.h"
4#include "../util/util.h" 5#include "../util/util.h"
@@ -79,7 +80,8 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
79} 80}
80 81
81#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 82#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
82static int hpp__header_##_type(struct perf_hpp *hpp) \ 83static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
84 struct perf_hpp *hpp) \
83{ \ 85{ \
84 int len = _min_width; \ 86 int len = _min_width; \
85 \ 87 \
@@ -92,7 +94,8 @@ static int hpp__header_##_type(struct perf_hpp *hpp) \
92} 94}
93 95
94#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 96#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
95static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \ 97static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
98 struct perf_hpp *hpp __maybe_unused) \
96{ \ 99{ \
97 int len = _min_width; \ 100 int len = _min_width; \
98 \ 101 \
@@ -110,14 +113,16 @@ static u64 he_get_##_field(struct hist_entry *he) \
110 return he->stat._field; \ 113 return he->stat._field; \
111} \ 114} \
112 \ 115 \
113static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ 116static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
117 struct perf_hpp *hpp, struct hist_entry *he) \
114{ \ 118{ \
115 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ 119 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
116 (hpp_snprint_fn)percent_color_snprintf, true); \ 120 (hpp_snprint_fn)percent_color_snprintf, true); \
117} 121}
118 122
119#define __HPP_ENTRY_PERCENT_FN(_type, _field) \ 123#define __HPP_ENTRY_PERCENT_FN(_type, _field) \
120static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ 124static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
125 struct perf_hpp *hpp, struct hist_entry *he) \
121{ \ 126{ \
122 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ 127 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
123 return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ 128 return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
@@ -130,7 +135,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \
130 return he->stat._field; \ 135 return he->stat._field; \
131} \ 136} \
132 \ 137 \
133static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ 138static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
139 struct perf_hpp *hpp, struct hist_entry *he) \
134{ \ 140{ \
135 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ 141 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
136 return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ 142 return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
@@ -157,196 +163,6 @@ HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
157HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) 163HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
158HPP_RAW_FNS(period, "Period", period, 12, 12) 164HPP_RAW_FNS(period, "Period", period, 12, 12)
159 165
160
161static int hpp__header_baseline(struct perf_hpp *hpp)
162{
163 return scnprintf(hpp->buf, hpp->size, "Baseline");
164}
165
166static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
167{
168 return 8;
169}
170
171static double baseline_percent(struct hist_entry *he)
172{
173 struct hist_entry *pair = hist_entry__next_pair(he);
174 struct hists *pair_hists = pair ? pair->hists : NULL;
175 double percent = 0.0;
176
177 if (pair) {
178 u64 total_period = pair_hists->stats.total_period;
179 u64 base_period = pair->stat.period;
180
181 percent = 100.0 * base_period / total_period;
182 }
183
184 return percent;
185}
186
187static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
188{
189 double percent = baseline_percent(he);
190
191 if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
192 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
193 else
194 return scnprintf(hpp->buf, hpp->size, " ");
195}
196
197static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
198{
199 double percent = baseline_percent(he);
200 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
201
202 if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
203 return scnprintf(hpp->buf, hpp->size, fmt, percent);
204 else
205 return scnprintf(hpp->buf, hpp->size, " ");
206}
207
208static int hpp__header_period_baseline(struct perf_hpp *hpp)
209{
210 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
211
212 return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
213}
214
215static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
216{
217 return 12;
218}
219
220static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
221{
222 struct hist_entry *pair = hist_entry__next_pair(he);
223 u64 period = pair ? pair->stat.period : 0;
224 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
225
226 return scnprintf(hpp->buf, hpp->size, fmt, period);
227}
228
229static int hpp__header_delta(struct perf_hpp *hpp)
230{
231 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
232
233 return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
234}
235
236static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
237{
238 return 7;
239}
240
241static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
242{
243 struct hist_entry *pair = hist_entry__next_pair(he);
244 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
245 char buf[32] = " ";
246 double diff = 0.0;
247
248 if (pair) {
249 if (he->diff.computed)
250 diff = he->diff.period_ratio_delta;
251 else
252 diff = perf_diff__compute_delta(he, pair);
253 } else
254 diff = perf_diff__period_percent(he, he->stat.period);
255
256 if (fabs(diff) >= 0.01)
257 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
258
259 return scnprintf(hpp->buf, hpp->size, fmt, buf);
260}
261
262static int hpp__header_ratio(struct perf_hpp *hpp)
263{
264 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
265
266 return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
267}
268
269static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
270{
271 return 14;
272}
273
274static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
275{
276 struct hist_entry *pair = hist_entry__next_pair(he);
277 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
278 char buf[32] = " ";
279 double ratio = 0.0;
280
281 if (pair) {
282 if (he->diff.computed)
283 ratio = he->diff.period_ratio;
284 else
285 ratio = perf_diff__compute_ratio(he, pair);
286 }
287
288 if (ratio > 0.0)
289 scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
290
291 return scnprintf(hpp->buf, hpp->size, fmt, buf);
292}
293
294static int hpp__header_wdiff(struct perf_hpp *hpp)
295{
296 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
297
298 return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
299}
300
301static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
302{
303 return 14;
304}
305
306static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
307{
308 struct hist_entry *pair = hist_entry__next_pair(he);
309 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
310 char buf[32] = " ";
311 s64 wdiff = 0;
312
313 if (pair) {
314 if (he->diff.computed)
315 wdiff = he->diff.wdiff;
316 else
317 wdiff = perf_diff__compute_wdiff(he, pair);
318 }
319
320 if (wdiff != 0)
321 scnprintf(buf, sizeof(buf), "%14ld", wdiff);
322
323 return scnprintf(hpp->buf, hpp->size, fmt, buf);
324}
325
326static int hpp__header_formula(struct perf_hpp *hpp)
327{
328 const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
329
330 return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
331}
332
333static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
334{
335 return 70;
336}
337
338static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
339{
340 struct hist_entry *pair = hist_entry__next_pair(he);
341 const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
342 char buf[96] = " ";
343
344 if (pair)
345 perf_diff__formula(he, pair, buf, sizeof(buf));
346
347 return scnprintf(hpp->buf, hpp->size, fmt, buf);
348}
349
350#define HPP__COLOR_PRINT_FNS(_name) \ 166#define HPP__COLOR_PRINT_FNS(_name) \
351 { \ 167 { \
352 .header = hpp__header_ ## _name, \ 168 .header = hpp__header_ ## _name, \
@@ -363,19 +179,13 @@ static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
363 } 179 }
364 180
365struct perf_hpp_fmt perf_hpp__format[] = { 181struct perf_hpp_fmt perf_hpp__format[] = {
366 HPP__COLOR_PRINT_FNS(baseline),
367 HPP__COLOR_PRINT_FNS(overhead), 182 HPP__COLOR_PRINT_FNS(overhead),
368 HPP__COLOR_PRINT_FNS(overhead_sys), 183 HPP__COLOR_PRINT_FNS(overhead_sys),
369 HPP__COLOR_PRINT_FNS(overhead_us), 184 HPP__COLOR_PRINT_FNS(overhead_us),
370 HPP__COLOR_PRINT_FNS(overhead_guest_sys), 185 HPP__COLOR_PRINT_FNS(overhead_guest_sys),
371 HPP__COLOR_PRINT_FNS(overhead_guest_us), 186 HPP__COLOR_PRINT_FNS(overhead_guest_us),
372 HPP__PRINT_FNS(samples), 187 HPP__PRINT_FNS(samples),
373 HPP__PRINT_FNS(period), 188 HPP__PRINT_FNS(period)
374 HPP__PRINT_FNS(period_baseline),
375 HPP__PRINT_FNS(delta),
376 HPP__PRINT_FNS(ratio),
377 HPP__PRINT_FNS(wdiff),
378 HPP__PRINT_FNS(formula)
379}; 189};
380 190
381LIST_HEAD(perf_hpp__list); 191LIST_HEAD(perf_hpp__list);
@@ -396,6 +206,8 @@ LIST_HEAD(perf_hpp__list);
396 206
397void perf_hpp__init(void) 207void perf_hpp__init(void)
398{ 208{
209 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
210
399 if (symbol_conf.show_cpu_utilization) { 211 if (symbol_conf.show_cpu_utilization) {
400 perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); 212 perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
401 perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); 213 perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
@@ -424,46 +236,6 @@ void perf_hpp__column_enable(unsigned col)
424 perf_hpp__column_register(&perf_hpp__format[col]); 236 perf_hpp__column_register(&perf_hpp__format[col]);
425} 237}
426 238
427static inline void advance_hpp(struct perf_hpp *hpp, int inc)
428{
429 hpp->buf += inc;
430 hpp->size -= inc;
431}
432
433int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
434 bool color)
435{
436 const char *sep = symbol_conf.field_sep;
437 struct perf_hpp_fmt *fmt;
438 char *start = hpp->buf;
439 int ret;
440 bool first = true;
441
442 if (symbol_conf.exclude_other && !he->parent)
443 return 0;
444
445 perf_hpp__for_each_format(fmt) {
446 /*
447 * If there's no field_sep, we still need
448 * to display initial ' '.
449 */
450 if (!sep || !first) {
451 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
452 advance_hpp(hpp, ret);
453 } else
454 first = false;
455
456 if (color && fmt->color)
457 ret = fmt->color(hpp, he);
458 else
459 ret = fmt->entry(hpp, he);
460
461 advance_hpp(hpp, ret);
462 }
463
464 return hpp->buf - start;
465}
466
467int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, 239int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
468 struct hists *hists) 240 struct hists *hists)
469{ 241{
@@ -499,7 +271,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
499 if (i) 271 if (i)
500 ret += 2; 272 ret += 2;
501 273
502 ret += fmt->width(&dummy_hpp); 274 ret += fmt->width(fmt, &dummy_hpp);
503 } 275 }
504 276
505 list_for_each_entry(se, &hist_entry__sort_list, list) 277 list_for_each_entry(se, &hist_entry__sort_list, list)
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index ae6a789cb0f6..47d9a571f261 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -30,7 +30,6 @@ void setup_browser(bool fallback_to_pager)
30 if (fallback_to_pager) 30 if (fallback_to_pager)
31 setup_pager(); 31 setup_pager();
32 32
33 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
34 perf_hpp__init(); 33 perf_hpp__init();
35 break; 34 break;
36 } 35 }
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index ff1f60cf442e..194e2f42ff5d 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -308,10 +308,51 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
308 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); 308 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
309} 309}
310 310
311static inline void advance_hpp(struct perf_hpp *hpp, int inc)
312{
313 hpp->buf += inc;
314 hpp->size -= inc;
315}
316
317static int hist_entry__period_snprintf(struct perf_hpp *hpp,
318 struct hist_entry *he,
319 bool color)
320{
321 const char *sep = symbol_conf.field_sep;
322 struct perf_hpp_fmt *fmt;
323 char *start = hpp->buf;
324 int ret;
325 bool first = true;
326
327 if (symbol_conf.exclude_other && !he->parent)
328 return 0;
329
330 perf_hpp__for_each_format(fmt) {
331 /*
332 * If there's no field_sep, we still need
333 * to display initial ' '.
334 */
335 if (!sep || !first) {
336 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
337 advance_hpp(hpp, ret);
338 } else
339 first = false;
340
341 if (color && fmt->color)
342 ret = fmt->color(fmt, hpp, he);
343 else
344 ret = fmt->entry(fmt, hpp, he);
345
346 advance_hpp(hpp, ret);
347 }
348
349 return hpp->buf - start;
350}
351
311static int hist_entry__fprintf(struct hist_entry *he, size_t size, 352static int hist_entry__fprintf(struct hist_entry *he, size_t size,
312 struct hists *hists, FILE *fp) 353 struct hists *hists,
354 char *bf, size_t bfsz, FILE *fp)
313{ 355{
314 char bf[512];
315 int ret; 356 int ret;
316 struct perf_hpp hpp = { 357 struct perf_hpp hpp = {
317 .buf = bf, 358 .buf = bf,
@@ -319,8 +360,8 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
319 }; 360 };
320 bool color = !symbol_conf.field_sep; 361 bool color = !symbol_conf.field_sep;
321 362
322 if (size == 0 || size > sizeof(bf)) 363 if (size == 0 || size > bfsz)
323 size = hpp.size = sizeof(bf); 364 size = hpp.size = bfsz;
324 365
325 ret = hist_entry__period_snprintf(&hpp, he, color); 366 ret = hist_entry__period_snprintf(&hpp, he, color);
326 hist_entry__sort_snprintf(he, bf + ret, size - ret, hists); 367 hist_entry__sort_snprintf(he, bf + ret, size - ret, hists);
@@ -334,7 +375,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
334} 375}
335 376
336size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 377size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
337 int max_cols, FILE *fp) 378 int max_cols, float min_pcnt, FILE *fp)
338{ 379{
339 struct perf_hpp_fmt *fmt; 380 struct perf_hpp_fmt *fmt;
340 struct sort_entry *se; 381 struct sort_entry *se;
@@ -351,6 +392,8 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
351 .ptr = hists_to_evsel(hists), 392 .ptr = hists_to_evsel(hists),
352 }; 393 };
353 bool first = true; 394 bool first = true;
395 size_t linesz;
396 char *line = NULL;
354 397
355 init_rem_hits(); 398 init_rem_hits();
356 399
@@ -365,7 +408,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
365 else 408 else
366 first = false; 409 first = false;
367 410
368 fmt->header(&dummy_hpp); 411 fmt->header(fmt, &dummy_hpp);
369 fprintf(fp, "%s", bf); 412 fprintf(fp, "%s", bf);
370 } 413 }
371 414
@@ -410,7 +453,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
410 else 453 else
411 first = false; 454 first = false;
412 455
413 width = fmt->width(&dummy_hpp); 456 width = fmt->width(fmt, &dummy_hpp);
414 for (i = 0; i < width; i++) 457 for (i = 0; i < width; i++)
415 fprintf(fp, "."); 458 fprintf(fp, ".");
416 } 459 }
@@ -438,16 +481,28 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
438 goto out; 481 goto out;
439 482
440print_entries: 483print_entries:
484 linesz = hists__sort_list_width(hists) + 3 + 1;
485 line = malloc(linesz);
486 if (line == NULL) {
487 ret = -1;
488 goto out;
489 }
490
441 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 491 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
442 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 492 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
493 float percent = h->stat.period * 100.0 /
494 hists->stats.total_period;
443 495
444 if (h->filtered) 496 if (h->filtered)
445 continue; 497 continue;
446 498
447 ret += hist_entry__fprintf(h, max_cols, hists, fp); 499 if (percent < min_pcnt)
500 continue;
501
502 ret += hist_entry__fprintf(h, max_cols, hists, line, linesz, fp);
448 503
449 if (max_rows && ++nr_rows >= max_rows) 504 if (max_rows && ++nr_rows >= max_rows)
450 goto out; 505 break;
451 506
452 if (h->ms.map == NULL && verbose > 1) { 507 if (h->ms.map == NULL && verbose > 1) {
453 __map_groups__fprintf_maps(&h->thread->mg, 508 __map_groups__fprintf_maps(&h->thread->mg,
@@ -455,6 +510,8 @@ print_entries:
455 fprintf(fp, "%.10s end\n", graph_dotted_line); 510 fprintf(fp, "%.10s end\n", graph_dotted_line);
456 } 511 }
457 } 512 }
513
514 free(line);
458out: 515out:
459 free(rem_sq_bracket); 516 free(rem_sq_bracket);
460 517
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 055fef34b6f6..15a77b7c0e36 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -13,13 +13,22 @@ LF='
13# First check if there is a .git to get the version from git describe 13# First check if there is a .git to get the version from git describe
14# otherwise try to get the version from the kernel Makefile 14# otherwise try to get the version from the kernel Makefile
15# 15#
16if test -d ../../.git -o -f ../../.git && 16CID=
17 VN=$(git tag 2>/dev/null | tail -1 | grep -E "v[0-9].[0-9]*") 17TAG=
18if test -d ../../.git -o -f ../../.git
18then 19then
19 VN=$(echo $VN"-g"$(git log -1 --abbrev=4 --pretty=format:"%h" HEAD)) 20 TAG=$(git describe --abbrev=0 --match "v[0-9].[0-9]*" 2>/dev/null )
20 VN=$(echo "$VN" | sed -e 's/-/./g'); 21 CID=$(git log -1 --abbrev=4 --pretty=format:"%h" 2>/dev/null) && CID="-g$CID"
21else 22fi
22 VN=$(MAKEFLAGS= make -sC ../.. kernelversion) 23if test -z "$TAG"
24then
25 TAG=$(MAKEFLAGS= make -sC ../.. kernelversion)
26fi
27VN="$TAG$CID"
28if test -n "$CID"
29then
30 # format version string, strip trailing zero of sublevel:
31 VN=$(echo "$VN" | sed -e 's/-/./g;s/\([0-9]*[.][0-9]*\)[.]0/\1/')
23fi 32fi
24 33
25VN=$(expr "$VN" : v*'\(.*\)') 34VN=$(expr "$VN" : v*'\(.*\)')
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index d102716c43a1..7eae5488ecea 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -110,10 +110,10 @@ static int jump__parse(struct ins_operands *ops)
110{ 110{
111 const char *s = strchr(ops->raw, '+'); 111 const char *s = strchr(ops->raw, '+');
112 112
113 ops->target.addr = strtoll(ops->raw, NULL, 16); 113 ops->target.addr = strtoull(ops->raw, NULL, 16);
114 114
115 if (s++ != NULL) 115 if (s++ != NULL)
116 ops->target.offset = strtoll(s, NULL, 16); 116 ops->target.offset = strtoull(s, NULL, 16);
117 else 117 else
118 ops->target.offset = UINT64_MAX; 118 ops->target.offset = UINT64_MAX;
119 119
@@ -809,7 +809,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
809 end = map__rip_2objdump(map, sym->end); 809 end = map__rip_2objdump(map, sym->end);
810 810
811 offset = line_ip - start; 811 offset = line_ip - start;
812 if (offset < 0 || (u64)line_ip > end) 812 if ((u64)line_ip < start || (u64)line_ip > end)
813 offset = -1; 813 offset = -1;
814 else 814 else
815 parsed_line = tmp2 + 1; 815 parsed_line = tmp2 + 1;
@@ -821,11 +821,55 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
821 if (dl == NULL) 821 if (dl == NULL)
822 return -1; 822 return -1;
823 823
824 if (dl->ops.target.offset == UINT64_MAX)
825 dl->ops.target.offset = dl->ops.target.addr -
826 map__rip_2objdump(map, sym->start);
827
828 /*
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) {
833 struct symbol *s;
834 u64 ip = dl->ops.target.addr;
835
836 if (ip >= map->start && ip <= map->end) {
837 ip = map->map_ip(map, ip);
838 s = map__find_symbol(map, ip, NULL);
839 if (s && s->start == ip)
840 dl->ops.target.name = strdup(s->name);
841 }
842 }
843
824 disasm__add(&notes->src->source, dl); 844 disasm__add(&notes->src->source, dl);
825 845
826 return 0; 846 return 0;
827} 847}
828 848
849static void delete_last_nop(struct symbol *sym)
850{
851 struct annotation *notes = symbol__annotation(sym);
852 struct list_head *list = &notes->src->source;
853 struct disasm_line *dl;
854
855 while (!list_empty(list)) {
856 dl = list_entry(list->prev, struct disasm_line, node);
857
858 if (dl->ins && dl->ins->ops) {
859 if (dl->ins->ops != &nop_ops)
860 return;
861 } else {
862 if (!strstr(dl->line, " nop ") &&
863 !strstr(dl->line, " nopl ") &&
864 !strstr(dl->line, " nopw "))
865 return;
866 }
867
868 list_del(&dl->node);
869 disasm_line__free(dl);
870 }
871}
872
829int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) 873int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
830{ 874{
831 struct dso *dso = map->dso; 875 struct dso *dso = map->dso;
@@ -864,7 +908,8 @@ fallback:
864 free_filename = false; 908 free_filename = false;
865 } 909 }
866 910
867 if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { 911 if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
912 !dso__is_kcore(dso)) {
868 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; 913 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
869 char *build_id_msg = NULL; 914 char *build_id_msg = NULL;
870 915
@@ -898,7 +943,7 @@ fallback:
898 snprintf(command, sizeof(command), 943 snprintf(command, sizeof(command),
899 "%s %s%s --start-address=0x%016" PRIx64 944 "%s %s%s --start-address=0x%016" PRIx64
900 " --stop-address=0x%016" PRIx64 945 " --stop-address=0x%016" PRIx64
901 " -d %s %s -C %s|grep -v %s|expand", 946 " -d %s %s -C %s 2>/dev/null|grep -v %s|expand",
902 objdump_path ? objdump_path : "objdump", 947 objdump_path ? objdump_path : "objdump",
903 disassembler_style ? "-M " : "", 948 disassembler_style ? "-M " : "",
904 disassembler_style ? disassembler_style : "", 949 disassembler_style ? disassembler_style : "",
@@ -918,6 +963,13 @@ fallback:
918 if (symbol__parse_objdump_line(sym, map, file, privsize) < 0) 963 if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
919 break; 964 break;
920 965
966 /*
967 * kallsyms does not have symbol sizes so there may a nop at the end.
968 * Remove it.
969 */
970 if (dso__is_kcore(dso))
971 delete_last_nop(sym);
972
921 pclose(file); 973 pclose(file);
922out_free_filename: 974out_free_filename:
923 if (free_filename) 975 if (free_filename)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 5295625c0c00..7ded71d19d75 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -18,13 +18,14 @@
18 18
19int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, 19int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
20 union perf_event *event, 20 union perf_event *event,
21 struct perf_sample *sample __maybe_unused, 21 struct perf_sample *sample,
22 struct perf_evsel *evsel __maybe_unused, 22 struct perf_evsel *evsel __maybe_unused,
23 struct machine *machine) 23 struct machine *machine)
24{ 24{
25 struct addr_location al; 25 struct addr_location al;
26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
27 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 27 struct thread *thread = machine__findnew_thread(machine, sample->pid,
28 sample->pid);
28 29
29 if (thread == NULL) { 30 if (thread == NULL) {
30 pr_err("problem processing %d event, skipping it.\n", 31 pr_err("problem processing %d event, skipping it.\n",
@@ -33,7 +34,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
33 } 34 }
34 35
35 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 36 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
36 event->ip.ip, &al); 37 sample->ip, &al);
37 38
38 if (al.map != NULL) 39 if (al.map != NULL)
39 al.map->dso->hit = 1; 40 al.map->dso->hit = 1;
@@ -47,7 +48,9 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
47 __maybe_unused, 48 __maybe_unused,
48 struct machine *machine) 49 struct machine *machine)
49{ 50{
50 struct thread *thread = machine__findnew_thread(machine, event->fork.tid); 51 struct thread *thread = machine__findnew_thread(machine,
52 event->fork.pid,
53 event->fork.tid);
51 54
52 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, 55 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
53 event->fork.ppid, event->fork.ptid); 56 event->fork.ppid, event->fork.ptid);
@@ -64,6 +67,7 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
64struct perf_tool build_id__mark_dso_hit_ops = { 67struct perf_tool build_id__mark_dso_hit_ops = {
65 .sample = build_id__mark_dso_hit, 68 .sample = build_id__mark_dso_hit,
66 .mmap = perf_event__process_mmap, 69 .mmap = perf_event__process_mmap,
70 .mmap2 = perf_event__process_mmap2,
67 .fork = perf_event__process_fork, 71 .fork = perf_event__process_fork,
68 .exit = perf_event__exit_del_thread, 72 .exit = perf_event__exit_del_thread,
69 .attr = perf_event__process_attr, 73 .attr = perf_event__process_attr,
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 42b6a632fe7b..482f68081cd8 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -15,19 +15,12 @@
15#include <errno.h> 15#include <errno.h>
16#include <math.h> 16#include <math.h>
17 17
18#include "hist.h"
18#include "util.h" 19#include "util.h"
19#include "callchain.h" 20#include "callchain.h"
20 21
21__thread struct callchain_cursor callchain_cursor; 22__thread struct callchain_cursor callchain_cursor;
22 23
23bool ip_callchain__valid(struct ip_callchain *chain,
24 const union perf_event *event)
25{
26 unsigned int chain_size = event->header.size;
27 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
28 return chain->nr * sizeof(u64) <= chain_size;
29}
30
31#define chain_for_each_child(child, parent) \ 24#define chain_for_each_child(child, parent) \
32 list_for_each_entry(child, &parent->children, siblings) 25 list_for_each_entry(child, &parent->children, siblings)
33 26
@@ -327,7 +320,8 @@ append_chain(struct callchain_node *root,
327 /* 320 /*
328 * Lookup in the current node 321 * Lookup in the current node
329 * If we have a symbol, then compare the start to match 322 * If we have a symbol, then compare the start to match
330 * anywhere inside a function. 323 * anywhere inside a function, unless function
324 * mode is disabled.
331 */ 325 */
332 list_for_each_entry(cnode, &root->val, list) { 326 list_for_each_entry(cnode, &root->val, list) {
333 struct callchain_cursor_node *node; 327 struct callchain_cursor_node *node;
@@ -339,7 +333,8 @@ append_chain(struct callchain_node *root,
339 333
340 sym = node->sym; 334 sym = node->sym;
341 335
342 if (cnode->ms.sym && sym) { 336 if (cnode->ms.sym && sym &&
337 callchain_param.key == CCKEY_FUNCTION) {
343 if (cnode->ms.sym->start != sym->start) 338 if (cnode->ms.sym->start != sym->start)
344 break; 339 break;
345 } else if (cnode->ip != node->ip) 340 } else if (cnode->ip != node->ip)
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 3ee9f67d5af0..2b585bc308cf 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -41,12 +41,18 @@ struct callchain_param;
41typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *, 41typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
42 u64, struct callchain_param *); 42 u64, struct callchain_param *);
43 43
44enum chain_key {
45 CCKEY_FUNCTION,
46 CCKEY_ADDRESS
47};
48
44struct callchain_param { 49struct callchain_param {
45 enum chain_mode mode; 50 enum chain_mode mode;
46 u32 print_limit; 51 u32 print_limit;
47 double min_percent; 52 double min_percent;
48 sort_chain_func_t sort; 53 sort_chain_func_t sort;
49 enum chain_order order; 54 enum chain_order order;
55 enum chain_key key;
50}; 56};
51 57
52struct callchain_list { 58struct callchain_list {
@@ -103,11 +109,6 @@ int callchain_append(struct callchain_root *root,
103int callchain_merge(struct callchain_cursor *cursor, 109int callchain_merge(struct callchain_cursor *cursor,
104 struct callchain_root *dst, struct callchain_root *src); 110 struct callchain_root *dst, struct callchain_root *src);
105 111
106struct ip_callchain;
107union perf_event;
108
109bool ip_callchain__valid(struct ip_callchain *chain,
110 const union perf_event *event);
111/* 112/*
112 * Initialize a cursor before adding entries inside, but keep 113 * Initialize a cursor before adding entries inside, but keep
113 * the previously allocated entries as a cache. 114 * the previously allocated entries as a cache.
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 9bed02e5fb3d..b123bb9d6f55 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -41,7 +41,7 @@ static inline int cpu_map__nr(const struct cpu_map *map)
41 return map ? map->nr : 1; 41 return map ? map->nr : 1;
42} 42}
43 43
44static inline bool cpu_map__all(const struct cpu_map *map) 44static inline bool cpu_map__empty(const struct cpu_map *map)
45{ 45{
46 return map ? map->map[0] == -1 : true; 46 return map ? map->map[0] == -1 : true;
47} 47}
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 6f7d5a9d6b05..e3c1ff8512c8 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -78,6 +78,8 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
78 symbol_conf.symfs, build_id_hex, build_id_hex + 2); 78 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
79 break; 79 break;
80 80
81 case DSO_BINARY_TYPE__VMLINUX:
82 case DSO_BINARY_TYPE__GUEST_VMLINUX:
81 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 83 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
82 snprintf(file, size, "%s%s", 84 snprintf(file, size, "%s%s",
83 symbol_conf.symfs, dso->long_name); 85 symbol_conf.symfs, dso->long_name);
@@ -93,11 +95,14 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
93 dso->long_name); 95 dso->long_name);
94 break; 96 break;
95 97
98 case DSO_BINARY_TYPE__KCORE:
99 case DSO_BINARY_TYPE__GUEST_KCORE:
100 snprintf(file, size, "%s", dso->long_name);
101 break;
102
96 default: 103 default:
97 case DSO_BINARY_TYPE__KALLSYMS: 104 case DSO_BINARY_TYPE__KALLSYMS:
98 case DSO_BINARY_TYPE__VMLINUX:
99 case DSO_BINARY_TYPE__GUEST_KALLSYMS: 105 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
100 case DSO_BINARY_TYPE__GUEST_VMLINUX:
101 case DSO_BINARY_TYPE__JAVA_JIT: 106 case DSO_BINARY_TYPE__JAVA_JIT:
102 case DSO_BINARY_TYPE__NOT_FOUND: 107 case DSO_BINARY_TYPE__NOT_FOUND:
103 ret = -1; 108 ret = -1;
@@ -419,6 +424,7 @@ struct dso *dso__new(const char *name)
419 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 424 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
420 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; 425 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
421 dso->loaded = 0; 426 dso->loaded = 0;
427 dso->rel = 0;
422 dso->sorted_by_name = 0; 428 dso->sorted_by_name = 0;
423 dso->has_build_id = 0; 429 dso->has_build_id = 0;
424 dso->kernel = DSO_TYPE_USER; 430 dso->kernel = DSO_TYPE_USER;
@@ -513,10 +519,16 @@ void dsos__add(struct list_head *head, struct dso *dso)
513 list_add_tail(&dso->node, head); 519 list_add_tail(&dso->node, head);
514} 520}
515 521
516struct dso *dsos__find(struct list_head *head, const char *name) 522struct dso *dsos__find(struct list_head *head, const char *name, bool cmp_short)
517{ 523{
518 struct dso *pos; 524 struct dso *pos;
519 525
526 if (cmp_short) {
527 list_for_each_entry(pos, head, node)
528 if (strcmp(pos->short_name, name) == 0)
529 return pos;
530 return NULL;
531 }
520 list_for_each_entry(pos, head, node) 532 list_for_each_entry(pos, head, node)
521 if (strcmp(pos->long_name, name) == 0) 533 if (strcmp(pos->long_name, name) == 0)
522 return pos; 534 return pos;
@@ -525,7 +537,7 @@ struct dso *dsos__find(struct list_head *head, const char *name)
525 537
526struct dso *__dsos__findnew(struct list_head *head, const char *name) 538struct dso *__dsos__findnew(struct list_head *head, const char *name)
527{ 539{
528 struct dso *dso = dsos__find(head, name); 540 struct dso *dso = dsos__find(head, name, false);
529 541
530 if (!dso) { 542 if (!dso) {
531 dso = dso__new(name); 543 dso = dso__new(name);
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 450199ab51b5..b793053335d6 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include <stdbool.h>
6#include "types.h" 7#include "types.h"
7#include "map.h" 8#include "map.h"
8 9
@@ -20,6 +21,8 @@ enum dso_binary_type {
20 DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 21 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
21 DSO_BINARY_TYPE__GUEST_KMODULE, 22 DSO_BINARY_TYPE__GUEST_KMODULE,
22 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 23 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
24 DSO_BINARY_TYPE__KCORE,
25 DSO_BINARY_TYPE__GUEST_KCORE,
23 DSO_BINARY_TYPE__NOT_FOUND, 26 DSO_BINARY_TYPE__NOT_FOUND,
24}; 27};
25 28
@@ -84,6 +87,7 @@ struct dso {
84 u8 lname_alloc:1; 87 u8 lname_alloc:1;
85 u8 sorted_by_name; 88 u8 sorted_by_name;
86 u8 loaded; 89 u8 loaded;
90 u8 rel;
87 u8 build_id[BUILD_ID_SIZE]; 91 u8 build_id[BUILD_ID_SIZE];
88 const char *short_name; 92 const char *short_name;
89 char *long_name; 93 char *long_name;
@@ -133,7 +137,8 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
133 const char *short_name, int dso_type); 137 const char *short_name, int dso_type);
134 138
135void dsos__add(struct list_head *head, struct dso *dso); 139void dsos__add(struct list_head *head, struct dso *dso);
136struct dso *dsos__find(struct list_head *head, const char *name); 140struct dso *dsos__find(struct list_head *head, const char *name,
141 bool cmp_short);
137struct dso *__dsos__findnew(struct list_head *head, const char *name); 142struct dso *__dsos__findnew(struct list_head *head, const char *name);
138bool __dsos__read_build_ids(struct list_head *head, bool with_hits); 143bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
139 144
@@ -145,4 +150,17 @@ size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
145size_t dso__fprintf_symbols_by_name(struct dso *dso, 150size_t dso__fprintf_symbols_by_name(struct dso *dso,
146 enum map_type type, FILE *fp); 151 enum map_type type, FILE *fp);
147size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); 152size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
153
154static inline bool dso__is_vmlinux(struct dso *dso)
155{
156 return dso->data_type == DSO_BINARY_TYPE__VMLINUX ||
157 dso->data_type == DSO_BINARY_TYPE__GUEST_VMLINUX;
158}
159
160static inline bool dso__is_kcore(struct dso *dso)
161{
162 return dso->data_type == DSO_BINARY_TYPE__KCORE ||
163 dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE;
164}
165
148#endif /* __PERF_DSO */ 166#endif /* __PERF_DSO */
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 3e5f5430a28a..e23bde19d590 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -263,6 +263,21 @@ bool die_is_signed_type(Dwarf_Die *tp_die)
263} 263}
264 264
265/** 265/**
266 * die_is_func_def - Ensure that this DIE is a subprogram and definition
267 * @dw_die: a DIE
268 *
269 * Ensure that this DIE is a subprogram and NOT a declaration. This
270 * returns true if @dw_die is a function definition.
271 **/
272bool die_is_func_def(Dwarf_Die *dw_die)
273{
274 Dwarf_Attribute attr;
275
276 return (dwarf_tag(dw_die) == DW_TAG_subprogram &&
277 dwarf_attr(dw_die, DW_AT_declaration, &attr) == NULL);
278}
279
280/**
266 * die_get_data_member_location - Get the data-member offset 281 * die_get_data_member_location - Get the data-member offset
267 * @mb_die: a DIE of a member of a data structure 282 * @mb_die: a DIE of a member of a data structure
268 * @offs: The offset of the member in the data structure 283 * @offs: The offset of the member in the data structure
@@ -392,6 +407,10 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
392{ 407{
393 struct __addr_die_search_param *ad = data; 408 struct __addr_die_search_param *ad = data;
394 409
410 /*
411 * Since a declaration entry doesn't has given pc, this always returns
412 * function definition entry.
413 */
395 if (dwarf_tag(fn_die) == DW_TAG_subprogram && 414 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
396 dwarf_haspc(fn_die, ad->addr)) { 415 dwarf_haspc(fn_die, ad->addr)) {
397 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); 416 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index 6ce1717784b7..8658d41697d2 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -38,6 +38,9 @@ extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
38extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, 38extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
39 int (*callback)(Dwarf_Die *, void *), void *data); 39 int (*callback)(Dwarf_Die *, void *), void *data);
40 40
41/* Ensure that this DIE is a subprogram and definition (not declaration) */
42extern bool die_is_func_def(Dwarf_Die *dw_die);
43
41/* Compare diename and tname */ 44/* Compare diename and tname */
42extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); 45extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
43 46
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 5cd13d768cec..9b393e7dca6f 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -11,6 +11,7 @@
11static const char *perf_event__names[] = { 11static const char *perf_event__names[] = {
12 [0] = "TOTAL", 12 [0] = "TOTAL",
13 [PERF_RECORD_MMAP] = "MMAP", 13 [PERF_RECORD_MMAP] = "MMAP",
14 [PERF_RECORD_MMAP2] = "MMAP2",
14 [PERF_RECORD_LOST] = "LOST", 15 [PERF_RECORD_LOST] = "LOST",
15 [PERF_RECORD_COMM] = "COMM", 16 [PERF_RECORD_COMM] = "COMM",
16 [PERF_RECORD_EXIT] = "EXIT", 17 [PERF_RECORD_EXIT] = "EXIT",
@@ -186,7 +187,7 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
186 return -1; 187 return -1;
187 } 188 }
188 189
189 event->header.type = PERF_RECORD_MMAP; 190 event->header.type = PERF_RECORD_MMAP2;
190 /* 191 /*
191 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 192 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
192 */ 193 */
@@ -197,7 +198,9 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
197 char prot[5]; 198 char prot[5];
198 char execname[PATH_MAX]; 199 char execname[PATH_MAX];
199 char anonstr[] = "//anon"; 200 char anonstr[] = "//anon";
201 unsigned int ino;
200 size_t size; 202 size_t size;
203 ssize_t n;
201 204
202 if (fgets(bf, sizeof(bf), fp) == NULL) 205 if (fgets(bf, sizeof(bf), fp) == NULL)
203 break; 206 break;
@@ -206,9 +209,16 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
206 strcpy(execname, ""); 209 strcpy(execname, "");
207 210
208 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 211 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
209 sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", 212 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
210 &event->mmap.start, &event->mmap.len, prot, 213 &event->mmap2.start, &event->mmap2.len, prot,
211 &event->mmap.pgoff, execname); 214 &event->mmap2.pgoff, &event->mmap2.maj,
215 &event->mmap2.min,
216 &ino, execname);
217
218 event->mmap2.ino = (u64)ino;
219
220 if (n != 8)
221 continue;
212 222
213 if (prot[2] != 'x') 223 if (prot[2] != 'x')
214 continue; 224 continue;
@@ -217,15 +227,15 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
217 strcpy(execname, anonstr); 227 strcpy(execname, anonstr);
218 228
219 size = strlen(execname) + 1; 229 size = strlen(execname) + 1;
220 memcpy(event->mmap.filename, execname, size); 230 memcpy(event->mmap2.filename, execname, size);
221 size = PERF_ALIGN(size, sizeof(u64)); 231 size = PERF_ALIGN(size, sizeof(u64));
222 event->mmap.len -= event->mmap.start; 232 event->mmap2.len -= event->mmap.start;
223 event->mmap.header.size = (sizeof(event->mmap) - 233 event->mmap2.header.size = (sizeof(event->mmap2) -
224 (sizeof(event->mmap.filename) - size)); 234 (sizeof(event->mmap2.filename) - size));
225 memset(event->mmap.filename + size, 0, machine->id_hdr_size); 235 memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
226 event->mmap.header.size += machine->id_hdr_size; 236 event->mmap2.header.size += machine->id_hdr_size;
227 event->mmap.pid = tgid; 237 event->mmap2.pid = tgid;
228 event->mmap.tid = pid; 238 event->mmap2.tid = pid;
229 239
230 if (process(tool, event, &synth_sample, machine) != 0) { 240 if (process(tool, event, &synth_sample, machine) != 0) {
231 rc = -1; 241 rc = -1;
@@ -527,6 +537,17 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
527 event->mmap.len, event->mmap.pgoff, event->mmap.filename); 537 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
528} 538}
529 539
540size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
541{
542 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
543 " %02x:%02x %"PRIu64" %"PRIu64"]: %s\n",
544 event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
545 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
546 event->mmap2.min, event->mmap2.ino,
547 event->mmap2.ino_generation,
548 event->mmap2.filename);
549}
550
530int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, 551int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
531 union perf_event *event, 552 union perf_event *event,
532 struct perf_sample *sample __maybe_unused, 553 struct perf_sample *sample __maybe_unused,
@@ -535,6 +556,14 @@ int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
535 return machine__process_mmap_event(machine, event); 556 return machine__process_mmap_event(machine, event);
536} 557}
537 558
559int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused,
560 union perf_event *event,
561 struct perf_sample *sample __maybe_unused,
562 struct machine *machine)
563{
564 return machine__process_mmap2_event(machine, event);
565}
566
538size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 567size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
539{ 568{
540 return fprintf(fp, "(%d:%d):(%d:%d)\n", 569 return fprintf(fp, "(%d:%d):(%d:%d)\n",
@@ -574,6 +603,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
574 case PERF_RECORD_MMAP: 603 case PERF_RECORD_MMAP:
575 ret += perf_event__fprintf_mmap(event, fp); 604 ret += perf_event__fprintf_mmap(event, fp);
576 break; 605 break;
606 case PERF_RECORD_MMAP2:
607 ret += perf_event__fprintf_mmap2(event, fp);
608 break;
577 default: 609 default:
578 ret += fprintf(fp, "\n"); 610 ret += fprintf(fp, "\n");
579 } 611 }
@@ -595,6 +627,7 @@ void thread__find_addr_map(struct thread *self,
595 struct addr_location *al) 627 struct addr_location *al)
596{ 628{
597 struct map_groups *mg = &self->mg; 629 struct map_groups *mg = &self->mg;
630 bool load_map = false;
598 631
599 al->thread = self; 632 al->thread = self;
600 al->addr = addr; 633 al->addr = addr;
@@ -609,11 +642,13 @@ void thread__find_addr_map(struct thread *self,
609 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { 642 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
610 al->level = 'k'; 643 al->level = 'k';
611 mg = &machine->kmaps; 644 mg = &machine->kmaps;
645 load_map = true;
612 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { 646 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
613 al->level = '.'; 647 al->level = '.';
614 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { 648 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
615 al->level = 'g'; 649 al->level = 'g';
616 mg = &machine->kmaps; 650 mg = &machine->kmaps;
651 load_map = true;
617 } else { 652 } else {
618 /* 653 /*
619 * 'u' means guest os user space. 654 * 'u' means guest os user space.
@@ -654,18 +689,25 @@ try_again:
654 mg = &machine->kmaps; 689 mg = &machine->kmaps;
655 goto try_again; 690 goto try_again;
656 } 691 }
657 } else 692 } else {
693 /*
694 * Kernel maps might be changed when loading symbols so loading
695 * must be done prior to using kernel maps.
696 */
697 if (load_map)
698 map__load(al->map, machine->symbol_filter);
658 al->addr = al->map->map_ip(al->map, al->addr); 699 al->addr = al->map->map_ip(al->map, al->addr);
700 }
659} 701}
660 702
661void thread__find_addr_location(struct thread *thread, struct machine *machine, 703void thread__find_addr_location(struct thread *thread, struct machine *machine,
662 u8 cpumode, enum map_type type, u64 addr, 704 u8 cpumode, enum map_type type, u64 addr,
663 struct addr_location *al, 705 struct addr_location *al)
664 symbol_filter_t filter)
665{ 706{
666 thread__find_addr_map(thread, machine, cpumode, type, addr, al); 707 thread__find_addr_map(thread, machine, cpumode, type, addr, al);
667 if (al->map != NULL) 708 if (al->map != NULL)
668 al->sym = map__find_symbol(al->map, al->addr, filter); 709 al->sym = map__find_symbol(al->map, al->addr,
710 machine->symbol_filter);
669 else 711 else
670 al->sym = NULL; 712 al->sym = NULL;
671} 713}
@@ -673,11 +715,11 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine,
673int perf_event__preprocess_sample(const union perf_event *event, 715int perf_event__preprocess_sample(const union perf_event *event,
674 struct machine *machine, 716 struct machine *machine,
675 struct addr_location *al, 717 struct addr_location *al,
676 struct perf_sample *sample, 718 struct perf_sample *sample)
677 symbol_filter_t filter)
678{ 719{
679 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 720 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
680 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 721 struct thread *thread = machine__findnew_thread(machine, sample->pid,
722 sample->pid);
681 723
682 if (thread == NULL) 724 if (thread == NULL)
683 return -1; 725 return -1;
@@ -686,7 +728,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
686 !strlist__has_entry(symbol_conf.comm_list, thread->comm)) 728 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
687 goto out_filtered; 729 goto out_filtered;
688 730
689 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 731 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
690 /* 732 /*
691 * Have we already created the kernel maps for this machine? 733 * Have we already created the kernel maps for this machine?
692 * 734 *
@@ -699,7 +741,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
699 machine__create_kernel_maps(machine); 741 machine__create_kernel_maps(machine);
700 742
701 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 743 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
702 event->ip.ip, al); 744 sample->ip, al);
703 dump_printf(" ...... dso: %s\n", 745 dump_printf(" ...... dso: %s\n",
704 al->map ? al->map->dso->long_name : 746 al->map ? al->map->dso->long_name :
705 al->level == 'H' ? "[hypervisor]" : "<not found>"); 747 al->level == 'H' ? "[hypervisor]" : "<not found>");
@@ -717,7 +759,8 @@ int perf_event__preprocess_sample(const union perf_event *event,
717 dso->long_name))))) 759 dso->long_name)))))
718 goto out_filtered; 760 goto out_filtered;
719 761
720 al->sym = map__find_symbol(al->map, al->addr, filter); 762 al->sym = map__find_symbol(al->map, al->addr,
763 machine->symbol_filter);
721 } 764 }
722 765
723 if (symbol_conf.sym_list && 766 if (symbol_conf.sym_list &&
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 181389535c0c..c67ecc457d29 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -8,22 +8,25 @@
8#include "map.h" 8#include "map.h"
9#include "build-id.h" 9#include "build-id.h"
10 10
11/* 11struct mmap_event {
12 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
13 */
14struct ip_event {
15 struct perf_event_header header; 12 struct perf_event_header header;
16 u64 ip;
17 u32 pid, tid; 13 u32 pid, tid;
18 unsigned char __more_data[]; 14 u64 start;
15 u64 len;
16 u64 pgoff;
17 char filename[PATH_MAX];
19}; 18};
20 19
21struct mmap_event { 20struct mmap2_event {
22 struct perf_event_header header; 21 struct perf_event_header header;
23 u32 pid, tid; 22 u32 pid, tid;
24 u64 start; 23 u64 start;
25 u64 len; 24 u64 len;
26 u64 pgoff; 25 u64 pgoff;
26 u32 maj;
27 u32 min;
28 u64 ino;
29 u64 ino_generation;
27 char filename[PATH_MAX]; 30 char filename[PATH_MAX];
28}; 31};
29 32
@@ -63,7 +66,8 @@ struct read_event {
63 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ 66 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
64 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ 67 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \
65 PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \ 68 PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \
66 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) 69 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \
70 PERF_SAMPLE_IDENTIFIER)
67 71
68struct sample_event { 72struct sample_event {
69 struct perf_event_header header; 73 struct perf_event_header header;
@@ -71,6 +75,7 @@ struct sample_event {
71}; 75};
72 76
73struct regs_dump { 77struct regs_dump {
78 u64 abi;
74 u64 *regs; 79 u64 *regs;
75}; 80};
76 81
@@ -80,6 +85,23 @@ struct stack_dump {
80 char *data; 85 char *data;
81}; 86};
82 87
88struct sample_read_value {
89 u64 value;
90 u64 id;
91};
92
93struct sample_read {
94 u64 time_enabled;
95 u64 time_running;
96 union {
97 struct {
98 u64 nr;
99 struct sample_read_value *values;
100 } group;
101 struct sample_read_value one;
102 };
103};
104
83struct perf_sample { 105struct perf_sample {
84 u64 ip; 106 u64 ip;
85 u32 pid, tid; 107 u32 pid, tid;
@@ -97,6 +119,7 @@ struct perf_sample {
97 struct branch_stack *branch_stack; 119 struct branch_stack *branch_stack;
98 struct regs_dump user_regs; 120 struct regs_dump user_regs;
99 struct stack_dump user_stack; 121 struct stack_dump user_stack;
122 struct sample_read read;
100}; 123};
101 124
102#define PERF_MEM_DATA_SRC_NONE \ 125#define PERF_MEM_DATA_SRC_NONE \
@@ -116,7 +139,7 @@ struct build_id_event {
116enum perf_user_event_type { /* above any possible kernel type */ 139enum perf_user_event_type { /* above any possible kernel type */
117 PERF_RECORD_USER_TYPE_START = 64, 140 PERF_RECORD_USER_TYPE_START = 64,
118 PERF_RECORD_HEADER_ATTR = 64, 141 PERF_RECORD_HEADER_ATTR = 64,
119 PERF_RECORD_HEADER_EVENT_TYPE = 65, 142 PERF_RECORD_HEADER_EVENT_TYPE = 65, /* depreceated */
120 PERF_RECORD_HEADER_TRACING_DATA = 66, 143 PERF_RECORD_HEADER_TRACING_DATA = 66,
121 PERF_RECORD_HEADER_BUILD_ID = 67, 144 PERF_RECORD_HEADER_BUILD_ID = 67,
122 PERF_RECORD_FINISHED_ROUND = 68, 145 PERF_RECORD_FINISHED_ROUND = 68,
@@ -148,8 +171,8 @@ struct tracing_data_event {
148 171
149union perf_event { 172union perf_event {
150 struct perf_event_header header; 173 struct perf_event_header header;
151 struct ip_event ip;
152 struct mmap_event mmap; 174 struct mmap_event mmap;
175 struct mmap2_event mmap2;
153 struct comm_event comm; 176 struct comm_event comm;
154 struct fork_event fork; 177 struct fork_event fork;
155 struct lost_event lost; 178 struct lost_event lost;
@@ -199,6 +222,10 @@ int perf_event__process_mmap(struct perf_tool *tool,
199 union perf_event *event, 222 union perf_event *event,
200 struct perf_sample *sample, 223 struct perf_sample *sample,
201 struct machine *machine); 224 struct machine *machine);
225int perf_event__process_mmap2(struct perf_tool *tool,
226 union perf_event *event,
227 struct perf_sample *sample,
228 struct machine *machine);
202int perf_event__process_fork(struct perf_tool *tool, 229int perf_event__process_fork(struct perf_tool *tool,
203 union perf_event *event, 230 union perf_event *event,
204 struct perf_sample *sample, 231 struct perf_sample *sample,
@@ -216,17 +243,20 @@ struct addr_location;
216int perf_event__preprocess_sample(const union perf_event *self, 243int perf_event__preprocess_sample(const union perf_event *self,
217 struct machine *machine, 244 struct machine *machine,
218 struct addr_location *al, 245 struct addr_location *al,
219 struct perf_sample *sample, 246 struct perf_sample *sample);
220 symbol_filter_t filter);
221 247
222const char *perf_event__name(unsigned int id); 248const char *perf_event__name(unsigned int id);
223 249
250size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
251 u64 sample_regs_user, u64 read_format);
224int perf_event__synthesize_sample(union perf_event *event, u64 type, 252int perf_event__synthesize_sample(union perf_event *event, u64 type,
253 u64 sample_regs_user, u64 read_format,
225 const struct perf_sample *sample, 254 const struct perf_sample *sample,
226 bool swapped); 255 bool swapped);
227 256
228size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); 257size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
229size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); 258size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
259size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
230size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); 260size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
231size_t perf_event__fprintf(union perf_event *event, FILE *fp); 261size_t perf_event__fprintf(union perf_event *event, FILE *fp);
232 262
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index f7c727801aab..f9f77bee0b1b 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -14,6 +14,7 @@
14#include "target.h" 14#include "target.h"
15#include "evlist.h" 15#include "evlist.h"
16#include "evsel.h" 16#include "evsel.h"
17#include "debug.h"
17#include <unistd.h> 18#include <unistd.h>
18 19
19#include "parse-events.h" 20#include "parse-events.h"
@@ -48,26 +49,29 @@ struct perf_evlist *perf_evlist__new(void)
48 return evlist; 49 return evlist;
49} 50}
50 51
51void perf_evlist__config(struct perf_evlist *evlist, 52/**
52 struct perf_record_opts *opts) 53 * perf_evlist__set_id_pos - set the positions of event ids.
54 * @evlist: selected event list
55 *
56 * Events with compatible sample types all have the same id_pos
57 * and is_pos. For convenience, put a copy on evlist.
58 */
59void perf_evlist__set_id_pos(struct perf_evlist *evlist)
53{ 60{
54 struct perf_evsel *evsel; 61 struct perf_evsel *first = perf_evlist__first(evlist);
55 /*
56 * Set the evsel leader links before we configure attributes,
57 * since some might depend on this info.
58 */
59 if (opts->group)
60 perf_evlist__set_leader(evlist);
61 62
62 if (evlist->cpus->map[0] < 0) 63 evlist->id_pos = first->id_pos;
63 opts->no_inherit = true; 64 evlist->is_pos = first->is_pos;
65}
64 66
65 list_for_each_entry(evsel, &evlist->entries, node) { 67static void perf_evlist__update_id_pos(struct perf_evlist *evlist)
66 perf_evsel__config(evsel, opts); 68{
69 struct perf_evsel *evsel;
67 70
68 if (evlist->nr_entries > 1) 71 list_for_each_entry(evsel, &evlist->entries, node)
69 perf_evsel__set_sample_id(evsel); 72 perf_evsel__calc_id_pos(evsel);
70 } 73
74 perf_evlist__set_id_pos(evlist);
71} 75}
72 76
73static void perf_evlist__purge(struct perf_evlist *evlist) 77static void perf_evlist__purge(struct perf_evlist *evlist)
@@ -100,15 +104,20 @@ void perf_evlist__delete(struct perf_evlist *evlist)
100void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) 104void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
101{ 105{
102 list_add_tail(&entry->node, &evlist->entries); 106 list_add_tail(&entry->node, &evlist->entries);
103 ++evlist->nr_entries; 107 if (!evlist->nr_entries++)
108 perf_evlist__set_id_pos(evlist);
104} 109}
105 110
106void perf_evlist__splice_list_tail(struct perf_evlist *evlist, 111void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
107 struct list_head *list, 112 struct list_head *list,
108 int nr_entries) 113 int nr_entries)
109{ 114{
115 bool set_id_pos = !evlist->nr_entries;
116
110 list_splice_tail(list, &evlist->entries); 117 list_splice_tail(list, &evlist->entries);
111 evlist->nr_entries += nr_entries; 118 evlist->nr_entries += nr_entries;
119 if (set_id_pos)
120 perf_evlist__set_id_pos(evlist);
112} 121}
113 122
114void __perf_evlist__set_leader(struct list_head *list) 123void __perf_evlist__set_leader(struct list_head *list)
@@ -209,6 +218,21 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
209 return NULL; 218 return NULL;
210} 219}
211 220
221struct perf_evsel *
222perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
223 const char *name)
224{
225 struct perf_evsel *evsel;
226
227 list_for_each_entry(evsel, &evlist->entries, node) {
228 if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) &&
229 (strcmp(evsel->name, name) == 0))
230 return evsel;
231 }
232
233 return NULL;
234}
235
212int perf_evlist__add_newtp(struct perf_evlist *evlist, 236int perf_evlist__add_newtp(struct perf_evlist *evlist,
213 const char *sys, const char *name, void *handler) 237 const char *sys, const char *name, void *handler)
214{ 238{
@@ -232,7 +256,7 @@ void perf_evlist__disable(struct perf_evlist *evlist)
232 256
233 for (cpu = 0; cpu < nr_cpus; cpu++) { 257 for (cpu = 0; cpu < nr_cpus; cpu++) {
234 list_for_each_entry(pos, &evlist->entries, node) { 258 list_for_each_entry(pos, &evlist->entries, node) {
235 if (!perf_evsel__is_group_leader(pos)) 259 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
236 continue; 260 continue;
237 for (thread = 0; thread < nr_threads; thread++) 261 for (thread = 0; thread < nr_threads; thread++)
238 ioctl(FD(pos, cpu, thread), 262 ioctl(FD(pos, cpu, thread),
@@ -250,7 +274,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
250 274
251 for (cpu = 0; cpu < nr_cpus; cpu++) { 275 for (cpu = 0; cpu < nr_cpus; cpu++) {
252 list_for_each_entry(pos, &evlist->entries, node) { 276 list_for_each_entry(pos, &evlist->entries, node) {
253 if (!perf_evsel__is_group_leader(pos)) 277 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
254 continue; 278 continue;
255 for (thread = 0; thread < nr_threads; thread++) 279 for (thread = 0; thread < nr_threads; thread++)
256 ioctl(FD(pos, cpu, thread), 280 ioctl(FD(pos, cpu, thread),
@@ -259,6 +283,44 @@ void perf_evlist__enable(struct perf_evlist *evlist)
259 } 283 }
260} 284}
261 285
286int perf_evlist__disable_event(struct perf_evlist *evlist,
287 struct perf_evsel *evsel)
288{
289 int cpu, thread, err;
290
291 if (!evsel->fd)
292 return 0;
293
294 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
295 for (thread = 0; thread < evlist->threads->nr; thread++) {
296 err = ioctl(FD(evsel, cpu, thread),
297 PERF_EVENT_IOC_DISABLE, 0);
298 if (err)
299 return err;
300 }
301 }
302 return 0;
303}
304
305int perf_evlist__enable_event(struct perf_evlist *evlist,
306 struct perf_evsel *evsel)
307{
308 int cpu, thread, err;
309
310 if (!evsel->fd)
311 return -EINVAL;
312
313 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
314 for (thread = 0; thread < evlist->threads->nr; thread++) {
315 err = ioctl(FD(evsel, cpu, thread),
316 PERF_EVENT_IOC_ENABLE, 0);
317 if (err)
318 return err;
319 }
320 }
321 return 0;
322}
323
262static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 324static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
263{ 325{
264 int nr_cpus = cpu_map__nr(evlist->cpus); 326 int nr_cpus = cpu_map__nr(evlist->cpus);
@@ -302,6 +364,24 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
302{ 364{
303 u64 read_data[4] = { 0, }; 365 u64 read_data[4] = { 0, };
304 int id_idx = 1; /* The first entry is the counter value */ 366 int id_idx = 1; /* The first entry is the counter value */
367 u64 id;
368 int ret;
369
370 ret = ioctl(fd, PERF_EVENT_IOC_ID, &id);
371 if (!ret)
372 goto add;
373
374 if (errno != ENOTTY)
375 return -1;
376
377 /* Legacy way to get event id.. All hail to old kernels! */
378
379 /*
380 * This way does not work with group format read, so bail
381 * out in that case.
382 */
383 if (perf_evlist__read_format(evlist) & PERF_FORMAT_GROUP)
384 return -1;
305 385
306 if (!(evsel->attr.read_format & PERF_FORMAT_ID) || 386 if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
307 read(fd, &read_data, sizeof(read_data)) == -1) 387 read(fd, &read_data, sizeof(read_data)) == -1)
@@ -312,25 +392,39 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
312 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 392 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
313 ++id_idx; 393 ++id_idx;
314 394
315 perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]); 395 id = read_data[id_idx];
396
397 add:
398 perf_evlist__id_add(evlist, evsel, cpu, thread, id);
316 return 0; 399 return 0;
317} 400}
318 401
319struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) 402struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id)
320{ 403{
321 struct hlist_head *head; 404 struct hlist_head *head;
322 struct perf_sample_id *sid; 405 struct perf_sample_id *sid;
323 int hash; 406 int hash;
324 407
325 if (evlist->nr_entries == 1)
326 return perf_evlist__first(evlist);
327
328 hash = hash_64(id, PERF_EVLIST__HLIST_BITS); 408 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
329 head = &evlist->heads[hash]; 409 head = &evlist->heads[hash];
330 410
331 hlist_for_each_entry(sid, head, node) 411 hlist_for_each_entry(sid, head, node)
332 if (sid->id == id) 412 if (sid->id == id)
333 return sid->evsel; 413 return sid;
414
415 return NULL;
416}
417
418struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
419{
420 struct perf_sample_id *sid;
421
422 if (evlist->nr_entries == 1)
423 return perf_evlist__first(evlist);
424
425 sid = perf_evlist__id2sid(evlist, id);
426 if (sid)
427 return sid->evsel;
334 428
335 if (!perf_evlist__sample_id_all(evlist)) 429 if (!perf_evlist__sample_id_all(evlist))
336 return perf_evlist__first(evlist); 430 return perf_evlist__first(evlist);
@@ -338,6 +432,60 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
338 return NULL; 432 return NULL;
339} 433}
340 434
435static int perf_evlist__event2id(struct perf_evlist *evlist,
436 union perf_event *event, u64 *id)
437{
438 const u64 *array = event->sample.array;
439 ssize_t n;
440
441 n = (event->header.size - sizeof(event->header)) >> 3;
442
443 if (event->header.type == PERF_RECORD_SAMPLE) {
444 if (evlist->id_pos >= n)
445 return -1;
446 *id = array[evlist->id_pos];
447 } else {
448 if (evlist->is_pos > n)
449 return -1;
450 n -= evlist->is_pos;
451 *id = array[n];
452 }
453 return 0;
454}
455
456static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
457 union perf_event *event)
458{
459 struct perf_evsel *first = perf_evlist__first(evlist);
460 struct hlist_head *head;
461 struct perf_sample_id *sid;
462 int hash;
463 u64 id;
464
465 if (evlist->nr_entries == 1)
466 return first;
467
468 if (!first->attr.sample_id_all &&
469 event->header.type != PERF_RECORD_SAMPLE)
470 return first;
471
472 if (perf_evlist__event2id(evlist, event, &id))
473 return NULL;
474
475 /* Synthesized events have an id of zero */
476 if (!id)
477 return first;
478
479 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
480 head = &evlist->heads[hash];
481
482 hlist_for_each_entry(sid, head, node) {
483 if (sid->id == id)
484 return sid->evsel;
485 }
486 return NULL;
487}
488
341union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) 489union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
342{ 490{
343 struct perf_mmap *md = &evlist->mmap[idx]; 491 struct perf_mmap *md = &evlist->mmap[idx];
@@ -403,16 +551,20 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
403 return event; 551 return event;
404} 552}
405 553
554static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
555{
556 if (evlist->mmap[idx].base != NULL) {
557 munmap(evlist->mmap[idx].base, evlist->mmap_len);
558 evlist->mmap[idx].base = NULL;
559 }
560}
561
406void perf_evlist__munmap(struct perf_evlist *evlist) 562void perf_evlist__munmap(struct perf_evlist *evlist)
407{ 563{
408 int i; 564 int i;
409 565
410 for (i = 0; i < evlist->nr_mmaps; i++) { 566 for (i = 0; i < evlist->nr_mmaps; i++)
411 if (evlist->mmap[i].base != NULL) { 567 __perf_evlist__munmap(evlist, i);
412 munmap(evlist->mmap[i].base, evlist->mmap_len);
413 evlist->mmap[i].base = NULL;
414 }
415 }
416 568
417 free(evlist->mmap); 569 free(evlist->mmap);
418 evlist->mmap = NULL; 570 evlist->mmap = NULL;
@@ -421,7 +573,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
421static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) 573static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
422{ 574{
423 evlist->nr_mmaps = cpu_map__nr(evlist->cpus); 575 evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
424 if (cpu_map__all(evlist->cpus)) 576 if (cpu_map__empty(evlist->cpus))
425 evlist->nr_mmaps = thread_map__nr(evlist->threads); 577 evlist->nr_mmaps = thread_map__nr(evlist->threads);
426 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); 578 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
427 return evlist->mmap != NULL ? 0 : -ENOMEM; 579 return evlist->mmap != NULL ? 0 : -ENOMEM;
@@ -450,6 +602,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
450 int nr_cpus = cpu_map__nr(evlist->cpus); 602 int nr_cpus = cpu_map__nr(evlist->cpus);
451 int nr_threads = thread_map__nr(evlist->threads); 603 int nr_threads = thread_map__nr(evlist->threads);
452 604
605 pr_debug2("perf event ring buffer mmapped per cpu\n");
453 for (cpu = 0; cpu < nr_cpus; cpu++) { 606 for (cpu = 0; cpu < nr_cpus; cpu++) {
454 int output = -1; 607 int output = -1;
455 608
@@ -477,12 +630,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
477 return 0; 630 return 0;
478 631
479out_unmap: 632out_unmap:
480 for (cpu = 0; cpu < nr_cpus; cpu++) { 633 for (cpu = 0; cpu < nr_cpus; cpu++)
481 if (evlist->mmap[cpu].base != NULL) { 634 __perf_evlist__munmap(evlist, cpu);
482 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
483 evlist->mmap[cpu].base = NULL;
484 }
485 }
486 return -1; 635 return -1;
487} 636}
488 637
@@ -492,6 +641,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
492 int thread; 641 int thread;
493 int nr_threads = thread_map__nr(evlist->threads); 642 int nr_threads = thread_map__nr(evlist->threads);
494 643
644 pr_debug2("perf event ring buffer mmapped per thread\n");
495 for (thread = 0; thread < nr_threads; thread++) { 645 for (thread = 0; thread < nr_threads; thread++) {
496 int output = -1; 646 int output = -1;
497 647
@@ -517,12 +667,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
517 return 0; 667 return 0;
518 668
519out_unmap: 669out_unmap:
520 for (thread = 0; thread < nr_threads; thread++) { 670 for (thread = 0; thread < nr_threads; thread++)
521 if (evlist->mmap[thread].base != NULL) { 671 __perf_evlist__munmap(evlist, thread);
522 munmap(evlist->mmap[thread].base, evlist->mmap_len);
523 evlist->mmap[thread].base = NULL;
524 }
525 }
526 return -1; 672 return -1;
527} 673}
528 674
@@ -573,7 +719,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
573 return -ENOMEM; 719 return -ENOMEM;
574 } 720 }
575 721
576 if (cpu_map__all(cpus)) 722 if (cpu_map__empty(cpus))
577 return perf_evlist__mmap_per_thread(evlist, prot, mask); 723 return perf_evlist__mmap_per_thread(evlist, prot, mask);
578 724
579 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 725 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
@@ -650,20 +796,66 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
650 796
651bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) 797bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
652{ 798{
799 struct perf_evsel *pos;
800
801 if (evlist->nr_entries == 1)
802 return true;
803
804 if (evlist->id_pos < 0 || evlist->is_pos < 0)
805 return false;
806
807 list_for_each_entry(pos, &evlist->entries, node) {
808 if (pos->id_pos != evlist->id_pos ||
809 pos->is_pos != evlist->is_pos)
810 return false;
811 }
812
813 return true;
814}
815
816u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist)
817{
818 struct perf_evsel *evsel;
819
820 if (evlist->combined_sample_type)
821 return evlist->combined_sample_type;
822
823 list_for_each_entry(evsel, &evlist->entries, node)
824 evlist->combined_sample_type |= evsel->attr.sample_type;
825
826 return evlist->combined_sample_type;
827}
828
829u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist)
830{
831 evlist->combined_sample_type = 0;
832 return __perf_evlist__combined_sample_type(evlist);
833}
834
835bool perf_evlist__valid_read_format(struct perf_evlist *evlist)
836{
653 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; 837 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
838 u64 read_format = first->attr.read_format;
839 u64 sample_type = first->attr.sample_type;
654 840
655 list_for_each_entry_continue(pos, &evlist->entries, node) { 841 list_for_each_entry_continue(pos, &evlist->entries, node) {
656 if (first->attr.sample_type != pos->attr.sample_type) 842 if (read_format != pos->attr.read_format)
657 return false; 843 return false;
658 } 844 }
659 845
846 /* PERF_SAMPLE_READ imples PERF_FORMAT_ID. */
847 if ((sample_type & PERF_SAMPLE_READ) &&
848 !(read_format & PERF_FORMAT_ID)) {
849 return false;
850 }
851
660 return true; 852 return true;
661} 853}
662 854
663u64 perf_evlist__sample_type(struct perf_evlist *evlist) 855u64 perf_evlist__read_format(struct perf_evlist *evlist)
664{ 856{
665 struct perf_evsel *first = perf_evlist__first(evlist); 857 struct perf_evsel *first = perf_evlist__first(evlist);
666 return first->attr.sample_type; 858 return first->attr.read_format;
667} 859}
668 860
669u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist) 861u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist)
@@ -692,6 +884,9 @@ u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist)
692 884
693 if (sample_type & PERF_SAMPLE_CPU) 885 if (sample_type & PERF_SAMPLE_CPU)
694 size += sizeof(data->cpu) * 2; 886 size += sizeof(data->cpu) * 2;
887
888 if (sample_type & PERF_SAMPLE_IDENTIFIER)
889 size += sizeof(data->id);
695out: 890out:
696 return size; 891 return size;
697} 892}
@@ -735,6 +930,8 @@ int perf_evlist__open(struct perf_evlist *evlist)
735 struct perf_evsel *evsel; 930 struct perf_evsel *evsel;
736 int err; 931 int err;
737 932
933 perf_evlist__update_id_pos(evlist);
934
738 list_for_each_entry(evsel, &evlist->entries, node) { 935 list_for_each_entry(evsel, &evlist->entries, node) {
739 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); 936 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
740 if (err < 0) 937 if (err < 0)
@@ -776,18 +973,13 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
776 if (pipe_output) 973 if (pipe_output)
777 dup2(2, 1); 974 dup2(2, 1);
778 975
976 signal(SIGTERM, SIG_DFL);
977
779 close(child_ready_pipe[0]); 978 close(child_ready_pipe[0]);
780 close(go_pipe[1]); 979 close(go_pipe[1]);
781 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); 980 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
782 981
783 /* 982 /*
784 * Do a dummy execvp to get the PLT entry resolved,
785 * so we avoid the resolver overhead on the real
786 * execvp call.
787 */
788 execvp("", (char **)argv);
789
790 /*
791 * Tell the parent we're ready to go 983 * Tell the parent we're ready to go
792 */ 984 */
793 close(child_ready_pipe[1]); 985 close(child_ready_pipe[1]);
@@ -819,6 +1011,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
819 goto out_close_pipes; 1011 goto out_close_pipes;
820 } 1012 }
821 1013
1014 fcntl(go_pipe[1], F_SETFD, FD_CLOEXEC);
822 evlist->workload.cork_fd = go_pipe[1]; 1015 evlist->workload.cork_fd = go_pipe[1];
823 close(child_ready_pipe[0]); 1016 close(child_ready_pipe[0]);
824 return 0; 1017 return 0;
@@ -835,10 +1028,17 @@ out_close_ready_pipe:
835int perf_evlist__start_workload(struct perf_evlist *evlist) 1028int perf_evlist__start_workload(struct perf_evlist *evlist)
836{ 1029{
837 if (evlist->workload.cork_fd > 0) { 1030 if (evlist->workload.cork_fd > 0) {
1031 char bf = 0;
1032 int ret;
838 /* 1033 /*
839 * Remove the cork, let it rip! 1034 * Remove the cork, let it rip!
840 */ 1035 */
841 return close(evlist->workload.cork_fd); 1036 ret = write(evlist->workload.cork_fd, &bf, 1);
1037 if (ret < 0)
1038 perror("enable to write to pipe");
1039
1040 close(evlist->workload.cork_fd);
1041 return ret;
842 } 1042 }
843 1043
844 return 0; 1044 return 0;
@@ -847,7 +1047,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist)
847int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, 1047int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
848 struct perf_sample *sample) 1048 struct perf_sample *sample)
849{ 1049{
850 struct perf_evsel *evsel = perf_evlist__first(evlist); 1050 struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
1051
1052 if (!evsel)
1053 return -EFAULT;
851 return perf_evsel__parse_sample(evsel, event, sample); 1054 return perf_evsel__parse_sample(evsel, event, sample);
852} 1055}
853 1056
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 0583d36252be..880d7139d2fb 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -32,6 +32,9 @@ struct perf_evlist {
32 int nr_fds; 32 int nr_fds;
33 int nr_mmaps; 33 int nr_mmaps;
34 int mmap_len; 34 int mmap_len;
35 int id_pos;
36 int is_pos;
37 u64 combined_sample_type;
35 struct { 38 struct {
36 int cork_fd; 39 int cork_fd;
37 pid_t pid; 40 pid_t pid;
@@ -71,6 +74,10 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter);
71struct perf_evsel * 74struct perf_evsel *
72perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); 75perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id);
73 76
77struct perf_evsel *
78perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
79 const char *name);
80
74void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, 81void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
75 int cpu, int thread, u64 id); 82 int cpu, int thread, u64 id);
76 83
@@ -78,11 +85,15 @@ void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
78 85
79struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); 86struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
80 87
88struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id);
89
81union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 90union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
82 91
83int perf_evlist__open(struct perf_evlist *evlist); 92int perf_evlist__open(struct perf_evlist *evlist);
84void perf_evlist__close(struct perf_evlist *evlist); 93void perf_evlist__close(struct perf_evlist *evlist);
85 94
95void perf_evlist__set_id_pos(struct perf_evlist *evlist);
96bool perf_can_sample_identifier(void);
86void perf_evlist__config(struct perf_evlist *evlist, 97void perf_evlist__config(struct perf_evlist *evlist,
87 struct perf_record_opts *opts); 98 struct perf_record_opts *opts);
88 99
@@ -99,6 +110,11 @@ void perf_evlist__munmap(struct perf_evlist *evlist);
99void perf_evlist__disable(struct perf_evlist *evlist); 110void perf_evlist__disable(struct perf_evlist *evlist);
100void perf_evlist__enable(struct perf_evlist *evlist); 111void perf_evlist__enable(struct perf_evlist *evlist);
101 112
113int perf_evlist__disable_event(struct perf_evlist *evlist,
114 struct perf_evsel *evsel);
115int perf_evlist__enable_event(struct perf_evlist *evlist,
116 struct perf_evsel *evsel);
117
102void perf_evlist__set_selected(struct perf_evlist *evlist, 118void perf_evlist__set_selected(struct perf_evlist *evlist,
103 struct perf_evsel *evsel); 119 struct perf_evsel *evsel);
104 120
@@ -118,7 +134,9 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist);
118void __perf_evlist__set_leader(struct list_head *list); 134void __perf_evlist__set_leader(struct list_head *list);
119void perf_evlist__set_leader(struct perf_evlist *evlist); 135void perf_evlist__set_leader(struct perf_evlist *evlist);
120 136
121u64 perf_evlist__sample_type(struct perf_evlist *evlist); 137u64 perf_evlist__read_format(struct perf_evlist *evlist);
138u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist);
139u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist);
122bool perf_evlist__sample_id_all(struct perf_evlist *evlist); 140bool perf_evlist__sample_id_all(struct perf_evlist *evlist);
123u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); 141u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist);
124 142
@@ -127,6 +145,7 @@ int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *even
127 145
128bool perf_evlist__valid_sample_type(struct perf_evlist *evlist); 146bool perf_evlist__valid_sample_type(struct perf_evlist *evlist);
129bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist); 147bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist);
148bool perf_evlist__valid_read_format(struct perf_evlist *evlist);
130 149
131void perf_evlist__splice_list_tail(struct perf_evlist *evlist, 150void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
132 struct list_head *list, 151 struct list_head *list,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 07b1a3ad3e24..0ce9febf1ba0 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -9,27 +9,30 @@
9 9
10#include <byteswap.h> 10#include <byteswap.h>
11#include <linux/bitops.h> 11#include <linux/bitops.h>
12#include "asm/bug.h"
13#include <lk/debugfs.h> 12#include <lk/debugfs.h>
14#include "event-parse.h" 13#include <traceevent/event-parse.h>
14#include <linux/hw_breakpoint.h>
15#include <linux/perf_event.h>
16#include <sys/resource.h>
17#include "asm/bug.h"
15#include "evsel.h" 18#include "evsel.h"
16#include "evlist.h" 19#include "evlist.h"
17#include "util.h" 20#include "util.h"
18#include "cpumap.h" 21#include "cpumap.h"
19#include "thread_map.h" 22#include "thread_map.h"
20#include "target.h" 23#include "target.h"
21#include <linux/hw_breakpoint.h>
22#include <linux/perf_event.h>
23#include "perf_regs.h" 24#include "perf_regs.h"
25#include "debug.h"
24 26
25static struct { 27static struct {
26 bool sample_id_all; 28 bool sample_id_all;
27 bool exclude_guest; 29 bool exclude_guest;
30 bool mmap2;
28} perf_missing_features; 31} perf_missing_features;
29 32
30#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 33#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
31 34
32static int __perf_evsel__sample_size(u64 sample_type) 35int __perf_evsel__sample_size(u64 sample_type)
33{ 36{
34 u64 mask = sample_type & PERF_SAMPLE_MASK; 37 u64 mask = sample_type & PERF_SAMPLE_MASK;
35 int size = 0; 38 int size = 0;
@@ -45,6 +48,72 @@ static int __perf_evsel__sample_size(u64 sample_type)
45 return size; 48 return size;
46} 49}
47 50
51/**
52 * __perf_evsel__calc_id_pos - calculate id_pos.
53 * @sample_type: sample type
54 *
55 * This function returns the position of the event id (PERF_SAMPLE_ID or
56 * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of struct
57 * sample_event.
58 */
59static int __perf_evsel__calc_id_pos(u64 sample_type)
60{
61 int idx = 0;
62
63 if (sample_type & PERF_SAMPLE_IDENTIFIER)
64 return 0;
65
66 if (!(sample_type & PERF_SAMPLE_ID))
67 return -1;
68
69 if (sample_type & PERF_SAMPLE_IP)
70 idx += 1;
71
72 if (sample_type & PERF_SAMPLE_TID)
73 idx += 1;
74
75 if (sample_type & PERF_SAMPLE_TIME)
76 idx += 1;
77
78 if (sample_type & PERF_SAMPLE_ADDR)
79 idx += 1;
80
81 return idx;
82}
83
84/**
85 * __perf_evsel__calc_is_pos - calculate is_pos.
86 * @sample_type: sample type
87 *
88 * This function returns the position (counting backwards) of the event id
89 * (PERF_SAMPLE_ID or PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if
90 * sample_id_all is used there is an id sample appended to non-sample events.
91 */
92static int __perf_evsel__calc_is_pos(u64 sample_type)
93{
94 int idx = 1;
95
96 if (sample_type & PERF_SAMPLE_IDENTIFIER)
97 return 1;
98
99 if (!(sample_type & PERF_SAMPLE_ID))
100 return -1;
101
102 if (sample_type & PERF_SAMPLE_CPU)
103 idx += 1;
104
105 if (sample_type & PERF_SAMPLE_STREAM_ID)
106 idx += 1;
107
108 return idx;
109}
110
111void perf_evsel__calc_id_pos(struct perf_evsel *evsel)
112{
113 evsel->id_pos = __perf_evsel__calc_id_pos(evsel->attr.sample_type);
114 evsel->is_pos = __perf_evsel__calc_is_pos(evsel->attr.sample_type);
115}
116
48void hists__init(struct hists *hists) 117void hists__init(struct hists *hists)
49{ 118{
50 memset(hists, 0, sizeof(*hists)); 119 memset(hists, 0, sizeof(*hists));
@@ -61,6 +130,7 @@ void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
61 if (!(evsel->attr.sample_type & bit)) { 130 if (!(evsel->attr.sample_type & bit)) {
62 evsel->attr.sample_type |= bit; 131 evsel->attr.sample_type |= bit;
63 evsel->sample_size += sizeof(u64); 132 evsel->sample_size += sizeof(u64);
133 perf_evsel__calc_id_pos(evsel);
64 } 134 }
65} 135}
66 136
@@ -70,12 +140,19 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
70 if (evsel->attr.sample_type & bit) { 140 if (evsel->attr.sample_type & bit) {
71 evsel->attr.sample_type &= ~bit; 141 evsel->attr.sample_type &= ~bit;
72 evsel->sample_size -= sizeof(u64); 142 evsel->sample_size -= sizeof(u64);
143 perf_evsel__calc_id_pos(evsel);
73 } 144 }
74} 145}
75 146
76void perf_evsel__set_sample_id(struct perf_evsel *evsel) 147void perf_evsel__set_sample_id(struct perf_evsel *evsel,
148 bool can_sample_identifier)
77{ 149{
78 perf_evsel__set_sample_bit(evsel, ID); 150 if (can_sample_identifier) {
151 perf_evsel__reset_sample_bit(evsel, ID);
152 perf_evsel__set_sample_bit(evsel, IDENTIFIER);
153 } else {
154 perf_evsel__set_sample_bit(evsel, ID);
155 }
79 evsel->attr.read_format |= PERF_FORMAT_ID; 156 evsel->attr.read_format |= PERF_FORMAT_ID;
80} 157}
81 158
@@ -88,6 +165,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
88 INIT_LIST_HEAD(&evsel->node); 165 INIT_LIST_HEAD(&evsel->node);
89 hists__init(&evsel->hists); 166 hists__init(&evsel->hists);
90 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 167 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
168 perf_evsel__calc_id_pos(evsel);
91} 169}
92 170
93struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 171struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
@@ -124,7 +202,7 @@ struct event_format *event_format__new(const char *sys, const char *name)
124 bf = nbf; 202 bf = nbf;
125 } 203 }
126 204
127 n = read(fd, bf + size, BUFSIZ); 205 n = read(fd, bf + size, alloc_size - size);
128 if (n < 0) 206 if (n < 0)
129 goto out_free_bf; 207 goto out_free_bf;
130 size += n; 208 size += n;
@@ -246,6 +324,7 @@ const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
246 "major-faults", 324 "major-faults",
247 "alignment-faults", 325 "alignment-faults",
248 "emulation-faults", 326 "emulation-faults",
327 "dummy",
249}; 328};
250 329
251static const char *__perf_evsel__sw_name(u64 config) 330static const char *__perf_evsel__sw_name(u64 config)
@@ -490,6 +569,7 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
490void perf_evsel__config(struct perf_evsel *evsel, 569void perf_evsel__config(struct perf_evsel *evsel,
491 struct perf_record_opts *opts) 570 struct perf_record_opts *opts)
492{ 571{
572 struct perf_evsel *leader = evsel->leader;
493 struct perf_event_attr *attr = &evsel->attr; 573 struct perf_event_attr *attr = &evsel->attr;
494 int track = !evsel->idx; /* only the first counter needs these */ 574 int track = !evsel->idx; /* only the first counter needs these */
495 575
@@ -499,6 +579,25 @@ void perf_evsel__config(struct perf_evsel *evsel,
499 perf_evsel__set_sample_bit(evsel, IP); 579 perf_evsel__set_sample_bit(evsel, IP);
500 perf_evsel__set_sample_bit(evsel, TID); 580 perf_evsel__set_sample_bit(evsel, TID);
501 581
582 if (evsel->sample_read) {
583 perf_evsel__set_sample_bit(evsel, READ);
584
585 /*
586 * We need ID even in case of single event, because
587 * PERF_SAMPLE_READ process ID specific data.
588 */
589 perf_evsel__set_sample_id(evsel, false);
590
591 /*
592 * Apply group format only if we belong to group
593 * with more than one members.
594 */
595 if (leader->nr_members > 1) {
596 attr->read_format |= PERF_FORMAT_GROUP;
597 attr->inherit = 0;
598 }
599 }
600
502 /* 601 /*
503 * We default some events to a 1 default interval. But keep 602 * We default some events to a 1 default interval. But keep
504 * it a weak assumption overridable by the user. 603 * it a weak assumption overridable by the user.
@@ -514,6 +613,15 @@ void perf_evsel__config(struct perf_evsel *evsel,
514 } 613 }
515 } 614 }
516 615
616 /*
617 * Disable sampling for all group members other
618 * than leader in case leader 'leads' the sampling.
619 */
620 if ((leader != evsel) && leader->sample_read) {
621 attr->sample_freq = 0;
622 attr->sample_period = 0;
623 }
624
517 if (opts->no_samples) 625 if (opts->no_samples)
518 attr->sample_freq = 0; 626 attr->sample_freq = 0;
519 627
@@ -569,8 +677,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
569 if (opts->sample_weight) 677 if (opts->sample_weight)
570 attr->sample_type |= PERF_SAMPLE_WEIGHT; 678 attr->sample_type |= PERF_SAMPLE_WEIGHT;
571 679
572 attr->mmap = track; 680 attr->mmap = track;
573 attr->comm = track; 681 attr->mmap2 = track && !perf_missing_features.mmap2;
682 attr->comm = track;
574 683
575 /* 684 /*
576 * XXX see the function comment above 685 * XXX see the function comment above
@@ -605,15 +714,15 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
605 return evsel->fd != NULL ? 0 : -ENOMEM; 714 return evsel->fd != NULL ? 0 : -ENOMEM;
606} 715}
607 716
608int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 717static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthreads,
609 const char *filter) 718 int ioc, void *arg)
610{ 719{
611 int cpu, thread; 720 int cpu, thread;
612 721
613 for (cpu = 0; cpu < ncpus; cpu++) { 722 for (cpu = 0; cpu < ncpus; cpu++) {
614 for (thread = 0; thread < nthreads; thread++) { 723 for (thread = 0; thread < nthreads; thread++) {
615 int fd = FD(evsel, cpu, thread), 724 int fd = FD(evsel, cpu, thread),
616 err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter); 725 err = ioctl(fd, ioc, arg);
617 726
618 if (err) 727 if (err)
619 return err; 728 return err;
@@ -623,6 +732,21 @@ int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
623 return 0; 732 return 0;
624} 733}
625 734
735int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
736 const char *filter)
737{
738 return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
739 PERF_EVENT_IOC_SET_FILTER,
740 (void *)filter);
741}
742
743int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
744{
745 return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
746 PERF_EVENT_IOC_ENABLE,
747 0);
748}
749
626int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) 750int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
627{ 751{
628 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); 752 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
@@ -817,12 +941,72 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
817 return fd; 941 return fd;
818} 942}
819 943
944#define __PRINT_ATTR(fmt, cast, field) \
945 fprintf(fp, " %-19s "fmt"\n", #field, cast attr->field)
946
947#define PRINT_ATTR_U32(field) __PRINT_ATTR("%u" , , field)
948#define PRINT_ATTR_X32(field) __PRINT_ATTR("%#x", , field)
949#define PRINT_ATTR_U64(field) __PRINT_ATTR("%" PRIu64, (uint64_t), field)
950#define PRINT_ATTR_X64(field) __PRINT_ATTR("%#"PRIx64, (uint64_t), field)
951
952#define PRINT_ATTR2N(name1, field1, name2, field2) \
953 fprintf(fp, " %-19s %u %-19s %u\n", \
954 name1, attr->field1, name2, attr->field2)
955
956#define PRINT_ATTR2(field1, field2) \
957 PRINT_ATTR2N(#field1, field1, #field2, field2)
958
959static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
960{
961 size_t ret = 0;
962
963 ret += fprintf(fp, "%.60s\n", graph_dotted_line);
964 ret += fprintf(fp, "perf_event_attr:\n");
965
966 ret += PRINT_ATTR_U32(type);
967 ret += PRINT_ATTR_U32(size);
968 ret += PRINT_ATTR_X64(config);
969 ret += PRINT_ATTR_U64(sample_period);
970 ret += PRINT_ATTR_U64(sample_freq);
971 ret += PRINT_ATTR_X64(sample_type);
972 ret += PRINT_ATTR_X64(read_format);
973
974 ret += PRINT_ATTR2(disabled, inherit);
975 ret += PRINT_ATTR2(pinned, exclusive);
976 ret += PRINT_ATTR2(exclude_user, exclude_kernel);
977 ret += PRINT_ATTR2(exclude_hv, exclude_idle);
978 ret += PRINT_ATTR2(mmap, comm);
979 ret += PRINT_ATTR2(freq, inherit_stat);
980 ret += PRINT_ATTR2(enable_on_exec, task);
981 ret += PRINT_ATTR2(watermark, precise_ip);
982 ret += PRINT_ATTR2(mmap_data, sample_id_all);
983 ret += PRINT_ATTR2(exclude_host, exclude_guest);
984 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel,
985 "excl.callchain_user", exclude_callchain_user);
986
987 ret += PRINT_ATTR_U32(wakeup_events);
988 ret += PRINT_ATTR_U32(wakeup_watermark);
989 ret += PRINT_ATTR_X32(bp_type);
990 ret += PRINT_ATTR_X64(bp_addr);
991 ret += PRINT_ATTR_X64(config1);
992 ret += PRINT_ATTR_U64(bp_len);
993 ret += PRINT_ATTR_X64(config2);
994 ret += PRINT_ATTR_X64(branch_sample_type);
995 ret += PRINT_ATTR_X64(sample_regs_user);
996 ret += PRINT_ATTR_U32(sample_stack_user);
997
998 ret += fprintf(fp, "%.60s\n", graph_dotted_line);
999
1000 return ret;
1001}
1002
820static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 1003static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
821 struct thread_map *threads) 1004 struct thread_map *threads)
822{ 1005{
823 int cpu, thread; 1006 int cpu, thread;
824 unsigned long flags = 0; 1007 unsigned long flags = 0;
825 int pid = -1, err; 1008 int pid = -1, err;
1009 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
826 1010
827 if (evsel->fd == NULL && 1011 if (evsel->fd == NULL &&
828 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) 1012 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
@@ -834,12 +1018,17 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
834 } 1018 }
835 1019
836fallback_missing_features: 1020fallback_missing_features:
1021 if (perf_missing_features.mmap2)
1022 evsel->attr.mmap2 = 0;
837 if (perf_missing_features.exclude_guest) 1023 if (perf_missing_features.exclude_guest)
838 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; 1024 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
839retry_sample_id: 1025retry_sample_id:
840 if (perf_missing_features.sample_id_all) 1026 if (perf_missing_features.sample_id_all)
841 evsel->attr.sample_id_all = 0; 1027 evsel->attr.sample_id_all = 0;
842 1028
1029 if (verbose >= 2)
1030 perf_event_attr__fprintf(&evsel->attr, stderr);
1031
843 for (cpu = 0; cpu < cpus->nr; cpu++) { 1032 for (cpu = 0; cpu < cpus->nr; cpu++) {
844 1033
845 for (thread = 0; thread < threads->nr; thread++) { 1034 for (thread = 0; thread < threads->nr; thread++) {
@@ -849,6 +1038,9 @@ retry_sample_id:
849 pid = threads->map[thread]; 1038 pid = threads->map[thread];
850 1039
851 group_fd = get_group_fd(evsel, cpu, thread); 1040 group_fd = get_group_fd(evsel, cpu, thread);
1041retry_open:
1042 pr_debug2("perf_event_open: pid %d cpu %d group_fd %d flags %#lx\n",
1043 pid, cpus->map[cpu], group_fd, flags);
852 1044
853 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, 1045 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
854 pid, 1046 pid,
@@ -858,17 +1050,45 @@ retry_sample_id:
858 err = -errno; 1050 err = -errno;
859 goto try_fallback; 1051 goto try_fallback;
860 } 1052 }
1053 set_rlimit = NO_CHANGE;
861 } 1054 }
862 } 1055 }
863 1056
864 return 0; 1057 return 0;
865 1058
866try_fallback: 1059try_fallback:
1060 /*
1061 * perf stat needs between 5 and 22 fds per CPU. When we run out
1062 * of them try to increase the limits.
1063 */
1064 if (err == -EMFILE && set_rlimit < INCREASED_MAX) {
1065 struct rlimit l;
1066 int old_errno = errno;
1067
1068 if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
1069 if (set_rlimit == NO_CHANGE)
1070 l.rlim_cur = l.rlim_max;
1071 else {
1072 l.rlim_cur = l.rlim_max + 1000;
1073 l.rlim_max = l.rlim_cur;
1074 }
1075 if (setrlimit(RLIMIT_NOFILE, &l) == 0) {
1076 set_rlimit++;
1077 errno = old_errno;
1078 goto retry_open;
1079 }
1080 }
1081 errno = old_errno;
1082 }
1083
867 if (err != -EINVAL || cpu > 0 || thread > 0) 1084 if (err != -EINVAL || cpu > 0 || thread > 0)
868 goto out_close; 1085 goto out_close;
869 1086
870 if (!perf_missing_features.exclude_guest && 1087 if (!perf_missing_features.mmap2 && evsel->attr.mmap2) {
871 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { 1088 perf_missing_features.mmap2 = true;
1089 goto fallback_missing_features;
1090 } else if (!perf_missing_features.exclude_guest &&
1091 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
872 perf_missing_features.exclude_guest = true; 1092 perf_missing_features.exclude_guest = true;
873 goto fallback_missing_features; 1093 goto fallback_missing_features;
874 } else if (!perf_missing_features.sample_id_all) { 1094 } else if (!perf_missing_features.sample_id_all) {
@@ -951,6 +1171,11 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
951 array += ((event->header.size - 1171 array += ((event->header.size -
952 sizeof(event->header)) / sizeof(u64)) - 1; 1172 sizeof(event->header)) / sizeof(u64)) - 1;
953 1173
1174 if (type & PERF_SAMPLE_IDENTIFIER) {
1175 sample->id = *array;
1176 array--;
1177 }
1178
954 if (type & PERF_SAMPLE_CPU) { 1179 if (type & PERF_SAMPLE_CPU) {
955 u.val64 = *array; 1180 u.val64 = *array;
956 if (swapped) { 1181 if (swapped) {
@@ -994,24 +1219,30 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
994 return 0; 1219 return 0;
995} 1220}
996 1221
997static bool sample_overlap(const union perf_event *event, 1222static inline bool overflow(const void *endp, u16 max_size, const void *offset,
998 const void *offset, u64 size) 1223 u64 size)
999{ 1224{
1000 const void *base = event; 1225 return size > max_size || offset + size > endp;
1226}
1001 1227
1002 if (offset + size > base + event->header.size) 1228#define OVERFLOW_CHECK(offset, size, max_size) \
1003 return true; 1229 do { \
1230 if (overflow(endp, (max_size), (offset), (size))) \
1231 return -EFAULT; \
1232 } while (0)
1004 1233
1005 return false; 1234#define OVERFLOW_CHECK_u64(offset) \
1006} 1235 OVERFLOW_CHECK(offset, sizeof(u64), sizeof(u64))
1007 1236
1008int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, 1237int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1009 struct perf_sample *data) 1238 struct perf_sample *data)
1010{ 1239{
1011 u64 type = evsel->attr.sample_type; 1240 u64 type = evsel->attr.sample_type;
1012 u64 regs_user = evsel->attr.sample_regs_user;
1013 bool swapped = evsel->needs_swap; 1241 bool swapped = evsel->needs_swap;
1014 const u64 *array; 1242 const u64 *array;
1243 u16 max_size = event->header.size;
1244 const void *endp = (void *)event + max_size;
1245 u64 sz;
1015 1246
1016 /* 1247 /*
1017 * used for cross-endian analysis. See git commit 65014ab3 1248 * used for cross-endian analysis. See git commit 65014ab3
@@ -1033,11 +1264,22 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1033 1264
1034 array = event->sample.array; 1265 array = event->sample.array;
1035 1266
1267 /*
1268 * The evsel's sample_size is based on PERF_SAMPLE_MASK which includes
1269 * up to PERF_SAMPLE_PERIOD. After that overflow() must be used to
1270 * check the format does not go past the end of the event.
1271 */
1036 if (evsel->sample_size + sizeof(event->header) > event->header.size) 1272 if (evsel->sample_size + sizeof(event->header) > event->header.size)
1037 return -EFAULT; 1273 return -EFAULT;
1038 1274
1275 data->id = -1ULL;
1276 if (type & PERF_SAMPLE_IDENTIFIER) {
1277 data->id = *array;
1278 array++;
1279 }
1280
1039 if (type & PERF_SAMPLE_IP) { 1281 if (type & PERF_SAMPLE_IP) {
1040 data->ip = event->ip.ip; 1282 data->ip = *array;
1041 array++; 1283 array++;
1042 } 1284 }
1043 1285
@@ -1066,7 +1308,6 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1066 array++; 1308 array++;
1067 } 1309 }
1068 1310
1069 data->id = -1ULL;
1070 if (type & PERF_SAMPLE_ID) { 1311 if (type & PERF_SAMPLE_ID) {
1071 data->id = *array; 1312 data->id = *array;
1072 array++; 1313 array++;
@@ -1096,25 +1337,62 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1096 } 1337 }
1097 1338
1098 if (type & PERF_SAMPLE_READ) { 1339 if (type & PERF_SAMPLE_READ) {
1099 fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n"); 1340 u64 read_format = evsel->attr.read_format;
1100 return -1; 1341
1342 OVERFLOW_CHECK_u64(array);
1343 if (read_format & PERF_FORMAT_GROUP)
1344 data->read.group.nr = *array;
1345 else
1346 data->read.one.value = *array;
1347
1348 array++;
1349
1350 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
1351 OVERFLOW_CHECK_u64(array);
1352 data->read.time_enabled = *array;
1353 array++;
1354 }
1355
1356 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
1357 OVERFLOW_CHECK_u64(array);
1358 data->read.time_running = *array;
1359 array++;
1360 }
1361
1362 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
1363 if (read_format & PERF_FORMAT_GROUP) {
1364 const u64 max_group_nr = UINT64_MAX /
1365 sizeof(struct sample_read_value);
1366
1367 if (data->read.group.nr > max_group_nr)
1368 return -EFAULT;
1369 sz = data->read.group.nr *
1370 sizeof(struct sample_read_value);
1371 OVERFLOW_CHECK(array, sz, max_size);
1372 data->read.group.values =
1373 (struct sample_read_value *)array;
1374 array = (void *)array + sz;
1375 } else {
1376 OVERFLOW_CHECK_u64(array);
1377 data->read.one.id = *array;
1378 array++;
1379 }
1101 } 1380 }
1102 1381
1103 if (type & PERF_SAMPLE_CALLCHAIN) { 1382 if (type & PERF_SAMPLE_CALLCHAIN) {
1104 if (sample_overlap(event, array, sizeof(data->callchain->nr))) 1383 const u64 max_callchain_nr = UINT64_MAX / sizeof(u64);
1105 return -EFAULT;
1106
1107 data->callchain = (struct ip_callchain *)array;
1108 1384
1109 if (sample_overlap(event, array, data->callchain->nr)) 1385 OVERFLOW_CHECK_u64(array);
1386 data->callchain = (struct ip_callchain *)array++;
1387 if (data->callchain->nr > max_callchain_nr)
1110 return -EFAULT; 1388 return -EFAULT;
1111 1389 sz = data->callchain->nr * sizeof(u64);
1112 array += 1 + data->callchain->nr; 1390 OVERFLOW_CHECK(array, sz, max_size);
1391 array = (void *)array + sz;
1113 } 1392 }
1114 1393
1115 if (type & PERF_SAMPLE_RAW) { 1394 if (type & PERF_SAMPLE_RAW) {
1116 const u64 *pdata; 1395 OVERFLOW_CHECK_u64(array);
1117
1118 u.val64 = *array; 1396 u.val64 = *array;
1119 if (WARN_ONCE(swapped, 1397 if (WARN_ONCE(swapped,
1120 "Endianness of raw data not corrected!\n")) { 1398 "Endianness of raw data not corrected!\n")) {
@@ -1123,65 +1401,71 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1123 u.val32[0] = bswap_32(u.val32[0]); 1401 u.val32[0] = bswap_32(u.val32[0]);
1124 u.val32[1] = bswap_32(u.val32[1]); 1402 u.val32[1] = bswap_32(u.val32[1]);
1125 } 1403 }
1126
1127 if (sample_overlap(event, array, sizeof(u32)))
1128 return -EFAULT;
1129
1130 data->raw_size = u.val32[0]; 1404 data->raw_size = u.val32[0];
1131 pdata = (void *) array + sizeof(u32); 1405 array = (void *)array + sizeof(u32);
1132 1406
1133 if (sample_overlap(event, pdata, data->raw_size)) 1407 OVERFLOW_CHECK(array, data->raw_size, max_size);
1134 return -EFAULT; 1408 data->raw_data = (void *)array;
1135 1409 array = (void *)array + data->raw_size;
1136 data->raw_data = (void *) pdata;
1137
1138 array = (void *)array + data->raw_size + sizeof(u32);
1139 } 1410 }
1140 1411
1141 if (type & PERF_SAMPLE_BRANCH_STACK) { 1412 if (type & PERF_SAMPLE_BRANCH_STACK) {
1142 u64 sz; 1413 const u64 max_branch_nr = UINT64_MAX /
1414 sizeof(struct branch_entry);
1143 1415
1144 data->branch_stack = (struct branch_stack *)array; 1416 OVERFLOW_CHECK_u64(array);
1145 array++; /* nr */ 1417 data->branch_stack = (struct branch_stack *)array++;
1146 1418
1419 if (data->branch_stack->nr > max_branch_nr)
1420 return -EFAULT;
1147 sz = data->branch_stack->nr * sizeof(struct branch_entry); 1421 sz = data->branch_stack->nr * sizeof(struct branch_entry);
1148 sz /= sizeof(u64); 1422 OVERFLOW_CHECK(array, sz, max_size);
1149 array += sz; 1423 array = (void *)array + sz;
1150 } 1424 }
1151 1425
1152 if (type & PERF_SAMPLE_REGS_USER) { 1426 if (type & PERF_SAMPLE_REGS_USER) {
1153 /* First u64 tells us if we have any regs in sample. */ 1427 OVERFLOW_CHECK_u64(array);
1154 u64 avail = *array++; 1428 data->user_regs.abi = *array;
1429 array++;
1430
1431 if (data->user_regs.abi) {
1432 u64 regs_user = evsel->attr.sample_regs_user;
1155 1433
1156 if (avail) { 1434 sz = hweight_long(regs_user) * sizeof(u64);
1435 OVERFLOW_CHECK(array, sz, max_size);
1157 data->user_regs.regs = (u64 *)array; 1436 data->user_regs.regs = (u64 *)array;
1158 array += hweight_long(regs_user); 1437 array = (void *)array + sz;
1159 } 1438 }
1160 } 1439 }
1161 1440
1162 if (type & PERF_SAMPLE_STACK_USER) { 1441 if (type & PERF_SAMPLE_STACK_USER) {
1163 u64 size = *array++; 1442 OVERFLOW_CHECK_u64(array);
1443 sz = *array++;
1164 1444
1165 data->user_stack.offset = ((char *)(array - 1) 1445 data->user_stack.offset = ((char *)(array - 1)
1166 - (char *) event); 1446 - (char *) event);
1167 1447
1168 if (!size) { 1448 if (!sz) {
1169 data->user_stack.size = 0; 1449 data->user_stack.size = 0;
1170 } else { 1450 } else {
1451 OVERFLOW_CHECK(array, sz, max_size);
1171 data->user_stack.data = (char *)array; 1452 data->user_stack.data = (char *)array;
1172 array += size / sizeof(*array); 1453 array = (void *)array + sz;
1173 data->user_stack.size = *array; 1454 OVERFLOW_CHECK_u64(array);
1455 data->user_stack.size = *array++;
1174 } 1456 }
1175 } 1457 }
1176 1458
1177 data->weight = 0; 1459 data->weight = 0;
1178 if (type & PERF_SAMPLE_WEIGHT) { 1460 if (type & PERF_SAMPLE_WEIGHT) {
1461 OVERFLOW_CHECK_u64(array);
1179 data->weight = *array; 1462 data->weight = *array;
1180 array++; 1463 array++;
1181 } 1464 }
1182 1465
1183 data->data_src = PERF_MEM_DATA_SRC_NONE; 1466 data->data_src = PERF_MEM_DATA_SRC_NONE;
1184 if (type & PERF_SAMPLE_DATA_SRC) { 1467 if (type & PERF_SAMPLE_DATA_SRC) {
1468 OVERFLOW_CHECK_u64(array);
1185 data->data_src = *array; 1469 data->data_src = *array;
1186 array++; 1470 array++;
1187 } 1471 }
@@ -1189,12 +1473,105 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1189 return 0; 1473 return 0;
1190} 1474}
1191 1475
1476size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
1477 u64 sample_regs_user, u64 read_format)
1478{
1479 size_t sz, result = sizeof(struct sample_event);
1480
1481 if (type & PERF_SAMPLE_IDENTIFIER)
1482 result += sizeof(u64);
1483
1484 if (type & PERF_SAMPLE_IP)
1485 result += sizeof(u64);
1486
1487 if (type & PERF_SAMPLE_TID)
1488 result += sizeof(u64);
1489
1490 if (type & PERF_SAMPLE_TIME)
1491 result += sizeof(u64);
1492
1493 if (type & PERF_SAMPLE_ADDR)
1494 result += sizeof(u64);
1495
1496 if (type & PERF_SAMPLE_ID)
1497 result += sizeof(u64);
1498
1499 if (type & PERF_SAMPLE_STREAM_ID)
1500 result += sizeof(u64);
1501
1502 if (type & PERF_SAMPLE_CPU)
1503 result += sizeof(u64);
1504
1505 if (type & PERF_SAMPLE_PERIOD)
1506 result += sizeof(u64);
1507
1508 if (type & PERF_SAMPLE_READ) {
1509 result += sizeof(u64);
1510 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
1511 result += sizeof(u64);
1512 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
1513 result += sizeof(u64);
1514 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
1515 if (read_format & PERF_FORMAT_GROUP) {
1516 sz = sample->read.group.nr *
1517 sizeof(struct sample_read_value);
1518 result += sz;
1519 } else {
1520 result += sizeof(u64);
1521 }
1522 }
1523
1524 if (type & PERF_SAMPLE_CALLCHAIN) {
1525 sz = (sample->callchain->nr + 1) * sizeof(u64);
1526 result += sz;
1527 }
1528
1529 if (type & PERF_SAMPLE_RAW) {
1530 result += sizeof(u32);
1531 result += sample->raw_size;
1532 }
1533
1534 if (type & PERF_SAMPLE_BRANCH_STACK) {
1535 sz = sample->branch_stack->nr * sizeof(struct branch_entry);
1536 sz += sizeof(u64);
1537 result += sz;
1538 }
1539
1540 if (type & PERF_SAMPLE_REGS_USER) {
1541 if (sample->user_regs.abi) {
1542 result += sizeof(u64);
1543 sz = hweight_long(sample_regs_user) * sizeof(u64);
1544 result += sz;
1545 } else {
1546 result += sizeof(u64);
1547 }
1548 }
1549
1550 if (type & PERF_SAMPLE_STACK_USER) {
1551 sz = sample->user_stack.size;
1552 result += sizeof(u64);
1553 if (sz) {
1554 result += sz;
1555 result += sizeof(u64);
1556 }
1557 }
1558
1559 if (type & PERF_SAMPLE_WEIGHT)
1560 result += sizeof(u64);
1561
1562 if (type & PERF_SAMPLE_DATA_SRC)
1563 result += sizeof(u64);
1564
1565 return result;
1566}
1567
1192int perf_event__synthesize_sample(union perf_event *event, u64 type, 1568int perf_event__synthesize_sample(union perf_event *event, u64 type,
1569 u64 sample_regs_user, u64 read_format,
1193 const struct perf_sample *sample, 1570 const struct perf_sample *sample,
1194 bool swapped) 1571 bool swapped)
1195{ 1572{
1196 u64 *array; 1573 u64 *array;
1197 1574 size_t sz;
1198 /* 1575 /*
1199 * used for cross-endian analysis. See git commit 65014ab3 1576 * used for cross-endian analysis. See git commit 65014ab3
1200 * for why this goofiness is needed. 1577 * for why this goofiness is needed.
@@ -1203,8 +1580,13 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
1203 1580
1204 array = event->sample.array; 1581 array = event->sample.array;
1205 1582
1583 if (type & PERF_SAMPLE_IDENTIFIER) {
1584 *array = sample->id;
1585 array++;
1586 }
1587
1206 if (type & PERF_SAMPLE_IP) { 1588 if (type & PERF_SAMPLE_IP) {
1207 event->ip.ip = sample->ip; 1589 *array = sample->ip;
1208 array++; 1590 array++;
1209 } 1591 }
1210 1592
@@ -1262,6 +1644,97 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
1262 array++; 1644 array++;
1263 } 1645 }
1264 1646
1647 if (type & PERF_SAMPLE_READ) {
1648 if (read_format & PERF_FORMAT_GROUP)
1649 *array = sample->read.group.nr;
1650 else
1651 *array = sample->read.one.value;
1652 array++;
1653
1654 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
1655 *array = sample->read.time_enabled;
1656 array++;
1657 }
1658
1659 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
1660 *array = sample->read.time_running;
1661 array++;
1662 }
1663
1664 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
1665 if (read_format & PERF_FORMAT_GROUP) {
1666 sz = sample->read.group.nr *
1667 sizeof(struct sample_read_value);
1668 memcpy(array, sample->read.group.values, sz);
1669 array = (void *)array + sz;
1670 } else {
1671 *array = sample->read.one.id;
1672 array++;
1673 }
1674 }
1675
1676 if (type & PERF_SAMPLE_CALLCHAIN) {
1677 sz = (sample->callchain->nr + 1) * sizeof(u64);
1678 memcpy(array, sample->callchain, sz);
1679 array = (void *)array + sz;
1680 }
1681
1682 if (type & PERF_SAMPLE_RAW) {
1683 u.val32[0] = sample->raw_size;
1684 if (WARN_ONCE(swapped,
1685 "Endianness of raw data not corrected!\n")) {
1686 /*
1687 * Inverse of what is done in perf_evsel__parse_sample
1688 */
1689 u.val32[0] = bswap_32(u.val32[0]);
1690 u.val32[1] = bswap_32(u.val32[1]);
1691 u.val64 = bswap_64(u.val64);
1692 }
1693 *array = u.val64;
1694 array = (void *)array + sizeof(u32);
1695
1696 memcpy(array, sample->raw_data, sample->raw_size);
1697 array = (void *)array + sample->raw_size;
1698 }
1699
1700 if (type & PERF_SAMPLE_BRANCH_STACK) {
1701 sz = sample->branch_stack->nr * sizeof(struct branch_entry);
1702 sz += sizeof(u64);
1703 memcpy(array, sample->branch_stack, sz);
1704 array = (void *)array + sz;
1705 }
1706
1707 if (type & PERF_SAMPLE_REGS_USER) {
1708 if (sample->user_regs.abi) {
1709 *array++ = sample->user_regs.abi;
1710 sz = hweight_long(sample_regs_user) * sizeof(u64);
1711 memcpy(array, sample->user_regs.regs, sz);
1712 array = (void *)array + sz;
1713 } else {
1714 *array++ = 0;
1715 }
1716 }
1717
1718 if (type & PERF_SAMPLE_STACK_USER) {
1719 sz = sample->user_stack.size;
1720 *array++ = sz;
1721 if (sz) {
1722 memcpy(array, sample->user_stack.data, sz);
1723 array = (void *)array + sz;
1724 *array++ = sz;
1725 }
1726 }
1727
1728 if (type & PERF_SAMPLE_WEIGHT) {
1729 *array = sample->weight;
1730 array++;
1731 }
1732
1733 if (type & PERF_SAMPLE_DATA_SRC) {
1734 *array = sample->data_src;
1735 array++;
1736 }
1737
1265 return 0; 1738 return 0;
1266} 1739}
1267 1740
@@ -1391,6 +1864,7 @@ static int sample_type__fprintf(FILE *fp, bool *first, u64 value)
1391 bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), 1864 bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
1392 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), 1865 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
1393 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), 1866 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
1867 bit_name(IDENTIFIER),
1394 { .name = NULL, } 1868 { .name = NULL, }
1395 }; 1869 };
1396#undef bit_name 1870#undef bit_name
@@ -1458,6 +1932,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
1458 if_print(exclude_hv); 1932 if_print(exclude_hv);
1459 if_print(exclude_idle); 1933 if_print(exclude_idle);
1460 if_print(mmap); 1934 if_print(mmap);
1935 if_print(mmap2);
1461 if_print(comm); 1936 if_print(comm);
1462 if_print(freq); 1937 if_print(freq);
1463 if_print(inherit_stat); 1938 if_print(inherit_stat);
@@ -1482,7 +1957,7 @@ out:
1482bool perf_evsel__fallback(struct perf_evsel *evsel, int err, 1957bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
1483 char *msg, size_t msgsize) 1958 char *msg, size_t msgsize)
1484{ 1959{
1485 if ((err == ENOENT || err == ENXIO) && 1960 if ((err == ENOENT || err == ENXIO || err == ENODEV) &&
1486 evsel->attr.type == PERF_TYPE_HARDWARE && 1961 evsel->attr.type == PERF_TYPE_HARDWARE &&
1487 evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) { 1962 evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
1488 /* 1963 /*
@@ -1514,7 +1989,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel,
1514 switch (err) { 1989 switch (err) {
1515 case EPERM: 1990 case EPERM:
1516 case EACCES: 1991 case EACCES:
1517 return scnprintf(msg, size, "%s", 1992 return scnprintf(msg, size,
1518 "You may not have permission to collect %sstats.\n" 1993 "You may not have permission to collect %sstats.\n"
1519 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" 1994 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
1520 " -1 - Not paranoid at all\n" 1995 " -1 - Not paranoid at all\n"
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3f156ccc1acb..4a7bdc713bab 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -38,6 +38,9 @@ struct perf_sample_id {
38 struct hlist_node node; 38 struct hlist_node node;
39 u64 id; 39 u64 id;
40 struct perf_evsel *evsel; 40 struct perf_evsel *evsel;
41
42 /* Holds total ID period value for PERF_SAMPLE_READ processing. */
43 u64 period;
41}; 44};
42 45
43/** struct perf_evsel - event selector 46/** struct perf_evsel - event selector
@@ -45,6 +48,12 @@ struct perf_sample_id {
45 * @name - Can be set to retain the original event name passed by the user, 48 * @name - Can be set to retain the original event name passed by the user,
46 * so that when showing results in tools such as 'perf stat', we 49 * so that when showing results in tools such as 'perf stat', we
47 * show the name used, not some alias. 50 * show the name used, not some alias.
51 * @id_pos: the position of the event id (PERF_SAMPLE_ID or
52 * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of
53 * struct sample_event
54 * @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or
55 * PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all
56 * is used there is an id sample appended to non-sample events
48 */ 57 */
49struct perf_evsel { 58struct perf_evsel {
50 struct list_head node; 59 struct list_head node;
@@ -71,11 +80,14 @@ struct perf_evsel {
71 } handler; 80 } handler;
72 struct cpu_map *cpus; 81 struct cpu_map *cpus;
73 unsigned int sample_size; 82 unsigned int sample_size;
83 int id_pos;
84 int is_pos;
74 bool supported; 85 bool supported;
75 bool needs_swap; 86 bool needs_swap;
76 /* parse modifier helper */ 87 /* parse modifier helper */
77 int exclude_GH; 88 int exclude_GH;
78 int nr_members; 89 int nr_members;
90 int sample_read;
79 struct perf_evsel *leader; 91 struct perf_evsel *leader;
80 char *group_name; 92 char *group_name;
81}; 93};
@@ -100,6 +112,9 @@ void perf_evsel__delete(struct perf_evsel *evsel);
100void perf_evsel__config(struct perf_evsel *evsel, 112void perf_evsel__config(struct perf_evsel *evsel,
101 struct perf_record_opts *opts); 113 struct perf_record_opts *opts);
102 114
115int __perf_evsel__sample_size(u64 sample_type);
116void perf_evsel__calc_id_pos(struct perf_evsel *evsel);
117
103bool perf_evsel__is_cache_op_valid(u8 type, u8 op); 118bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
104 119
105#define PERF_EVSEL__MAX_ALIASES 8 120#define PERF_EVSEL__MAX_ALIASES 8
@@ -138,10 +153,12 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
138#define perf_evsel__reset_sample_bit(evsel, bit) \ 153#define perf_evsel__reset_sample_bit(evsel, bit) \
139 __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) 154 __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit)
140 155
141void perf_evsel__set_sample_id(struct perf_evsel *evsel); 156void perf_evsel__set_sample_id(struct perf_evsel *evsel,
157 bool use_sample_identifier);
142 158
143int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 159int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
144 const char *filter); 160 const char *filter);
161int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads);
145 162
146int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 163int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
147 struct cpu_map *cpus); 164 struct cpu_map *cpus);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 326068a593a5..ce69901176d8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -25,41 +25,9 @@
25 25
26static bool no_buildid_cache = false; 26static bool no_buildid_cache = false;
27 27
28static int trace_event_count;
29static struct perf_trace_event_type *trace_events;
30
31static u32 header_argc; 28static u32 header_argc;
32static const char **header_argv; 29static const char **header_argv;
33 30
34int perf_header__push_event(u64 id, const char *name)
35{
36 struct perf_trace_event_type *nevents;
37
38 if (strlen(name) > MAX_EVENT_NAME)
39 pr_warning("Event %s will be truncated\n", name);
40
41 nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events));
42 if (nevents == NULL)
43 return -ENOMEM;
44 trace_events = nevents;
45
46 memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type));
47 trace_events[trace_event_count].event_id = id;
48 strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1);
49 trace_event_count++;
50 return 0;
51}
52
53char *perf_header__find_event(u64 id)
54{
55 int i;
56 for (i = 0 ; i < trace_event_count; i++) {
57 if (trace_events[i].event_id == id)
58 return trace_events[i].name;
59 }
60 return NULL;
61}
62
63/* 31/*
64 * magic2 = "PERFILE2" 32 * magic2 = "PERFILE2"
65 * must be a numerical value to let the endianness 33 * must be a numerical value to let the endianness
@@ -231,9 +199,11 @@ static int write_buildid(char *name, size_t name_len, u8 *build_id,
231 return write_padded(fd, name, name_len + 1, len); 199 return write_padded(fd, name, name_len + 1, len);
232} 200}
233 201
234static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, 202static int __dsos__write_buildid_table(struct list_head *head,
235 u16 misc, int fd) 203 struct machine *machine,
204 pid_t pid, u16 misc, int fd)
236{ 205{
206 char nm[PATH_MAX];
237 struct dso *pos; 207 struct dso *pos;
238 208
239 dsos__for_each_with_build_id(pos, head) { 209 dsos__for_each_with_build_id(pos, head) {
@@ -247,6 +217,10 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
247 if (is_vdso_map(pos->short_name)) { 217 if (is_vdso_map(pos->short_name)) {
248 name = (char *) VDSO__MAP_NAME; 218 name = (char *) VDSO__MAP_NAME;
249 name_len = sizeof(VDSO__MAP_NAME) + 1; 219 name_len = sizeof(VDSO__MAP_NAME) + 1;
220 } else if (dso__is_kcore(pos)) {
221 machine__mmap_name(machine, nm, sizeof(nm));
222 name = nm;
223 name_len = strlen(nm) + 1;
250 } else { 224 } else {
251 name = pos->long_name; 225 name = pos->long_name;
252 name_len = pos->long_name_len + 1; 226 name_len = pos->long_name_len + 1;
@@ -272,10 +246,10 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
272 umisc = PERF_RECORD_MISC_GUEST_USER; 246 umisc = PERF_RECORD_MISC_GUEST_USER;
273 } 247 }
274 248
275 err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, 249 err = __dsos__write_buildid_table(&machine->kernel_dsos, machine,
276 kmisc, fd); 250 machine->pid, kmisc, fd);
277 if (err == 0) 251 if (err == 0)
278 err = __dsos__write_buildid_table(&machine->user_dsos, 252 err = __dsos__write_buildid_table(&machine->user_dsos, machine,
279 machine->pid, umisc, fd); 253 machine->pid, umisc, fd);
280 return err; 254 return err;
281} 255}
@@ -407,23 +381,31 @@ out_free:
407 return err; 381 return err;
408} 382}
409 383
410static int dso__cache_build_id(struct dso *dso, const char *debugdir) 384static int dso__cache_build_id(struct dso *dso, struct machine *machine,
385 const char *debugdir)
411{ 386{
412 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 387 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
413 bool is_vdso = is_vdso_map(dso->short_name); 388 bool is_vdso = is_vdso_map(dso->short_name);
389 char *name = dso->long_name;
390 char nm[PATH_MAX];
414 391
415 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), 392 if (dso__is_kcore(dso)) {
416 dso->long_name, debugdir, 393 is_kallsyms = true;
417 is_kallsyms, is_vdso); 394 machine__mmap_name(machine, nm, sizeof(nm));
395 name = nm;
396 }
397 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
398 debugdir, is_kallsyms, is_vdso);
418} 399}
419 400
420static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) 401static int __dsos__cache_build_ids(struct list_head *head,
402 struct machine *machine, const char *debugdir)
421{ 403{
422 struct dso *pos; 404 struct dso *pos;
423 int err = 0; 405 int err = 0;
424 406
425 dsos__for_each_with_build_id(pos, head) 407 dsos__for_each_with_build_id(pos, head)
426 if (dso__cache_build_id(pos, debugdir)) 408 if (dso__cache_build_id(pos, machine, debugdir))
427 err = -1; 409 err = -1;
428 410
429 return err; 411 return err;
@@ -431,8 +413,9 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
431 413
432static int machine__cache_build_ids(struct machine *machine, const char *debugdir) 414static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
433{ 415{
434 int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); 416 int ret = __dsos__cache_build_ids(&machine->kernel_dsos, machine,
435 ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); 417 debugdir);
418 ret |= __dsos__cache_build_ids(&machine->user_dsos, machine, debugdir);
436 return ret; 419 return ret;
437} 420}
438 421
@@ -748,18 +731,19 @@ static int build_cpu_topo(struct cpu_topo *tp, int cpu)
748 char filename[MAXPATHLEN]; 731 char filename[MAXPATHLEN];
749 char *buf = NULL, *p; 732 char *buf = NULL, *p;
750 size_t len = 0; 733 size_t len = 0;
734 ssize_t sret;
751 u32 i = 0; 735 u32 i = 0;
752 int ret = -1; 736 int ret = -1;
753 737
754 sprintf(filename, CORE_SIB_FMT, cpu); 738 sprintf(filename, CORE_SIB_FMT, cpu);
755 fp = fopen(filename, "r"); 739 fp = fopen(filename, "r");
756 if (!fp) 740 if (!fp)
757 return -1; 741 goto try_threads;
758
759 if (getline(&buf, &len, fp) <= 0)
760 goto done;
761 742
743 sret = getline(&buf, &len, fp);
762 fclose(fp); 744 fclose(fp);
745 if (sret <= 0)
746 goto try_threads;
763 747
764 p = strchr(buf, '\n'); 748 p = strchr(buf, '\n');
765 if (p) 749 if (p)
@@ -775,7 +759,9 @@ static int build_cpu_topo(struct cpu_topo *tp, int cpu)
775 buf = NULL; 759 buf = NULL;
776 len = 0; 760 len = 0;
777 } 761 }
762 ret = 0;
778 763
764try_threads:
779 sprintf(filename, THRD_SIB_FMT, cpu); 765 sprintf(filename, THRD_SIB_FMT, cpu);
780 fp = fopen(filename, "r"); 766 fp = fopen(filename, "r");
781 if (!fp) 767 if (!fp)
@@ -1380,6 +1366,9 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
1380 1366
1381 fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip); 1367 fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip);
1382 1368
1369 fprintf(fp, ", attr_mmap2 = %d", evsel->attr.mmap2);
1370 fprintf(fp, ", attr_mmap = %d", evsel->attr.mmap);
1371 fprintf(fp, ", attr_mmap_data = %d", evsel->attr.mmap_data);
1383 if (evsel->ids) { 1372 if (evsel->ids) {
1384 fprintf(fp, ", id = {"); 1373 fprintf(fp, ", id = {");
1385 for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) { 1374 for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) {
@@ -2257,7 +2246,7 @@ static int perf_header__adds_write(struct perf_header *header,
2257 2246
2258 sec_size = sizeof(*feat_sec) * nr_sections; 2247 sec_size = sizeof(*feat_sec) * nr_sections;
2259 2248
2260 sec_start = header->data_offset + header->data_size; 2249 sec_start = header->feat_offset;
2261 lseek(fd, sec_start + sec_size, SEEK_SET); 2250 lseek(fd, sec_start + sec_size, SEEK_SET);
2262 2251
2263 for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { 2252 for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
@@ -2303,32 +2292,22 @@ int perf_session__write_header(struct perf_session *session,
2303 struct perf_file_header f_header; 2292 struct perf_file_header f_header;
2304 struct perf_file_attr f_attr; 2293 struct perf_file_attr f_attr;
2305 struct perf_header *header = &session->header; 2294 struct perf_header *header = &session->header;
2306 struct perf_evsel *evsel, *pair = NULL; 2295 struct perf_evsel *evsel;
2296 u64 attr_offset;
2307 int err; 2297 int err;
2308 2298
2309 lseek(fd, sizeof(f_header), SEEK_SET); 2299 lseek(fd, sizeof(f_header), SEEK_SET);
2310 2300
2311 if (session->evlist != evlist)
2312 pair = perf_evlist__first(session->evlist);
2313
2314 list_for_each_entry(evsel, &evlist->entries, node) { 2301 list_for_each_entry(evsel, &evlist->entries, node) {
2315 evsel->id_offset = lseek(fd, 0, SEEK_CUR); 2302 evsel->id_offset = lseek(fd, 0, SEEK_CUR);
2316 err = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); 2303 err = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
2317 if (err < 0) { 2304 if (err < 0) {
2318out_err_write:
2319 pr_debug("failed to write perf header\n"); 2305 pr_debug("failed to write perf header\n");
2320 return err; 2306 return err;
2321 } 2307 }
2322 if (session->evlist != evlist) {
2323 err = do_write(fd, pair->id, pair->ids * sizeof(u64));
2324 if (err < 0)
2325 goto out_err_write;
2326 evsel->ids += pair->ids;
2327 pair = perf_evsel__next(pair);
2328 }
2329 } 2308 }
2330 2309
2331 header->attr_offset = lseek(fd, 0, SEEK_CUR); 2310 attr_offset = lseek(fd, 0, SEEK_CUR);
2332 2311
2333 list_for_each_entry(evsel, &evlist->entries, node) { 2312 list_for_each_entry(evsel, &evlist->entries, node) {
2334 f_attr = (struct perf_file_attr){ 2313 f_attr = (struct perf_file_attr){
@@ -2345,17 +2324,8 @@ out_err_write:
2345 } 2324 }
2346 } 2325 }
2347 2326
2348 header->event_offset = lseek(fd, 0, SEEK_CUR);
2349 header->event_size = trace_event_count * sizeof(struct perf_trace_event_type);
2350 if (trace_events) {
2351 err = do_write(fd, trace_events, header->event_size);
2352 if (err < 0) {
2353 pr_debug("failed to write perf header events\n");
2354 return err;
2355 }
2356 }
2357
2358 header->data_offset = lseek(fd, 0, SEEK_CUR); 2327 header->data_offset = lseek(fd, 0, SEEK_CUR);
2328 header->feat_offset = header->data_offset + header->data_size;
2359 2329
2360 if (at_exit) { 2330 if (at_exit) {
2361 err = perf_header__adds_write(header, evlist, fd); 2331 err = perf_header__adds_write(header, evlist, fd);
@@ -2368,17 +2338,14 @@ out_err_write:
2368 .size = sizeof(f_header), 2338 .size = sizeof(f_header),
2369 .attr_size = sizeof(f_attr), 2339 .attr_size = sizeof(f_attr),
2370 .attrs = { 2340 .attrs = {
2371 .offset = header->attr_offset, 2341 .offset = attr_offset,
2372 .size = evlist->nr_entries * sizeof(f_attr), 2342 .size = evlist->nr_entries * sizeof(f_attr),
2373 }, 2343 },
2374 .data = { 2344 .data = {
2375 .offset = header->data_offset, 2345 .offset = header->data_offset,
2376 .size = header->data_size, 2346 .size = header->data_size,
2377 }, 2347 },
2378 .event_types = { 2348 /* event_types is ignored, store zeros */
2379 .offset = header->event_offset,
2380 .size = header->event_size,
2381 },
2382 }; 2349 };
2383 2350
2384 memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); 2351 memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
@@ -2391,7 +2358,6 @@ out_err_write:
2391 } 2358 }
2392 lseek(fd, header->data_offset + header->data_size, SEEK_SET); 2359 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
2393 2360
2394 header->frozen = 1;
2395 return 0; 2361 return 0;
2396} 2362}
2397 2363
@@ -2429,7 +2395,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
2429 2395
2430 sec_size = sizeof(*feat_sec) * nr_sections; 2396 sec_size = sizeof(*feat_sec) * nr_sections;
2431 2397
2432 lseek(fd, header->data_offset + header->data_size, SEEK_SET); 2398 lseek(fd, header->feat_offset, SEEK_SET);
2433 2399
2434 err = perf_header__getbuffer64(header, fd, feat_sec, sec_size); 2400 err = perf_header__getbuffer64(header, fd, feat_sec, sec_size);
2435 if (err < 0) 2401 if (err < 0)
@@ -2535,6 +2501,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2535 /* check for legacy format */ 2501 /* check for legacy format */
2536 ret = memcmp(&magic, __perf_magic1, sizeof(magic)); 2502 ret = memcmp(&magic, __perf_magic1, sizeof(magic));
2537 if (ret == 0) { 2503 if (ret == 0) {
2504 ph->version = PERF_HEADER_VERSION_1;
2538 pr_debug("legacy perf.data format\n"); 2505 pr_debug("legacy perf.data format\n");
2539 if (is_pipe) 2506 if (is_pipe)
2540 return try_all_pipe_abis(hdr_sz, ph); 2507 return try_all_pipe_abis(hdr_sz, ph);
@@ -2556,6 +2523,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2556 return -1; 2523 return -1;
2557 2524
2558 ph->needs_swap = true; 2525 ph->needs_swap = true;
2526 ph->version = PERF_HEADER_VERSION_2;
2559 2527
2560 return 0; 2528 return 0;
2561} 2529}
@@ -2626,10 +2594,9 @@ int perf_file_header__read(struct perf_file_header *header,
2626 memcpy(&ph->adds_features, &header->adds_features, 2594 memcpy(&ph->adds_features, &header->adds_features,
2627 sizeof(ph->adds_features)); 2595 sizeof(ph->adds_features));
2628 2596
2629 ph->event_offset = header->event_types.offset;
2630 ph->event_size = header->event_types.size;
2631 ph->data_offset = header->data.offset; 2597 ph->data_offset = header->data.offset;
2632 ph->data_size = header->data.size; 2598 ph->data_size = header->data.size;
2599 ph->feat_offset = header->data.offset + header->data.size;
2633 return 0; 2600 return 0;
2634} 2601}
2635 2602
@@ -2678,19 +2645,17 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
2678 return 0; 2645 return 0;
2679} 2646}
2680 2647
2681static int perf_header__read_pipe(struct perf_session *session, int fd) 2648static int perf_header__read_pipe(struct perf_session *session)
2682{ 2649{
2683 struct perf_header *header = &session->header; 2650 struct perf_header *header = &session->header;
2684 struct perf_pipe_file_header f_header; 2651 struct perf_pipe_file_header f_header;
2685 2652
2686 if (perf_file_header__read_pipe(&f_header, header, fd, 2653 if (perf_file_header__read_pipe(&f_header, header, session->fd,
2687 session->repipe) < 0) { 2654 session->repipe) < 0) {
2688 pr_debug("incompatible file format\n"); 2655 pr_debug("incompatible file format\n");
2689 return -EINVAL; 2656 return -EINVAL;
2690 } 2657 }
2691 2658
2692 session->fd = fd;
2693
2694 return 0; 2659 return 0;
2695} 2660}
2696 2661
@@ -2784,20 +2749,21 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
2784 return 0; 2749 return 0;
2785} 2750}
2786 2751
2787int perf_session__read_header(struct perf_session *session, int fd) 2752int perf_session__read_header(struct perf_session *session)
2788{ 2753{
2789 struct perf_header *header = &session->header; 2754 struct perf_header *header = &session->header;
2790 struct perf_file_header f_header; 2755 struct perf_file_header f_header;
2791 struct perf_file_attr f_attr; 2756 struct perf_file_attr f_attr;
2792 u64 f_id; 2757 u64 f_id;
2793 int nr_attrs, nr_ids, i, j; 2758 int nr_attrs, nr_ids, i, j;
2759 int fd = session->fd;
2794 2760
2795 session->evlist = perf_evlist__new(); 2761 session->evlist = perf_evlist__new();
2796 if (session->evlist == NULL) 2762 if (session->evlist == NULL)
2797 return -ENOMEM; 2763 return -ENOMEM;
2798 2764
2799 if (session->fd_pipe) 2765 if (session->fd_pipe)
2800 return perf_header__read_pipe(session, fd); 2766 return perf_header__read_pipe(session);
2801 2767
2802 if (perf_file_header__read(&f_header, header, fd) < 0) 2768 if (perf_file_header__read(&f_header, header, fd) < 0)
2803 return -EINVAL; 2769 return -EINVAL;
@@ -2851,27 +2817,13 @@ int perf_session__read_header(struct perf_session *session, int fd)
2851 2817
2852 symbol_conf.nr_events = nr_attrs; 2818 symbol_conf.nr_events = nr_attrs;
2853 2819
2854 if (f_header.event_types.size) {
2855 lseek(fd, f_header.event_types.offset, SEEK_SET);
2856 trace_events = malloc(f_header.event_types.size);
2857 if (trace_events == NULL)
2858 return -ENOMEM;
2859 if (perf_header__getbuffer64(header, fd, trace_events,
2860 f_header.event_types.size))
2861 goto out_errno;
2862 trace_event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
2863 }
2864
2865 perf_header__process_sections(header, fd, &session->pevent, 2820 perf_header__process_sections(header, fd, &session->pevent,
2866 perf_file_section__process); 2821 perf_file_section__process);
2867 2822
2868 lseek(fd, header->data_offset, SEEK_SET);
2869
2870 if (perf_evlist__prepare_tracepoint_events(session->evlist, 2823 if (perf_evlist__prepare_tracepoint_events(session->evlist,
2871 session->pevent)) 2824 session->pevent))
2872 goto out_delete_evlist; 2825 goto out_delete_evlist;
2873 2826
2874 header->frozen = 1;
2875 return 0; 2827 return 0;
2876out_errno: 2828out_errno:
2877 return -errno; 2829 return -errno;
@@ -2935,7 +2887,8 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
2935 return err; 2887 return err;
2936} 2888}
2937 2889
2938int perf_event__process_attr(union perf_event *event, 2890int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
2891 union perf_event *event,
2939 struct perf_evlist **pevlist) 2892 struct perf_evlist **pevlist)
2940{ 2893{
2941 u32 i, ids, n_ids; 2894 u32 i, ids, n_ids;
@@ -2969,63 +2922,7 @@ int perf_event__process_attr(union perf_event *event,
2969 perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]); 2922 perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]);
2970 } 2923 }
2971 2924
2972 return 0; 2925 symbol_conf.nr_events = evlist->nr_entries;
2973}
2974
2975int perf_event__synthesize_event_type(struct perf_tool *tool,
2976 u64 event_id, char *name,
2977 perf_event__handler_t process,
2978 struct machine *machine)
2979{
2980 union perf_event ev;
2981 size_t size = 0;
2982 int err = 0;
2983
2984 memset(&ev, 0, sizeof(ev));
2985
2986 ev.event_type.event_type.event_id = event_id;
2987 memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME);
2988 strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
2989
2990 ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
2991 size = strlen(ev.event_type.event_type.name);
2992 size = PERF_ALIGN(size, sizeof(u64));
2993 ev.event_type.header.size = sizeof(ev.event_type) -
2994 (sizeof(ev.event_type.event_type.name) - size);
2995
2996 err = process(tool, &ev, NULL, machine);
2997
2998 return err;
2999}
3000
3001int perf_event__synthesize_event_types(struct perf_tool *tool,
3002 perf_event__handler_t process,
3003 struct machine *machine)
3004{
3005 struct perf_trace_event_type *type;
3006 int i, err = 0;
3007
3008 for (i = 0; i < trace_event_count; i++) {
3009 type = &trace_events[i];
3010
3011 err = perf_event__synthesize_event_type(tool, type->event_id,
3012 type->name, process,
3013 machine);
3014 if (err) {
3015 pr_debug("failed to create perf header event type\n");
3016 return err;
3017 }
3018 }
3019
3020 return err;
3021}
3022
3023int perf_event__process_event_type(struct perf_tool *tool __maybe_unused,
3024 union perf_event *event)
3025{
3026 if (perf_header__push_event(event->event_type.event_type.event_id,
3027 event->event_type.event_type.name) < 0)
3028 return -ENOMEM;
3029 2926
3030 return 0; 2927 return 0;
3031} 2928}
@@ -3076,7 +2973,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
3076 return aligned_size; 2973 return aligned_size;
3077} 2974}
3078 2975
3079int perf_event__process_tracing_data(union perf_event *event, 2976int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
2977 union perf_event *event,
3080 struct perf_session *session) 2978 struct perf_session *session)
3081{ 2979{
3082 ssize_t size_read, padding, size = event->tracing_data.size; 2980 ssize_t size_read, padding, size = event->tracing_data.size;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index c9fc55cada6d..307c9aed972e 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -34,6 +34,11 @@ enum {
34 HEADER_FEAT_BITS = 256, 34 HEADER_FEAT_BITS = 256,
35}; 35};
36 36
37enum perf_header_version {
38 PERF_HEADER_VERSION_1,
39 PERF_HEADER_VERSION_2,
40};
41
37struct perf_file_section { 42struct perf_file_section {
38 u64 offset; 43 u64 offset;
39 u64 size; 44 u64 size;
@@ -45,6 +50,7 @@ struct perf_file_header {
45 u64 attr_size; 50 u64 attr_size;
46 struct perf_file_section attrs; 51 struct perf_file_section attrs;
47 struct perf_file_section data; 52 struct perf_file_section data;
53 /* event_types is ignored */
48 struct perf_file_section event_types; 54 struct perf_file_section event_types;
49 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
50}; 56};
@@ -84,29 +90,24 @@ struct perf_session_env {
84}; 90};
85 91
86struct perf_header { 92struct perf_header {
87 int frozen; 93 enum perf_header_version version;
88 bool needs_swap; 94 bool needs_swap;
89 s64 attr_offset; 95 u64 data_offset;
90 u64 data_offset; 96 u64 data_size;
91 u64 data_size; 97 u64 feat_offset;
92 u64 event_offset;
93 u64 event_size;
94 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 98 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
95 struct perf_session_env env; 99 struct perf_session_env env;
96}; 100};
97 101
98struct perf_evlist; 102struct perf_evlist;
99struct perf_session; 103struct perf_session;
100 104
101int perf_session__read_header(struct perf_session *session, int fd); 105int perf_session__read_header(struct perf_session *session);
102int perf_session__write_header(struct perf_session *session, 106int perf_session__write_header(struct perf_session *session,
103 struct perf_evlist *evlist, 107 struct perf_evlist *evlist,
104 int fd, bool at_exit); 108 int fd, bool at_exit);
105int perf_header__write_pipe(int fd); 109int perf_header__write_pipe(int fd);
106 110
107int perf_header__push_event(u64 id, const char *name);
108char *perf_header__find_event(u64 id);
109
110void perf_header__set_feat(struct perf_header *header, int feat); 111void perf_header__set_feat(struct perf_header *header, int feat);
111void perf_header__clear_feat(struct perf_header *header, int feat); 112void perf_header__clear_feat(struct perf_header *header, int feat);
112bool perf_header__has_feat(const struct perf_header *header, int feat); 113bool perf_header__has_feat(const struct perf_header *header, int feat);
@@ -131,22 +132,14 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
131int perf_event__synthesize_attrs(struct perf_tool *tool, 132int perf_event__synthesize_attrs(struct perf_tool *tool,
132 struct perf_session *session, 133 struct perf_session *session,
133 perf_event__handler_t process); 134 perf_event__handler_t process);
134int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); 135int perf_event__process_attr(struct perf_tool *tool, union perf_event *event,
135 136 struct perf_evlist **pevlist);
136int perf_event__synthesize_event_type(struct perf_tool *tool,
137 u64 event_id, char *name,
138 perf_event__handler_t process,
139 struct machine *machine);
140int perf_event__synthesize_event_types(struct perf_tool *tool,
141 perf_event__handler_t process,
142 struct machine *machine);
143int perf_event__process_event_type(struct perf_tool *tool,
144 union perf_event *event);
145 137
146int perf_event__synthesize_tracing_data(struct perf_tool *tool, 138int perf_event__synthesize_tracing_data(struct perf_tool *tool,
147 int fd, struct perf_evlist *evlist, 139 int fd, struct perf_evlist *evlist,
148 perf_event__handler_t process); 140 perf_event__handler_t process);
149int perf_event__process_tracing_data(union perf_event *event, 141int perf_event__process_tracing_data(struct perf_tool *tool,
142 union perf_event *event,
150 struct perf_session *session); 143 struct perf_session *session);
151 144
152int perf_event__synthesize_build_id(struct perf_tool *tool, 145int perf_event__synthesize_build_id(struct perf_tool *tool,
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 6b32721f829a..9ff6cf3e9a99 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -24,7 +24,8 @@ enum hist_filter {
24struct callchain_param callchain_param = { 24struct callchain_param callchain_param = {
25 .mode = CHAIN_GRAPH_REL, 25 .mode = CHAIN_GRAPH_REL,
26 .min_percent = 0.5, 26 .min_percent = 0.5,
27 .order = ORDER_CALLEE 27 .order = ORDER_CALLEE,
28 .key = CCKEY_FUNCTION
28}; 29};
29 30
30u16 hists__col_len(struct hists *hists, enum hist_column col) 31u16 hists__col_len(struct hists *hists, enum hist_column col)
@@ -70,9 +71,17 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
70 int symlen; 71 int symlen;
71 u16 len; 72 u16 len;
72 73
73 if (h->ms.sym) 74 /*
74 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4); 75 * +4 accounts for '[x] ' priv level info
75 else { 76 * +2 accounts for 0x prefix on raw addresses
77 * +3 accounts for ' y ' symtab origin info
78 */
79 if (h->ms.sym) {
80 symlen = h->ms.sym->namelen + 4;
81 if (verbose)
82 symlen += BITS_PER_LONG / 4 + 2 + 3;
83 hists__new_col_len(hists, HISTC_SYMBOL, symlen);
84 } else {
76 symlen = unresolved_col_width + 4 + 2; 85 symlen = unresolved_col_width + 4 + 2;
77 hists__new_col_len(hists, HISTC_SYMBOL, symlen); 86 hists__new_col_len(hists, HISTC_SYMBOL, symlen);
78 hists__set_unres_dso_col_len(hists, HISTC_DSO); 87 hists__set_unres_dso_col_len(hists, HISTC_DSO);
@@ -91,12 +100,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
91 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); 100 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
92 101
93 if (h->branch_info) { 102 if (h->branch_info) {
94 /*
95 * +4 accounts for '[x] ' priv level info
96 * +2 account of 0x prefix on raw addresses
97 */
98 if (h->branch_info->from.sym) { 103 if (h->branch_info->from.sym) {
99 symlen = (int)h->branch_info->from.sym->namelen + 4; 104 symlen = (int)h->branch_info->from.sym->namelen + 4;
105 if (verbose)
106 symlen += BITS_PER_LONG / 4 + 2 + 3;
100 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen); 107 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
101 108
102 symlen = dso__name_len(h->branch_info->from.map->dso); 109 symlen = dso__name_len(h->branch_info->from.map->dso);
@@ -109,6 +116,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
109 116
110 if (h->branch_info->to.sym) { 117 if (h->branch_info->to.sym) {
111 symlen = (int)h->branch_info->to.sym->namelen + 4; 118 symlen = (int)h->branch_info->to.sym->namelen + 4;
119 if (verbose)
120 symlen += BITS_PER_LONG / 4 + 2 + 3;
112 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); 121 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
113 122
114 symlen = dso__name_len(h->branch_info->to.map->dso); 123 symlen = dso__name_len(h->branch_info->to.map->dso);
@@ -121,10 +130,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
121 } 130 }
122 131
123 if (h->mem_info) { 132 if (h->mem_info) {
124 /*
125 * +4 accounts for '[x] ' priv level info
126 * +2 account of 0x prefix on raw addresses
127 */
128 if (h->mem_info->daddr.sym) { 133 if (h->mem_info->daddr.sym) {
129 symlen = (int)h->mem_info->daddr.sym->namelen + 4 134 symlen = (int)h->mem_info->daddr.sym->namelen + 4
130 + unresolved_col_width + 2; 135 + unresolved_col_width + 2;
@@ -236,8 +241,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
236 return he->stat.period == 0; 241 return he->stat.period == 0;
237} 242}
238 243
239static void __hists__decay_entries(struct hists *hists, bool zap_user, 244void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
240 bool zap_kernel, bool threaded)
241{ 245{
242 struct rb_node *next = rb_first(&hists->entries); 246 struct rb_node *next = rb_first(&hists->entries);
243 struct hist_entry *n; 247 struct hist_entry *n;
@@ -256,7 +260,7 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
256 !n->used) { 260 !n->used) {
257 rb_erase(&n->rb_node, &hists->entries); 261 rb_erase(&n->rb_node, &hists->entries);
258 262
259 if (sort__need_collapse || threaded) 263 if (sort__need_collapse)
260 rb_erase(&n->rb_node_in, &hists->entries_collapsed); 264 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
261 265
262 hist_entry__free(n); 266 hist_entry__free(n);
@@ -265,17 +269,6 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
265 } 269 }
266} 270}
267 271
268void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
269{
270 return __hists__decay_entries(hists, zap_user, zap_kernel, false);
271}
272
273void hists__decay_entries_threaded(struct hists *hists,
274 bool zap_user, bool zap_kernel)
275{
276 return __hists__decay_entries(hists, zap_user, zap_kernel, true);
277}
278
279/* 272/*
280 * histogram, sorted on item, collects periods 273 * histogram, sorted on item, collects periods
281 */ 274 */
@@ -292,6 +285,20 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
292 he->ms.map->referenced = true; 285 he->ms.map->referenced = true;
293 286
294 if (he->branch_info) { 287 if (he->branch_info) {
288 /*
289 * This branch info is (a part of) allocated from
290 * machine__resolve_bstack() and will be freed after
291 * adding new entries. So we need to save a copy.
292 */
293 he->branch_info = malloc(sizeof(*he->branch_info));
294 if (he->branch_info == NULL) {
295 free(he);
296 return NULL;
297 }
298
299 memcpy(he->branch_info, template->branch_info,
300 sizeof(*he->branch_info));
301
295 if (he->branch_info->from.map) 302 if (he->branch_info->from.map)
296 he->branch_info->from.map->referenced = true; 303 he->branch_info->from.map->referenced = true;
297 if (he->branch_info->to.map) 304 if (he->branch_info->to.map)
@@ -341,8 +348,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
341 struct hist_entry *he; 348 struct hist_entry *he;
342 int cmp; 349 int cmp;
343 350
344 pthread_mutex_lock(&hists->lock);
345
346 p = &hists->entries_in->rb_node; 351 p = &hists->entries_in->rb_node;
347 352
348 while (*p != NULL) { 353 while (*p != NULL) {
@@ -360,6 +365,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
360 if (!cmp) { 365 if (!cmp) {
361 he_stat__add_period(&he->stat, period, weight); 366 he_stat__add_period(&he->stat, period, weight);
362 367
368 /*
369 * This mem info was allocated from machine__resolve_mem
370 * and will not be used anymore.
371 */
372 free(entry->mem_info);
373
363 /* If the map of an existing hist_entry has 374 /* If the map of an existing hist_entry has
364 * become out-of-date due to an exec() or 375 * become out-of-date due to an exec() or
365 * similar, update it. Otherwise we will 376 * similar, update it. Otherwise we will
@@ -382,14 +393,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
382 393
383 he = hist_entry__new(entry); 394 he = hist_entry__new(entry);
384 if (!he) 395 if (!he)
385 goto out_unlock; 396 return NULL;
386 397
387 rb_link_node(&he->rb_node_in, parent, p); 398 rb_link_node(&he->rb_node_in, parent, p);
388 rb_insert_color(&he->rb_node_in, hists->entries_in); 399 rb_insert_color(&he->rb_node_in, hists->entries_in);
389out: 400out:
390 hist_entry__add_cpumode_period(he, al->cpumode, period); 401 hist_entry__add_cpumode_period(he, al->cpumode, period);
391out_unlock:
392 pthread_mutex_unlock(&hists->lock);
393 return he; 402 return he;
394} 403}
395 404
@@ -589,19 +598,21 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
589 hists__filter_entry_by_symbol(hists, he); 598 hists__filter_entry_by_symbol(hists, he);
590} 599}
591 600
592static void __hists__collapse_resort(struct hists *hists, bool threaded) 601void hists__collapse_resort(struct hists *hists)
593{ 602{
594 struct rb_root *root; 603 struct rb_root *root;
595 struct rb_node *next; 604 struct rb_node *next;
596 struct hist_entry *n; 605 struct hist_entry *n;
597 606
598 if (!sort__need_collapse && !threaded) 607 if (!sort__need_collapse)
599 return; 608 return;
600 609
601 root = hists__get_rotate_entries_in(hists); 610 root = hists__get_rotate_entries_in(hists);
602 next = rb_first(root); 611 next = rb_first(root);
603 612
604 while (next) { 613 while (next) {
614 if (session_done())
615 break;
605 n = rb_entry(next, struct hist_entry, rb_node_in); 616 n = rb_entry(next, struct hist_entry, rb_node_in);
606 next = rb_next(&n->rb_node_in); 617 next = rb_next(&n->rb_node_in);
607 618
@@ -617,16 +628,6 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
617 } 628 }
618} 629}
619 630
620void hists__collapse_resort(struct hists *hists)
621{
622 return __hists__collapse_resort(hists, false);
623}
624
625void hists__collapse_resort_threaded(struct hists *hists)
626{
627 return __hists__collapse_resort(hists, true);
628}
629
630/* 631/*
631 * reverse the map, sort on period. 632 * reverse the map, sort on period.
632 */ 633 */
@@ -713,7 +714,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
713 rb_insert_color(&he->rb_node, entries); 714 rb_insert_color(&he->rb_node, entries);
714} 715}
715 716
716static void __hists__output_resort(struct hists *hists, bool threaded) 717void hists__output_resort(struct hists *hists)
717{ 718{
718 struct rb_root *root; 719 struct rb_root *root;
719 struct rb_node *next; 720 struct rb_node *next;
@@ -722,7 +723,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
722 723
723 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); 724 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
724 725
725 if (sort__need_collapse || threaded) 726 if (sort__need_collapse)
726 root = &hists->entries_collapsed; 727 root = &hists->entries_collapsed;
727 else 728 else
728 root = hists->entries_in; 729 root = hists->entries_in;
@@ -743,16 +744,6 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
743 } 744 }
744} 745}
745 746
746void hists__output_resort(struct hists *hists)
747{
748 return __hists__output_resort(hists, false);
749}
750
751void hists__output_resort_threaded(struct hists *hists)
752{
753 return __hists__output_resort(hists, true);
754}
755
756static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h, 747static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
757 enum hist_filter filter) 748 enum hist_filter filter)
758{ 749{
@@ -924,6 +915,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
924 rb_link_node(&he->rb_node_in, parent, p); 915 rb_link_node(&he->rb_node_in, parent, p);
925 rb_insert_color(&he->rb_node_in, root); 916 rb_insert_color(&he->rb_node_in, root);
926 hists__inc_nr_entries(hists, he); 917 hists__inc_nr_entries(hists, he);
918 he->dummy = true;
927 } 919 }
928out: 920out:
929 return he; 921 return he;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 14c2fe20aa62..1329b6b6ffe6 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -43,12 +43,12 @@ enum hist_column {
43 HISTC_COMM, 43 HISTC_COMM,
44 HISTC_PARENT, 44 HISTC_PARENT,
45 HISTC_CPU, 45 HISTC_CPU,
46 HISTC_SRCLINE,
46 HISTC_MISPREDICT, 47 HISTC_MISPREDICT,
47 HISTC_SYMBOL_FROM, 48 HISTC_SYMBOL_FROM,
48 HISTC_SYMBOL_TO, 49 HISTC_SYMBOL_TO,
49 HISTC_DSO_FROM, 50 HISTC_DSO_FROM,
50 HISTC_DSO_TO, 51 HISTC_DSO_TO,
51 HISTC_SRCLINE,
52 HISTC_LOCAL_WEIGHT, 52 HISTC_LOCAL_WEIGHT,
53 HISTC_GLOBAL_WEIGHT, 53 HISTC_GLOBAL_WEIGHT,
54 HISTC_MEM_DADDR_SYMBOL, 54 HISTC_MEM_DADDR_SYMBOL,
@@ -104,13 +104,9 @@ struct hist_entry *__hists__add_mem_entry(struct hists *self,
104 u64 weight); 104 u64 weight);
105 105
106void hists__output_resort(struct hists *self); 106void hists__output_resort(struct hists *self);
107void hists__output_resort_threaded(struct hists *hists);
108void hists__collapse_resort(struct hists *self); 107void hists__collapse_resort(struct hists *self);
109void hists__collapse_resort_threaded(struct hists *hists);
110 108
111void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); 109void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
112void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
113 bool zap_kernel);
114void hists__output_recalc_col_len(struct hists *hists, int max_rows); 110void hists__output_recalc_col_len(struct hists *hists, int max_rows);
115 111
116void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); 112void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
@@ -119,7 +115,7 @@ void events_stats__inc(struct events_stats *stats, u32 type);
119size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); 115size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
120 116
121size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, 117size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
122 int max_cols, FILE *fp); 118 int max_cols, float min_pcnt, FILE *fp);
123 119
124int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); 120int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
125int hist_entry__annotate(struct hist_entry *self, size_t privsize); 121int hist_entry__annotate(struct hist_entry *self, size_t privsize);
@@ -145,10 +141,12 @@ struct perf_hpp {
145}; 141};
146 142
147struct perf_hpp_fmt { 143struct perf_hpp_fmt {
148 int (*header)(struct perf_hpp *hpp); 144 int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
149 int (*width)(struct perf_hpp *hpp); 145 int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
150 int (*color)(struct perf_hpp *hpp, struct hist_entry *he); 146 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
151 int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); 147 struct hist_entry *he);
148 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
149 struct hist_entry *he);
152 150
153 struct list_head list; 151 struct list_head list;
154}; 152};
@@ -161,7 +159,7 @@ extern struct list_head perf_hpp__list;
161extern struct perf_hpp_fmt perf_hpp__format[]; 159extern struct perf_hpp_fmt perf_hpp__format[];
162 160
163enum { 161enum {
164 PERF_HPP__BASELINE, 162 /* Matches perf_hpp__format array. */
165 PERF_HPP__OVERHEAD, 163 PERF_HPP__OVERHEAD,
166 PERF_HPP__OVERHEAD_SYS, 164 PERF_HPP__OVERHEAD_SYS,
167 PERF_HPP__OVERHEAD_US, 165 PERF_HPP__OVERHEAD_US,
@@ -169,11 +167,6 @@ enum {
169 PERF_HPP__OVERHEAD_GUEST_US, 167 PERF_HPP__OVERHEAD_GUEST_US,
170 PERF_HPP__SAMPLES, 168 PERF_HPP__SAMPLES,
171 PERF_HPP__PERIOD, 169 PERF_HPP__PERIOD,
172 PERF_HPP__PERIOD_BASELINE,
173 PERF_HPP__DELTA,
174 PERF_HPP__RATIO,
175 PERF_HPP__WEIGHTED_DIFF,
176 PERF_HPP__FORMULA,
177 170
178 PERF_HPP__MAX_INDEX 171 PERF_HPP__MAX_INDEX
179}; 172};
@@ -181,8 +174,6 @@ enum {
181void perf_hpp__init(void); 174void perf_hpp__init(void);
182void perf_hpp__column_register(struct perf_hpp_fmt *format); 175void perf_hpp__column_register(struct perf_hpp_fmt *format);
183void perf_hpp__column_enable(unsigned col); 176void perf_hpp__column_enable(unsigned col);
184int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
185 bool color);
186 177
187struct perf_evlist; 178struct perf_evlist;
188 179
@@ -199,6 +190,7 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
199 190
200int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 191int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
201 struct hist_browser_timer *hbt, 192 struct hist_browser_timer *hbt,
193 float min_pcnt,
202 struct perf_session_env *env); 194 struct perf_session_env *env);
203int script_browse(const char *script_opt); 195int script_browse(const char *script_opt);
204#else 196#else
@@ -206,6 +198,7 @@ static inline
206int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, 198int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
207 const char *help __maybe_unused, 199 const char *help __maybe_unused,
208 struct hist_browser_timer *hbt __maybe_unused, 200 struct hist_browser_timer *hbt __maybe_unused,
201 float min_pcnt __maybe_unused,
209 struct perf_session_env *env __maybe_unused) 202 struct perf_session_env *env __maybe_unused)
210{ 203{
211 return 0; 204 return 0;
@@ -233,23 +226,18 @@ static inline int script_browse(const char *script_opt __maybe_unused)
233 226
234#ifdef GTK2_SUPPORT 227#ifdef GTK2_SUPPORT
235int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, 228int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
236 struct hist_browser_timer *hbt __maybe_unused); 229 struct hist_browser_timer *hbt __maybe_unused,
230 float min_pcnt);
237#else 231#else
238static inline 232static inline
239int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, 233int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
240 const char *help __maybe_unused, 234 const char *help __maybe_unused,
241 struct hist_browser_timer *hbt __maybe_unused) 235 struct hist_browser_timer *hbt __maybe_unused,
236 float min_pcnt __maybe_unused)
242{ 237{
243 return 0; 238 return 0;
244} 239}
245#endif 240#endif
246 241
247unsigned int hists__sort_list_width(struct hists *self); 242unsigned int hists__sort_list_width(struct hists *self);
248
249double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
250double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
251s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
252int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
253 char *buf, size_t size);
254double perf_diff__period_percent(struct hist_entry *he, u64 period);
255#endif /* __PERF_HIST_H */ 243#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
index 6f19c548ecc0..97a800738226 100644
--- a/tools/perf/util/include/linux/string.h
+++ b/tools/perf/util/include/linux/string.h
@@ -1,3 +1,4 @@
1#include <string.h> 1#include <string.h>
2 2
3void *memdup(const void *src, size_t len); 3void *memdup(const void *src, size_t len);
4int str_append(char **s, int *len, const char *a);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index b2ecad6ec46b..6188d2876a71 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -25,12 +25,15 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
25 machine->kmaps.machine = machine; 25 machine->kmaps.machine = machine;
26 machine->pid = pid; 26 machine->pid = pid;
27 27
28 machine->symbol_filter = NULL;
29
28 machine->root_dir = strdup(root_dir); 30 machine->root_dir = strdup(root_dir);
29 if (machine->root_dir == NULL) 31 if (machine->root_dir == NULL)
30 return -ENOMEM; 32 return -ENOMEM;
31 33
32 if (pid != HOST_KERNEL_ID) { 34 if (pid != HOST_KERNEL_ID) {
33 struct thread *thread = machine__findnew_thread(machine, pid); 35 struct thread *thread = machine__findnew_thread(machine, 0,
36 pid);
34 char comm[64]; 37 char comm[64];
35 38
36 if (thread == NULL) 39 if (thread == NULL)
@@ -95,6 +98,7 @@ void machines__init(struct machines *machines)
95{ 98{
96 machine__init(&machines->host, "", HOST_KERNEL_ID); 99 machine__init(&machines->host, "", HOST_KERNEL_ID);
97 machines->guests = RB_ROOT; 100 machines->guests = RB_ROOT;
101 machines->symbol_filter = NULL;
98} 102}
99 103
100void machines__exit(struct machines *machines) 104void machines__exit(struct machines *machines)
@@ -118,6 +122,8 @@ struct machine *machines__add(struct machines *machines, pid_t pid,
118 return NULL; 122 return NULL;
119 } 123 }
120 124
125 machine->symbol_filter = machines->symbol_filter;
126
121 while (*p != NULL) { 127 while (*p != NULL) {
122 parent = *p; 128 parent = *p;
123 pos = rb_entry(parent, struct machine, rb_node); 129 pos = rb_entry(parent, struct machine, rb_node);
@@ -133,6 +139,21 @@ struct machine *machines__add(struct machines *machines, pid_t pid,
133 return machine; 139 return machine;
134} 140}
135 141
142void machines__set_symbol_filter(struct machines *machines,
143 symbol_filter_t symbol_filter)
144{
145 struct rb_node *nd;
146
147 machines->symbol_filter = symbol_filter;
148 machines->host.symbol_filter = symbol_filter;
149
150 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
151 struct machine *machine = rb_entry(nd, struct machine, rb_node);
152
153 machine->symbol_filter = symbol_filter;
154 }
155}
156
136struct machine *machines__find(struct machines *machines, pid_t pid) 157struct machine *machines__find(struct machines *machines, pid_t pid)
137{ 158{
138 struct rb_node **p = &machines->guests.rb_node; 159 struct rb_node **p = &machines->guests.rb_node;
@@ -233,7 +254,8 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
233 return; 254 return;
234} 255}
235 256
236static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, 257static struct thread *__machine__findnew_thread(struct machine *machine,
258 pid_t pid, pid_t tid,
237 bool create) 259 bool create)
238{ 260{
239 struct rb_node **p = &machine->threads.rb_node; 261 struct rb_node **p = &machine->threads.rb_node;
@@ -241,23 +263,28 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
241 struct thread *th; 263 struct thread *th;
242 264
243 /* 265 /*
244 * Font-end cache - PID lookups come in blocks, 266 * Front-end cache - TID lookups come in blocks,
245 * so most of the time we dont have to look up 267 * so most of the time we dont have to look up
246 * the full rbtree: 268 * the full rbtree:
247 */ 269 */
248 if (machine->last_match && machine->last_match->pid == pid) 270 if (machine->last_match && machine->last_match->tid == tid) {
271 if (pid && pid != machine->last_match->pid_)
272 machine->last_match->pid_ = pid;
249 return machine->last_match; 273 return machine->last_match;
274 }
250 275
251 while (*p != NULL) { 276 while (*p != NULL) {
252 parent = *p; 277 parent = *p;
253 th = rb_entry(parent, struct thread, rb_node); 278 th = rb_entry(parent, struct thread, rb_node);
254 279
255 if (th->pid == pid) { 280 if (th->tid == tid) {
256 machine->last_match = th; 281 machine->last_match = th;
282 if (pid && pid != th->pid_)
283 th->pid_ = pid;
257 return th; 284 return th;
258 } 285 }
259 286
260 if (pid < th->pid) 287 if (tid < th->tid)
261 p = &(*p)->rb_left; 288 p = &(*p)->rb_left;
262 else 289 else
263 p = &(*p)->rb_right; 290 p = &(*p)->rb_right;
@@ -266,7 +293,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
266 if (!create) 293 if (!create)
267 return NULL; 294 return NULL;
268 295
269 th = thread__new(pid); 296 th = thread__new(pid, tid);
270 if (th != NULL) { 297 if (th != NULL) {
271 rb_link_node(&th->rb_node, parent, p); 298 rb_link_node(&th->rb_node, parent, p);
272 rb_insert_color(&th->rb_node, &machine->threads); 299 rb_insert_color(&th->rb_node, &machine->threads);
@@ -276,19 +303,22 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
276 return th; 303 return th;
277} 304}
278 305
279struct thread *machine__findnew_thread(struct machine *machine, pid_t pid) 306struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
307 pid_t tid)
280{ 308{
281 return __machine__findnew_thread(machine, pid, true); 309 return __machine__findnew_thread(machine, pid, tid, true);
282} 310}
283 311
284struct thread *machine__find_thread(struct machine *machine, pid_t pid) 312struct thread *machine__find_thread(struct machine *machine, pid_t tid)
285{ 313{
286 return __machine__findnew_thread(machine, pid, false); 314 return __machine__findnew_thread(machine, 0, tid, false);
287} 315}
288 316
289int machine__process_comm_event(struct machine *machine, union perf_event *event) 317int machine__process_comm_event(struct machine *machine, union perf_event *event)
290{ 318{
291 struct thread *thread = machine__findnew_thread(machine, event->comm.tid); 319 struct thread *thread = machine__findnew_thread(machine,
320 event->comm.pid,
321 event->comm.tid);
292 322
293 if (dump_trace) 323 if (dump_trace)
294 perf_event__fprintf_comm(event, stdout); 324 perf_event__fprintf_comm(event, stdout);
@@ -628,10 +658,8 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
628 struct map *map = machine->vmlinux_maps[type]; 658 struct map *map = machine->vmlinux_maps[type];
629 int ret = dso__load_vmlinux_path(map->dso, map, filter); 659 int ret = dso__load_vmlinux_path(map->dso, map, filter);
630 660
631 if (ret > 0) { 661 if (ret > 0)
632 dso__set_loaded(map->dso, type); 662 dso__set_loaded(map->dso, type);
633 map__reloc_vmlinux(map);
634 }
635 663
636 return ret; 664 return ret;
637} 665}
@@ -764,7 +792,7 @@ static int machine__create_modules(struct machine *machine)
764 modules = path; 792 modules = path;
765 } 793 }
766 794
767 if (symbol__restricted_filename(path, "/proc/modules")) 795 if (symbol__restricted_filename(modules, "/proc/modules"))
768 return -1; 796 return -1;
769 797
770 file = fopen(modules, "r"); 798 file = fopen(modules, "r");
@@ -808,7 +836,10 @@ static int machine__create_modules(struct machine *machine)
808 free(line); 836 free(line);
809 fclose(file); 837 fclose(file);
810 838
811 return machine__set_modules_path(machine); 839 if (machine__set_modules_path(machine) < 0) {
840 pr_debug("Problems setting modules path maps, continuing anyway...\n");
841 }
842 return 0;
812 843
813out_delete_line: 844out_delete_line:
814 free(line); 845 free(line);
@@ -858,6 +889,18 @@ static void machine__set_kernel_mmap_len(struct machine *machine,
858 } 889 }
859} 890}
860 891
892static bool machine__uses_kcore(struct machine *machine)
893{
894 struct dso *dso;
895
896 list_for_each_entry(dso, &machine->kernel_dsos, node) {
897 if (dso__is_kcore(dso))
898 return true;
899 }
900
901 return false;
902}
903
861static int machine__process_kernel_mmap_event(struct machine *machine, 904static int machine__process_kernel_mmap_event(struct machine *machine,
862 union perf_event *event) 905 union perf_event *event)
863{ 906{
@@ -866,6 +909,10 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
866 enum dso_kernel_type kernel_type; 909 enum dso_kernel_type kernel_type;
867 bool is_kernel_mmap; 910 bool is_kernel_mmap;
868 911
912 /* If we have maps from kcore then we do not need or want any others */
913 if (machine__uses_kcore(machine))
914 return 0;
915
869 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); 916 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
870 if (machine__is_host(machine)) 917 if (machine__is_host(machine))
871 kernel_type = DSO_TYPE_KERNEL; 918 kernel_type = DSO_TYPE_KERNEL;
@@ -950,6 +997,54 @@ out_problem:
950 return -1; 997 return -1;
951} 998}
952 999
1000int machine__process_mmap2_event(struct machine *machine,
1001 union perf_event *event)
1002{
1003 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1004 struct thread *thread;
1005 struct map *map;
1006 enum map_type type;
1007 int ret = 0;
1008
1009 if (dump_trace)
1010 perf_event__fprintf_mmap2(event, stdout);
1011
1012 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
1013 cpumode == PERF_RECORD_MISC_KERNEL) {
1014 ret = machine__process_kernel_mmap_event(machine, event);
1015 if (ret < 0)
1016 goto out_problem;
1017 return 0;
1018 }
1019
1020 thread = machine__findnew_thread(machine, event->mmap2.pid,
1021 event->mmap2.pid);
1022 if (thread == NULL)
1023 goto out_problem;
1024
1025 if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
1026 type = MAP__VARIABLE;
1027 else
1028 type = MAP__FUNCTION;
1029
1030 map = map__new(&machine->user_dsos, event->mmap2.start,
1031 event->mmap2.len, event->mmap2.pgoff,
1032 event->mmap2.pid, event->mmap2.maj,
1033 event->mmap2.min, event->mmap2.ino,
1034 event->mmap2.ino_generation,
1035 event->mmap2.filename, type);
1036
1037 if (map == NULL)
1038 goto out_problem;
1039
1040 thread__insert_map(thread, map);
1041 return 0;
1042
1043out_problem:
1044 dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n");
1045 return 0;
1046}
1047
953int machine__process_mmap_event(struct machine *machine, union perf_event *event) 1048int machine__process_mmap_event(struct machine *machine, union perf_event *event)
954{ 1049{
955 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1050 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
@@ -969,7 +1064,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
969 return 0; 1064 return 0;
970 } 1065 }
971 1066
972 thread = machine__findnew_thread(machine, event->mmap.pid); 1067 thread = machine__findnew_thread(machine, event->mmap.pid,
1068 event->mmap.pid);
973 if (thread == NULL) 1069 if (thread == NULL)
974 goto out_problem; 1070 goto out_problem;
975 1071
@@ -980,7 +1076,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
980 1076
981 map = map__new(&machine->user_dsos, event->mmap.start, 1077 map = map__new(&machine->user_dsos, event->mmap.start,
982 event->mmap.len, event->mmap.pgoff, 1078 event->mmap.len, event->mmap.pgoff,
983 event->mmap.pid, event->mmap.filename, 1079 event->mmap.pid, 0, 0, 0, 0,
1080 event->mmap.filename,
984 type); 1081 type);
985 1082
986 if (map == NULL) 1083 if (map == NULL)
@@ -994,11 +1091,30 @@ out_problem:
994 return 0; 1091 return 0;
995} 1092}
996 1093
1094static void machine__remove_thread(struct machine *machine, struct thread *th)
1095{
1096 machine->last_match = NULL;
1097 rb_erase(&th->rb_node, &machine->threads);
1098 /*
1099 * We may have references to this thread, for instance in some hist_entry
1100 * instances, so just move them to a separate list.
1101 */
1102 list_add_tail(&th->node, &machine->dead_threads);
1103}
1104
997int machine__process_fork_event(struct machine *machine, union perf_event *event) 1105int machine__process_fork_event(struct machine *machine, union perf_event *event)
998{ 1106{
999 struct thread *thread = machine__findnew_thread(machine, event->fork.tid); 1107 struct thread *thread = machine__find_thread(machine, event->fork.tid);
1000 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); 1108 struct thread *parent = machine__findnew_thread(machine,
1109 event->fork.ppid,
1110 event->fork.ptid);
1001 1111
1112 /* if a thread currently exists for the thread id remove it */
1113 if (thread != NULL)
1114 machine__remove_thread(machine, thread);
1115
1116 thread = machine__findnew_thread(machine, event->fork.pid,
1117 event->fork.tid);
1002 if (dump_trace) 1118 if (dump_trace)
1003 perf_event__fprintf_task(event, stdout); 1119 perf_event__fprintf_task(event, stdout);
1004 1120
@@ -1011,18 +1127,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1011 return 0; 1127 return 0;
1012} 1128}
1013 1129
1014static void machine__remove_thread(struct machine *machine, struct thread *th) 1130int machine__process_exit_event(struct machine *machine __maybe_unused,
1015{ 1131 union perf_event *event)
1016 machine->last_match = NULL;
1017 rb_erase(&th->rb_node, &machine->threads);
1018 /*
1019 * We may have references to this thread, for instance in some hist_entry
1020 * instances, so just move them to a separate list.
1021 */
1022 list_add_tail(&th->node, &machine->dead_threads);
1023}
1024
1025int machine__process_exit_event(struct machine *machine, union perf_event *event)
1026{ 1132{
1027 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1133 struct thread *thread = machine__find_thread(machine, event->fork.tid);
1028 1134
@@ -1030,7 +1136,7 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event
1030 perf_event__fprintf_task(event, stdout); 1136 perf_event__fprintf_task(event, stdout);
1031 1137
1032 if (thread != NULL) 1138 if (thread != NULL)
1033 machine__remove_thread(machine, thread); 1139 thread__exited(thread);
1034 1140
1035 return 0; 1141 return 0;
1036} 1142}
@@ -1044,6 +1150,8 @@ int machine__process_event(struct machine *machine, union perf_event *event)
1044 ret = machine__process_comm_event(machine, event); break; 1150 ret = machine__process_comm_event(machine, event); break;
1045 case PERF_RECORD_MMAP: 1151 case PERF_RECORD_MMAP:
1046 ret = machine__process_mmap_event(machine, event); break; 1152 ret = machine__process_mmap_event(machine, event); break;
1153 case PERF_RECORD_MMAP2:
1154 ret = machine__process_mmap2_event(machine, event); break;
1047 case PERF_RECORD_FORK: 1155 case PERF_RECORD_FORK:
1048 ret = machine__process_fork_event(machine, event); break; 1156 ret = machine__process_fork_event(machine, event); break;
1049 case PERF_RECORD_EXIT: 1157 case PERF_RECORD_EXIT:
@@ -1058,11 +1166,10 @@ int machine__process_event(struct machine *machine, union perf_event *event)
1058 return ret; 1166 return ret;
1059} 1167}
1060 1168
1061static bool symbol__match_parent_regex(struct symbol *sym) 1169static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
1062{ 1170{
1063 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 1171 if (sym->name && !regexec(regex, sym->name, 0, NULL, 0))
1064 return 1; 1172 return 1;
1065
1066 return 0; 1173 return 0;
1067} 1174}
1068 1175
@@ -1094,7 +1201,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread,
1094 * or else, the symbol is unknown 1201 * or else, the symbol is unknown
1095 */ 1202 */
1096 thread__find_addr_location(thread, machine, m, MAP__FUNCTION, 1203 thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
1097 ip, &al, NULL); 1204 ip, &al);
1098 if (al.sym) 1205 if (al.sym)
1099 goto found; 1206 goto found;
1100 } 1207 }
@@ -1112,8 +1219,8 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread,
1112 1219
1113 memset(&al, 0, sizeof(al)); 1220 memset(&al, 0, sizeof(al));
1114 1221
1115 thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al, 1222 thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr,
1116 NULL); 1223 &al);
1117 ams->addr = addr; 1224 ams->addr = addr;
1118 ams->al_addr = al.addr; 1225 ams->al_addr = al.addr;
1119 ams->sym = al.sym; 1226 ams->sym = al.sym;
@@ -1159,8 +1266,8 @@ struct branch_info *machine__resolve_bstack(struct machine *machine,
1159static int machine__resolve_callchain_sample(struct machine *machine, 1266static int machine__resolve_callchain_sample(struct machine *machine,
1160 struct thread *thread, 1267 struct thread *thread,
1161 struct ip_callchain *chain, 1268 struct ip_callchain *chain,
1162 struct symbol **parent) 1269 struct symbol **parent,
1163 1270 struct addr_location *root_al)
1164{ 1271{
1165 u8 cpumode = PERF_RECORD_MISC_USER; 1272 u8 cpumode = PERF_RECORD_MISC_USER;
1166 unsigned int i; 1273 unsigned int i;
@@ -1208,11 +1315,18 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1208 1315
1209 al.filtered = false; 1316 al.filtered = false;
1210 thread__find_addr_location(thread, machine, cpumode, 1317 thread__find_addr_location(thread, machine, cpumode,
1211 MAP__FUNCTION, ip, &al, NULL); 1318 MAP__FUNCTION, ip, &al);
1212 if (al.sym != NULL) { 1319 if (al.sym != NULL) {
1213 if (sort__has_parent && !*parent && 1320 if (sort__has_parent && !*parent &&
1214 symbol__match_parent_regex(al.sym)) 1321 symbol__match_regex(al.sym, &parent_regex))
1215 *parent = al.sym; 1322 *parent = al.sym;
1323 else if (have_ignore_callees && root_al &&
1324 symbol__match_regex(al.sym, &ignore_callees_regex)) {
1325 /* Treat this symbol as the root,
1326 forgetting its callees. */
1327 *root_al = al;
1328 callchain_cursor_reset(&callchain_cursor);
1329 }
1216 if (!symbol_conf.use_callchain) 1330 if (!symbol_conf.use_callchain)
1217 break; 1331 break;
1218 } 1332 }
@@ -1237,15 +1351,13 @@ int machine__resolve_callchain(struct machine *machine,
1237 struct perf_evsel *evsel, 1351 struct perf_evsel *evsel,
1238 struct thread *thread, 1352 struct thread *thread,
1239 struct perf_sample *sample, 1353 struct perf_sample *sample,
1240 struct symbol **parent) 1354 struct symbol **parent,
1241 1355 struct addr_location *root_al)
1242{ 1356{
1243 int ret; 1357 int ret;
1244 1358
1245 callchain_cursor_reset(&callchain_cursor);
1246
1247 ret = machine__resolve_callchain_sample(machine, thread, 1359 ret = machine__resolve_callchain_sample(machine, thread,
1248 sample->callchain, parent); 1360 sample->callchain, parent, root_al);
1249 if (ret) 1361 if (ret)
1250 return ret; 1362 return ret;
1251 1363
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 77940680f1fc..58a6be1fc739 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -5,6 +5,7 @@
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include "map.h" 6#include "map.h"
7 7
8struct addr_location;
8struct branch_stack; 9struct branch_stack;
9struct perf_evsel; 10struct perf_evsel;
10struct perf_sample; 11struct perf_sample;
@@ -28,6 +29,7 @@ struct machine {
28 struct list_head kernel_dsos; 29 struct list_head kernel_dsos;
29 struct map_groups kmaps; 30 struct map_groups kmaps;
30 struct map *vmlinux_maps[MAP__NR_TYPES]; 31 struct map *vmlinux_maps[MAP__NR_TYPES];
32 symbol_filter_t symbol_filter;
31}; 33};
32 34
33static inline 35static inline
@@ -36,13 +38,14 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
36 return machine->vmlinux_maps[type]; 38 return machine->vmlinux_maps[type];
37} 39}
38 40
39struct thread *machine__find_thread(struct machine *machine, pid_t pid); 41struct thread *machine__find_thread(struct machine *machine, pid_t tid);
40 42
41int machine__process_comm_event(struct machine *machine, union perf_event *event); 43int machine__process_comm_event(struct machine *machine, union perf_event *event);
42int machine__process_exit_event(struct machine *machine, union perf_event *event); 44int machine__process_exit_event(struct machine *machine, union perf_event *event);
43int machine__process_fork_event(struct machine *machine, union perf_event *event); 45int machine__process_fork_event(struct machine *machine, union perf_event *event);
44int machine__process_lost_event(struct machine *machine, union perf_event *event); 46int machine__process_lost_event(struct machine *machine, union perf_event *event);
45int machine__process_mmap_event(struct machine *machine, union perf_event *event); 47int machine__process_mmap_event(struct machine *machine, union perf_event *event);
48int machine__process_mmap2_event(struct machine *machine, union perf_event *event);
46int machine__process_event(struct machine *machine, union perf_event *event); 49int machine__process_event(struct machine *machine, union perf_event *event);
47 50
48typedef void (*machine__process_t)(struct machine *machine, void *data); 51typedef void (*machine__process_t)(struct machine *machine, void *data);
@@ -50,6 +53,7 @@ typedef void (*machine__process_t)(struct machine *machine, void *data);
50struct machines { 53struct machines {
51 struct machine host; 54 struct machine host;
52 struct rb_root guests; 55 struct rb_root guests;
56 symbol_filter_t symbol_filter;
53}; 57};
54 58
55void machines__init(struct machines *machines); 59void machines__init(struct machines *machines);
@@ -67,6 +71,9 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid);
67void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size); 71void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
68char *machine__mmap_name(struct machine *machine, char *bf, size_t size); 72char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
69 73
74void machines__set_symbol_filter(struct machines *machines,
75 symbol_filter_t symbol_filter);
76
70int machine__init(struct machine *machine, const char *root_dir, pid_t pid); 77int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
71void machine__exit(struct machine *machine); 78void machine__exit(struct machine *machine);
72void machine__delete_dead_threads(struct machine *machine); 79void machine__delete_dead_threads(struct machine *machine);
@@ -83,7 +90,8 @@ int machine__resolve_callchain(struct machine *machine,
83 struct perf_evsel *evsel, 90 struct perf_evsel *evsel,
84 struct thread *thread, 91 struct thread *thread,
85 struct perf_sample *sample, 92 struct perf_sample *sample,
86 struct symbol **parent); 93 struct symbol **parent,
94 struct addr_location *root_al);
87 95
88/* 96/*
89 * Default guest kernel is defined by parameter --guestkallsyms 97 * Default guest kernel is defined by parameter --guestkallsyms
@@ -99,7 +107,8 @@ static inline bool machine__is_host(struct machine *machine)
99 return machine ? machine->pid == HOST_KERNEL_ID : false; 107 return machine ? machine->pid == HOST_KERNEL_ID : false;
100} 108}
101 109
102struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); 110struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
111 pid_t tid);
103 112
104size_t machine__fprintf(struct machine *machine, FILE *fp); 113size_t machine__fprintf(struct machine *machine, FILE *fp);
105 114
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 6fcb9de62340..4f6680d2043b 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -21,6 +21,7 @@ const char *map_type__name[MAP__NR_TYPES] = {
21static inline int is_anon_memory(const char *filename) 21static inline int is_anon_memory(const char *filename)
22{ 22{
23 return !strcmp(filename, "//anon") || 23 return !strcmp(filename, "//anon") ||
24 !strcmp(filename, "/dev/zero (deleted)") ||
24 !strcmp(filename, "/anon_hugepage (deleted)"); 25 !strcmp(filename, "/anon_hugepage (deleted)");
25} 26}
26 27
@@ -47,7 +48,8 @@ void map__init(struct map *map, enum map_type type,
47} 48}
48 49
49struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 50struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
50 u64 pgoff, u32 pid, char *filename, 51 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
52 u64 ino_gen, char *filename,
51 enum map_type type) 53 enum map_type type)
52{ 54{
53 struct map *map = malloc(sizeof(*map)); 55 struct map *map = malloc(sizeof(*map));
@@ -61,6 +63,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
61 vdso = is_vdso_map(filename); 63 vdso = is_vdso_map(filename);
62 no_dso = is_no_dso_memory(filename); 64 no_dso = is_no_dso_memory(filename);
63 65
66 map->maj = d_maj;
67 map->min = d_min;
68 map->ino = ino;
69 map->ino_generation = ino_gen;
70
64 if (anon) { 71 if (anon) {
65 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 72 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
66 filename = newfilename; 73 filename = newfilename;
@@ -181,12 +188,6 @@ int map__load(struct map *map, symbol_filter_t filter)
181#endif 188#endif
182 return -1; 189 return -1;
183 } 190 }
184 /*
185 * Only applies to the kernel, as its symtabs aren't relative like the
186 * module ones.
187 */
188 if (map->dso->kernel)
189 map__reloc_vmlinux(map);
190 191
191 return 0; 192 return 0;
192} 193}
@@ -253,14 +254,18 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
253 254
254/* 255/*
255 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 256 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
256 * map->dso->adjust_symbols==1 for ET_EXEC-like cases. 257 * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is
258 * relative to section start.
257 */ 259 */
258u64 map__rip_2objdump(struct map *map, u64 rip) 260u64 map__rip_2objdump(struct map *map, u64 rip)
259{ 261{
260 u64 addr = map->dso->adjust_symbols ? 262 if (!map->dso->adjust_symbols)
261 map->unmap_ip(map, rip) : /* RIP -> IP */ 263 return rip;
262 rip; 264
263 return addr; 265 if (map->dso->rel)
266 return rip - map->pgoff;
267
268 return map->unmap_ip(map, rip);
264} 269}
265 270
266void map_groups__init(struct map_groups *mg) 271void map_groups__init(struct map_groups *mg)
@@ -512,35 +517,6 @@ int map_groups__clone(struct map_groups *mg,
512 return 0; 517 return 0;
513} 518}
514 519
515static u64 map__reloc_map_ip(struct map *map, u64 ip)
516{
517 return ip + (s64)map->pgoff;
518}
519
520static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
521{
522 return ip - (s64)map->pgoff;
523}
524
525void map__reloc_vmlinux(struct map *map)
526{
527 struct kmap *kmap = map__kmap(map);
528 s64 reloc;
529
530 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
531 return;
532
533 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
534 kmap->ref_reloc_sym->addr);
535
536 if (!reloc)
537 return;
538
539 map->map_ip = map__reloc_map_ip;
540 map->unmap_ip = map__reloc_unmap_ip;
541 map->pgoff = reloc;
542}
543
544void maps__insert(struct rb_root *maps, struct map *map) 520void maps__insert(struct rb_root *maps, struct map *map)
545{ 521{
546 struct rb_node **p = &maps->rb_node; 522 struct rb_node **p = &maps->rb_node;
@@ -585,3 +561,21 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
585 561
586 return NULL; 562 return NULL;
587} 563}
564
565struct map *maps__first(struct rb_root *maps)
566{
567 struct rb_node *first = rb_first(maps);
568
569 if (first)
570 return rb_entry(first, struct map, rb_node);
571 return NULL;
572}
573
574struct map *maps__next(struct map *map)
575{
576 struct rb_node *next = rb_next(&map->rb_node);
577
578 if (next)
579 return rb_entry(next, struct map, rb_node);
580 return NULL;
581}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index a887f2c9dfbb..4886ca280536 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -36,6 +36,9 @@ struct map {
36 bool erange_warned; 36 bool erange_warned;
37 u32 priv; 37 u32 priv;
38 u64 pgoff; 38 u64 pgoff;
39 u32 maj, min; /* only valid for MMAP2 record */
40 u64 ino; /* only valid for MMAP2 record */
41 u64 ino_generation;/* only valid for MMAP2 record */
39 42
40 /* ip -> dso rip */ 43 /* ip -> dso rip */
41 u64 (*map_ip)(struct map *, u64); 44 u64 (*map_ip)(struct map *, u64);
@@ -88,8 +91,9 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
88void map__init(struct map *map, enum map_type type, 91void map__init(struct map *map, enum map_type type,
89 u64 start, u64 end, u64 pgoff, struct dso *dso); 92 u64 start, u64 end, u64 pgoff, struct dso *dso);
90struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 93struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
91 u64 pgoff, u32 pid, char *filename, 94 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
92 enum map_type type); 95 u64 ino_gen,
96 char *filename, enum map_type type);
93struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 97struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
94void map__delete(struct map *map); 98void map__delete(struct map *map);
95struct map *map__clone(struct map *map); 99struct map *map__clone(struct map *map);
@@ -112,6 +116,8 @@ size_t __map_groups__fprintf_maps(struct map_groups *mg,
112void maps__insert(struct rb_root *maps, struct map *map); 116void maps__insert(struct rb_root *maps, struct map *map);
113void maps__remove(struct rb_root *maps, struct map *map); 117void maps__remove(struct rb_root *maps, struct map *map);
114struct map *maps__find(struct rb_root *maps, u64 addr); 118struct map *maps__find(struct rb_root *maps, u64 addr);
119struct map *maps__first(struct rb_root *maps);
120struct map *maps__next(struct map *map);
115void map_groups__init(struct map_groups *mg); 121void map_groups__init(struct map_groups *mg);
116void map_groups__exit(struct map_groups *mg); 122void map_groups__exit(struct map_groups *mg);
117int map_groups__clone(struct map_groups *mg, 123int map_groups__clone(struct map_groups *mg,
@@ -139,6 +145,17 @@ static inline struct map *map_groups__find(struct map_groups *mg,
139 return maps__find(&mg->maps[type], addr); 145 return maps__find(&mg->maps[type], addr);
140} 146}
141 147
148static inline struct map *map_groups__first(struct map_groups *mg,
149 enum map_type type)
150{
151 return maps__first(&mg->maps[type]);
152}
153
154static inline struct map *map_groups__next(struct map *map)
155{
156 return maps__next(map);
157}
158
142struct symbol *map_groups__find_symbol(struct map_groups *mg, 159struct symbol *map_groups__find_symbol(struct map_groups *mg,
143 enum map_type type, u64 addr, 160 enum map_type type, u64 addr,
144 struct map **mapp, 161 struct map **mapp,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6c8bb0fb189b..98125319b158 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -6,7 +6,7 @@
6#include "parse-options.h" 6#include "parse-options.h"
7#include "parse-events.h" 7#include "parse-events.h"
8#include "exec_cmd.h" 8#include "exec_cmd.h"
9#include "string.h" 9#include "linux/string.h"
10#include "symbol.h" 10#include "symbol.h"
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
@@ -15,6 +15,7 @@
15#define YY_EXTRA_TYPE int 15#define YY_EXTRA_TYPE int
16#include "parse-events-flex.h" 16#include "parse-events-flex.h"
17#include "pmu.h" 17#include "pmu.h"
18#include "thread_map.h"
18 19
19#define MAX_NAME_LEN 100 20#define MAX_NAME_LEN 100
20 21
@@ -108,6 +109,10 @@ static struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
108 .symbol = "emulation-faults", 109 .symbol = "emulation-faults",
109 .alias = "", 110 .alias = "",
110 }, 111 },
112 [PERF_COUNT_SW_DUMMY] = {
113 .symbol = "dummy",
114 .alias = "",
115 },
111}; 116};
112 117
113#define __PERF_EVENT_FIELD(config, name) \ 118#define __PERF_EVENT_FIELD(config, name) \
@@ -217,6 +222,29 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
217 return NULL; 222 return NULL;
218} 223}
219 224
225struct tracepoint_path *tracepoint_name_to_path(const char *name)
226{
227 struct tracepoint_path *path = zalloc(sizeof(*path));
228 char *str = strchr(name, ':');
229
230 if (path == NULL || str == NULL) {
231 free(path);
232 return NULL;
233 }
234
235 path->system = strndup(name, str - name);
236 path->name = strdup(str+1);
237
238 if (path->system == NULL || path->name == NULL) {
239 free(path->system);
240 free(path->name);
241 free(path);
242 path = NULL;
243 }
244
245 return path;
246}
247
220const char *event_type(int type) 248const char *event_type(int type)
221{ 249{
222 switch (type) { 250 switch (type) {
@@ -241,40 +269,29 @@ const char *event_type(int type)
241 269
242 270
243 271
244static int __add_event(struct list_head **_list, int *idx, 272static int __add_event(struct list_head *list, int *idx,
245 struct perf_event_attr *attr, 273 struct perf_event_attr *attr,
246 char *name, struct cpu_map *cpus) 274 char *name, struct cpu_map *cpus)
247{ 275{
248 struct perf_evsel *evsel; 276 struct perf_evsel *evsel;
249 struct list_head *list = *_list;
250
251 if (!list) {
252 list = malloc(sizeof(*list));
253 if (!list)
254 return -ENOMEM;
255 INIT_LIST_HEAD(list);
256 }
257 277
258 event_attr_init(attr); 278 event_attr_init(attr);
259 279
260 evsel = perf_evsel__new(attr, (*idx)++); 280 evsel = perf_evsel__new(attr, (*idx)++);
261 if (!evsel) { 281 if (!evsel)
262 free(list);
263 return -ENOMEM; 282 return -ENOMEM;
264 }
265 283
266 evsel->cpus = cpus; 284 evsel->cpus = cpus;
267 if (name) 285 if (name)
268 evsel->name = strdup(name); 286 evsel->name = strdup(name);
269 list_add_tail(&evsel->node, list); 287 list_add_tail(&evsel->node, list);
270 *_list = list;
271 return 0; 288 return 0;
272} 289}
273 290
274static int add_event(struct list_head **_list, int *idx, 291static int add_event(struct list_head *list, int *idx,
275 struct perf_event_attr *attr, char *name) 292 struct perf_event_attr *attr, char *name)
276{ 293{
277 return __add_event(_list, idx, attr, name, NULL); 294 return __add_event(list, idx, attr, name, NULL);
278} 295}
279 296
280static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) 297static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
@@ -295,7 +312,7 @@ static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES]
295 return -1; 312 return -1;
296} 313}
297 314
298int parse_events_add_cache(struct list_head **list, int *idx, 315int parse_events_add_cache(struct list_head *list, int *idx,
299 char *type, char *op_result1, char *op_result2) 316 char *type, char *op_result1, char *op_result2)
300{ 317{
301 struct perf_event_attr attr; 318 struct perf_event_attr attr;
@@ -356,31 +373,21 @@ int parse_events_add_cache(struct list_head **list, int *idx,
356 return add_event(list, idx, &attr, name); 373 return add_event(list, idx, &attr, name);
357} 374}
358 375
359static int add_tracepoint(struct list_head **listp, int *idx, 376static int add_tracepoint(struct list_head *list, int *idx,
360 char *sys_name, char *evt_name) 377 char *sys_name, char *evt_name)
361{ 378{
362 struct perf_evsel *evsel; 379 struct perf_evsel *evsel;
363 struct list_head *list = *listp;
364
365 if (!list) {
366 list = malloc(sizeof(*list));
367 if (!list)
368 return -ENOMEM;
369 INIT_LIST_HEAD(list);
370 }
371 380
372 evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); 381 evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++);
373 if (!evsel) { 382 if (!evsel)
374 free(list);
375 return -ENOMEM; 383 return -ENOMEM;
376 }
377 384
378 list_add_tail(&evsel->node, list); 385 list_add_tail(&evsel->node, list);
379 *listp = list; 386
380 return 0; 387 return 0;
381} 388}
382 389
383static int add_tracepoint_multi_event(struct list_head **list, int *idx, 390static int add_tracepoint_multi_event(struct list_head *list, int *idx,
384 char *sys_name, char *evt_name) 391 char *sys_name, char *evt_name)
385{ 392{
386 char evt_path[MAXPATHLEN]; 393 char evt_path[MAXPATHLEN];
@@ -412,7 +419,7 @@ static int add_tracepoint_multi_event(struct list_head **list, int *idx,
412 return ret; 419 return ret;
413} 420}
414 421
415static int add_tracepoint_event(struct list_head **list, int *idx, 422static int add_tracepoint_event(struct list_head *list, int *idx,
416 char *sys_name, char *evt_name) 423 char *sys_name, char *evt_name)
417{ 424{
418 return strpbrk(evt_name, "*?") ? 425 return strpbrk(evt_name, "*?") ?
@@ -420,7 +427,7 @@ static int add_tracepoint_event(struct list_head **list, int *idx,
420 add_tracepoint(list, idx, sys_name, evt_name); 427 add_tracepoint(list, idx, sys_name, evt_name);
421} 428}
422 429
423static int add_tracepoint_multi_sys(struct list_head **list, int *idx, 430static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
424 char *sys_name, char *evt_name) 431 char *sys_name, char *evt_name)
425{ 432{
426 struct dirent *events_ent; 433 struct dirent *events_ent;
@@ -452,7 +459,7 @@ static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
452 return ret; 459 return ret;
453} 460}
454 461
455int parse_events_add_tracepoint(struct list_head **list, int *idx, 462int parse_events_add_tracepoint(struct list_head *list, int *idx,
456 char *sys, char *event) 463 char *sys, char *event)
457{ 464{
458 int ret; 465 int ret;
@@ -507,7 +514,7 @@ do { \
507 return 0; 514 return 0;
508} 515}
509 516
510int parse_events_add_breakpoint(struct list_head **list, int *idx, 517int parse_events_add_breakpoint(struct list_head *list, int *idx,
511 void *ptr, char *type) 518 void *ptr, char *type)
512{ 519{
513 struct perf_event_attr attr; 520 struct perf_event_attr attr;
@@ -588,7 +595,7 @@ static int config_attr(struct perf_event_attr *attr,
588 return 0; 595 return 0;
589} 596}
590 597
591int parse_events_add_numeric(struct list_head **list, int *idx, 598int parse_events_add_numeric(struct list_head *list, int *idx,
592 u32 type, u64 config, 599 u32 type, u64 config,
593 struct list_head *head_config) 600 struct list_head *head_config)
594{ 601{
@@ -621,7 +628,7 @@ static char *pmu_event_name(struct list_head *head_terms)
621 return NULL; 628 return NULL;
622} 629}
623 630
624int parse_events_add_pmu(struct list_head **list, int *idx, 631int parse_events_add_pmu(struct list_head *list, int *idx,
625 char *name, struct list_head *head_config) 632 char *name, struct list_head *head_config)
626{ 633{
627 struct perf_event_attr attr; 634 struct perf_event_attr attr;
@@ -664,6 +671,7 @@ void parse_events__set_leader(char *name, struct list_head *list)
664 leader->group_name = name ? strdup(name) : NULL; 671 leader->group_name = name ? strdup(name) : NULL;
665} 672}
666 673
674/* list_event is assumed to point to malloc'ed memory */
667void parse_events_update_lists(struct list_head *list_event, 675void parse_events_update_lists(struct list_head *list_event,
668 struct list_head *list_all) 676 struct list_head *list_all)
669{ 677{
@@ -684,6 +692,8 @@ struct event_modifier {
684 int eG; 692 int eG;
685 int precise; 693 int precise;
686 int exclude_GH; 694 int exclude_GH;
695 int sample_read;
696 int pinned;
687}; 697};
688 698
689static int get_event_modifier(struct event_modifier *mod, char *str, 699static int get_event_modifier(struct event_modifier *mod, char *str,
@@ -695,6 +705,8 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
695 int eH = evsel ? evsel->attr.exclude_host : 0; 705 int eH = evsel ? evsel->attr.exclude_host : 0;
696 int eG = evsel ? evsel->attr.exclude_guest : 0; 706 int eG = evsel ? evsel->attr.exclude_guest : 0;
697 int precise = evsel ? evsel->attr.precise_ip : 0; 707 int precise = evsel ? evsel->attr.precise_ip : 0;
708 int sample_read = 0;
709 int pinned = evsel ? evsel->attr.pinned : 0;
698 710
699 int exclude = eu | ek | eh; 711 int exclude = eu | ek | eh;
700 int exclude_GH = evsel ? evsel->exclude_GH : 0; 712 int exclude_GH = evsel ? evsel->exclude_GH : 0;
@@ -727,6 +739,10 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
727 /* use of precise requires exclude_guest */ 739 /* use of precise requires exclude_guest */
728 if (!exclude_GH) 740 if (!exclude_GH)
729 eG = 1; 741 eG = 1;
742 } else if (*str == 'S') {
743 sample_read = 1;
744 } else if (*str == 'D') {
745 pinned = 1;
730 } else 746 } else
731 break; 747 break;
732 748
@@ -753,6 +769,9 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
753 mod->eG = eG; 769 mod->eG = eG;
754 mod->precise = precise; 770 mod->precise = precise;
755 mod->exclude_GH = exclude_GH; 771 mod->exclude_GH = exclude_GH;
772 mod->sample_read = sample_read;
773 mod->pinned = pinned;
774
756 return 0; 775 return 0;
757} 776}
758 777
@@ -765,7 +784,7 @@ static int check_modifier(char *str)
765 char *p = str; 784 char *p = str;
766 785
767 /* The sizeof includes 0 byte as well. */ 786 /* The sizeof includes 0 byte as well. */
768 if (strlen(str) > (sizeof("ukhGHppp") - 1)) 787 if (strlen(str) > (sizeof("ukhGHpppSD") - 1))
769 return -1; 788 return -1;
770 789
771 while (*p) { 790 while (*p) {
@@ -803,6 +822,10 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add)
803 evsel->attr.exclude_host = mod.eH; 822 evsel->attr.exclude_host = mod.eH;
804 evsel->attr.exclude_guest = mod.eG; 823 evsel->attr.exclude_guest = mod.eG;
805 evsel->exclude_GH = mod.exclude_GH; 824 evsel->exclude_GH = mod.exclude_GH;
825 evsel->sample_read = mod.sample_read;
826
827 if (perf_evsel__is_group_leader(evsel))
828 evsel->attr.pinned = mod.pinned;
806 } 829 }
807 830
808 return 0; 831 return 0;
@@ -820,6 +843,32 @@ int parse_events_name(struct list_head *list, char *name)
820 return 0; 843 return 0;
821} 844}
822 845
846static int parse_events__scanner(const char *str, void *data, int start_token);
847
848static int parse_events_fixup(int ret, const char *str, void *data,
849 int start_token)
850{
851 char *o = strdup(str);
852 char *s = NULL;
853 char *t = o;
854 char *p;
855 int len = 0;
856
857 if (!o)
858 return ret;
859 while ((p = strsep(&t, ",")) != NULL) {
860 if (s)
861 str_append(&s, &len, ",");
862 str_append(&s, &len, "cpu/");
863 str_append(&s, &len, p);
864 str_append(&s, &len, "/");
865 }
866 free(o);
867 if (!s)
868 return -ENOMEM;
869 return parse_events__scanner(s, data, start_token);
870}
871
823static int parse_events__scanner(const char *str, void *data, int start_token) 872static int parse_events__scanner(const char *str, void *data, int start_token)
824{ 873{
825 YY_BUFFER_STATE buffer; 874 YY_BUFFER_STATE buffer;
@@ -840,6 +889,8 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
840 parse_events__flush_buffer(buffer, scanner); 889 parse_events__flush_buffer(buffer, scanner);
841 parse_events__delete_buffer(buffer, scanner); 890 parse_events__delete_buffer(buffer, scanner);
842 parse_events_lex_destroy(scanner); 891 parse_events_lex_destroy(scanner);
892 if (ret && !strchr(str, '/'))
893 ret = parse_events_fixup(ret, str, data, start_token);
843 return ret; 894 return ret;
844} 895}
845 896
@@ -860,7 +911,8 @@ int parse_events_terms(struct list_head *terms, const char *str)
860 return 0; 911 return 0;
861 } 912 }
862 913
863 parse_events__free_terms(data.terms); 914 if (data.terms)
915 parse_events__free_terms(data.terms);
864 return ret; 916 return ret;
865} 917}
866 918
@@ -1025,6 +1077,33 @@ int is_valid_tracepoint(const char *event_string)
1025 return 0; 1077 return 0;
1026} 1078}
1027 1079
1080static bool is_event_supported(u8 type, unsigned config)
1081{
1082 bool ret = true;
1083 struct perf_evsel *evsel;
1084 struct perf_event_attr attr = {
1085 .type = type,
1086 .config = config,
1087 .disabled = 1,
1088 .exclude_kernel = 1,
1089 };
1090 struct {
1091 struct thread_map map;
1092 int threads[1];
1093 } tmap = {
1094 .map.nr = 1,
1095 .threads = { 0 },
1096 };
1097
1098 evsel = perf_evsel__new(&attr, 0);
1099 if (evsel) {
1100 ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
1101 perf_evsel__delete(evsel);
1102 }
1103
1104 return ret;
1105}
1106
1028static void __print_events_type(u8 type, struct event_symbol *syms, 1107static void __print_events_type(u8 type, struct event_symbol *syms,
1029 unsigned max) 1108 unsigned max)
1030{ 1109{
@@ -1032,14 +1111,16 @@ static void __print_events_type(u8 type, struct event_symbol *syms,
1032 unsigned i; 1111 unsigned i;
1033 1112
1034 for (i = 0; i < max ; i++, syms++) { 1113 for (i = 0; i < max ; i++, syms++) {
1114 if (!is_event_supported(type, i))
1115 continue;
1116
1035 if (strlen(syms->alias)) 1117 if (strlen(syms->alias))
1036 snprintf(name, sizeof(name), "%s OR %s", 1118 snprintf(name, sizeof(name), "%s OR %s",
1037 syms->symbol, syms->alias); 1119 syms->symbol, syms->alias);
1038 else 1120 else
1039 snprintf(name, sizeof(name), "%s", syms->symbol); 1121 snprintf(name, sizeof(name), "%s", syms->symbol);
1040 1122
1041 printf(" %-50s [%s]\n", name, 1123 printf(" %-50s [%s]\n", name, event_type_descriptors[type]);
1042 event_type_descriptors[type]);
1043 } 1124 }
1044} 1125}
1045 1126
@@ -1068,6 +1149,10 @@ int print_hwcache_events(const char *event_glob, bool name_only)
1068 if (event_glob != NULL && !strglobmatch(name, event_glob)) 1149 if (event_glob != NULL && !strglobmatch(name, event_glob))
1069 continue; 1150 continue;
1070 1151
1152 if (!is_event_supported(PERF_TYPE_HW_CACHE,
1153 type | (op << 8) | (i << 16)))
1154 continue;
1155
1071 if (name_only) 1156 if (name_only)
1072 printf("%s ", name); 1157 printf("%s ", name);
1073 else 1158 else
@@ -1078,6 +1163,8 @@ int print_hwcache_events(const char *event_glob, bool name_only)
1078 } 1163 }
1079 } 1164 }
1080 1165
1166 if (printed)
1167 printf("\n");
1081 return printed; 1168 return printed;
1082} 1169}
1083 1170
@@ -1095,6 +1182,9 @@ static void print_symbol_events(const char *event_glob, unsigned type,
1095 (syms->alias && strglobmatch(syms->alias, event_glob)))) 1182 (syms->alias && strglobmatch(syms->alias, event_glob))))
1096 continue; 1183 continue;
1097 1184
1185 if (!is_event_supported(type, i))
1186 continue;
1187
1098 if (name_only) { 1188 if (name_only) {
1099 printf("%s ", syms->symbol); 1189 printf("%s ", syms->symbol);
1100 continue; 1190 continue;
@@ -1132,11 +1222,12 @@ void print_events(const char *event_glob, bool name_only)
1132 1222
1133 print_hwcache_events(event_glob, name_only); 1223 print_hwcache_events(event_glob, name_only);
1134 1224
1225 print_pmu_events(event_glob, name_only);
1226
1135 if (event_glob != NULL) 1227 if (event_glob != NULL)
1136 return; 1228 return;
1137 1229
1138 if (!name_only) { 1230 if (!name_only) {
1139 printf("\n");
1140 printf(" %-50s [%s]\n", 1231 printf(" %-50s [%s]\n",
1141 "rNNN", 1232 "rNNN",
1142 event_type_descriptors[PERF_TYPE_RAW]); 1233 event_type_descriptors[PERF_TYPE_RAW]);
@@ -1183,6 +1274,7 @@ static int new_term(struct parse_events_term **_term, int type_val,
1183 term->val.str = str; 1274 term->val.str = str;
1184 break; 1275 break;
1185 default: 1276 default:
1277 free(term);
1186 return -EINVAL; 1278 return -EINVAL;
1187 } 1279 }
1188 1280
@@ -1235,6 +1327,4 @@ void parse_events__free_terms(struct list_head *terms)
1235 1327
1236 list_for_each_entry_safe(term, h, terms, list) 1328 list_for_each_entry_safe(term, h, terms, list)
1237 free(term); 1329 free(term);
1238
1239 free(terms);
1240} 1330}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8a4859315fd9..f1cb4c4b3c70 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -23,6 +23,7 @@ struct tracepoint_path {
23}; 23};
24 24
25extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 25extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
26extern struct tracepoint_path *tracepoint_name_to_path(const char *name);
26extern bool have_tracepoints(struct list_head *evlist); 27extern bool have_tracepoints(struct list_head *evlist);
27 28
28const char *event_type(int type); 29const char *event_type(int type);
@@ -84,16 +85,16 @@ void parse_events__free_terms(struct list_head *terms);
84int parse_events__modifier_event(struct list_head *list, char *str, bool add); 85int parse_events__modifier_event(struct list_head *list, char *str, bool add);
85int parse_events__modifier_group(struct list_head *list, char *event_mod); 86int parse_events__modifier_group(struct list_head *list, char *event_mod);
86int parse_events_name(struct list_head *list, char *name); 87int parse_events_name(struct list_head *list, char *name);
87int parse_events_add_tracepoint(struct list_head **list, int *idx, 88int parse_events_add_tracepoint(struct list_head *list, int *idx,
88 char *sys, char *event); 89 char *sys, char *event);
89int parse_events_add_numeric(struct list_head **list, int *idx, 90int parse_events_add_numeric(struct list_head *list, int *idx,
90 u32 type, u64 config, 91 u32 type, u64 config,
91 struct list_head *head_config); 92 struct list_head *head_config);
92int parse_events_add_cache(struct list_head **list, int *idx, 93int parse_events_add_cache(struct list_head *list, int *idx,
93 char *type, char *op_result1, char *op_result2); 94 char *type, char *op_result1, char *op_result2);
94int parse_events_add_breakpoint(struct list_head **list, int *idx, 95int parse_events_add_breakpoint(struct list_head *list, int *idx,
95 void *ptr, char *type); 96 void *ptr, char *type);
96int parse_events_add_pmu(struct list_head **list, int *idx, 97int parse_events_add_pmu(struct list_head *list, int *idx,
97 char *pmu , struct list_head *head_config); 98 char *pmu , struct list_head *head_config);
98void parse_events__set_leader(char *name, struct list_head *list); 99void parse_events__set_leader(char *name, struct list_head *list);
99void parse_events_update_lists(struct list_head *list_event, 100void parse_events_update_lists(struct list_head *list_event,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index e9d1134c2c68..91346b753960 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -82,7 +82,8 @@ num_hex 0x[a-fA-F0-9]+
82num_raw_hex [a-fA-F0-9]+ 82num_raw_hex [a-fA-F0-9]+
83name [a-zA-Z_*?][a-zA-Z0-9_*?]* 83name [a-zA-Z_*?][a-zA-Z0-9_*?]*
84name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]* 84name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]*
85modifier_event [ukhpGH]+ 85/* If you add a modifier you need to update check_modifier() */
86modifier_event [ukhpGHSD]+
86modifier_bp [rwx]{1,3} 87modifier_bp [rwx]{1,3}
87 88
88%% 89%%
@@ -144,6 +145,7 @@ context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW
144cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } 145cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
145alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } 146alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
146emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } 147emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
148dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
147 149
148L1-dcache|l1-d|l1d|L1-data | 150L1-dcache|l1-d|l1d|L1-data |
149L1-icache|l1-i|l1i|L1-instruction | 151L1-icache|l1-i|l1i|L1-instruction |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index afc44c18dfe1..4eb67ec333f1 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -22,6 +22,13 @@ do { \
22 YYABORT; \ 22 YYABORT; \
23} while (0) 23} while (0)
24 24
25#define ALLOC_LIST(list) \
26do { \
27 list = malloc(sizeof(*list)); \
28 ABORT_ON(!list); \
29 INIT_LIST_HEAD(list); \
30} while (0)
31
25static inc_group_count(struct list_head *list, 32static inc_group_count(struct list_head *list,
26 struct parse_events_evlist *data) 33 struct parse_events_evlist *data)
27{ 34{
@@ -196,9 +203,10 @@ event_pmu:
196PE_NAME '/' event_config '/' 203PE_NAME '/' event_config '/'
197{ 204{
198 struct parse_events_evlist *data = _data; 205 struct parse_events_evlist *data = _data;
199 struct list_head *list = NULL; 206 struct list_head *list;
200 207
201 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); 208 ALLOC_LIST(list);
209 ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, $3));
202 parse_events__free_terms($3); 210 parse_events__free_terms($3);
203 $$ = list; 211 $$ = list;
204} 212}
@@ -212,11 +220,12 @@ event_legacy_symbol:
212value_sym '/' event_config '/' 220value_sym '/' event_config '/'
213{ 221{
214 struct parse_events_evlist *data = _data; 222 struct parse_events_evlist *data = _data;
215 struct list_head *list = NULL; 223 struct list_head *list;
216 int type = $1 >> 16; 224 int type = $1 >> 16;
217 int config = $1 & 255; 225 int config = $1 & 255;
218 226
219 ABORT_ON(parse_events_add_numeric(&list, &data->idx, 227 ALLOC_LIST(list);
228 ABORT_ON(parse_events_add_numeric(list, &data->idx,
220 type, config, $3)); 229 type, config, $3));
221 parse_events__free_terms($3); 230 parse_events__free_terms($3);
222 $$ = list; 231 $$ = list;
@@ -225,11 +234,12 @@ value_sym '/' event_config '/'
225value_sym sep_slash_dc 234value_sym sep_slash_dc
226{ 235{
227 struct parse_events_evlist *data = _data; 236 struct parse_events_evlist *data = _data;
228 struct list_head *list = NULL; 237 struct list_head *list;
229 int type = $1 >> 16; 238 int type = $1 >> 16;
230 int config = $1 & 255; 239 int config = $1 & 255;
231 240
232 ABORT_ON(parse_events_add_numeric(&list, &data->idx, 241 ALLOC_LIST(list);
242 ABORT_ON(parse_events_add_numeric(list, &data->idx,
233 type, config, NULL)); 243 type, config, NULL));
234 $$ = list; 244 $$ = list;
235} 245}
@@ -238,27 +248,30 @@ event_legacy_cache:
238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 248PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
239{ 249{
240 struct parse_events_evlist *data = _data; 250 struct parse_events_evlist *data = _data;
241 struct list_head *list = NULL; 251 struct list_head *list;
242 252
243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); 253 ALLOC_LIST(list);
254 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, $5));
244 $$ = list; 255 $$ = list;
245} 256}
246| 257|
247PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 258PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
248{ 259{
249 struct parse_events_evlist *data = _data; 260 struct parse_events_evlist *data = _data;
250 struct list_head *list = NULL; 261 struct list_head *list;
251 262
252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); 263 ALLOC_LIST(list);
264 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, NULL));
253 $$ = list; 265 $$ = list;
254} 266}
255| 267|
256PE_NAME_CACHE_TYPE 268PE_NAME_CACHE_TYPE
257{ 269{
258 struct parse_events_evlist *data = _data; 270 struct parse_events_evlist *data = _data;
259 struct list_head *list = NULL; 271 struct list_head *list;
260 272
261 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); 273 ALLOC_LIST(list);
274 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, NULL, NULL));
262 $$ = list; 275 $$ = list;
263} 276}
264 277
@@ -266,9 +279,10 @@ event_legacy_mem:
266PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 279PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
267{ 280{
268 struct parse_events_evlist *data = _data; 281 struct parse_events_evlist *data = _data;
269 struct list_head *list = NULL; 282 struct list_head *list;
270 283
271 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 284 ALLOC_LIST(list);
285 ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
272 (void *) $2, $4)); 286 (void *) $2, $4));
273 $$ = list; 287 $$ = list;
274} 288}
@@ -276,9 +290,10 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
276PE_PREFIX_MEM PE_VALUE sep_dc 290PE_PREFIX_MEM PE_VALUE sep_dc
277{ 291{
278 struct parse_events_evlist *data = _data; 292 struct parse_events_evlist *data = _data;
279 struct list_head *list = NULL; 293 struct list_head *list;
280 294
281 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 295 ALLOC_LIST(list);
296 ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
282 (void *) $2, NULL)); 297 (void *) $2, NULL));
283 $$ = list; 298 $$ = list;
284} 299}
@@ -287,9 +302,10 @@ event_legacy_tracepoint:
287PE_NAME ':' PE_NAME 302PE_NAME ':' PE_NAME
288{ 303{
289 struct parse_events_evlist *data = _data; 304 struct parse_events_evlist *data = _data;
290 struct list_head *list = NULL; 305 struct list_head *list;
291 306
292 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); 307 ALLOC_LIST(list);
308 ABORT_ON(parse_events_add_tracepoint(list, &data->idx, $1, $3));
293 $$ = list; 309 $$ = list;
294} 310}
295 311
@@ -297,9 +313,10 @@ event_legacy_numeric:
297PE_VALUE ':' PE_VALUE 313PE_VALUE ':' PE_VALUE
298{ 314{
299 struct parse_events_evlist *data = _data; 315 struct parse_events_evlist *data = _data;
300 struct list_head *list = NULL; 316 struct list_head *list;
301 317
302 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); 318 ALLOC_LIST(list);
319 ABORT_ON(parse_events_add_numeric(list, &data->idx, (u32)$1, $3, NULL));
303 $$ = list; 320 $$ = list;
304} 321}
305 322
@@ -307,9 +324,10 @@ event_legacy_raw:
307PE_RAW 324PE_RAW
308{ 325{
309 struct parse_events_evlist *data = _data; 326 struct parse_events_evlist *data = _data;
310 struct list_head *list = NULL; 327 struct list_head *list;
311 328
312 ABORT_ON(parse_events_add_numeric(&list, &data->idx, 329 ALLOC_LIST(list);
330 ABORT_ON(parse_events_add_numeric(list, &data->idx,
313 PERF_TYPE_RAW, $1, NULL)); 331 PERF_TYPE_RAW, $1, NULL));
314 $$ = list; 332 $$ = list;
315} 333}
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 4c6f9c490a8d..bc9d8069d376 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -73,7 +73,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head)
73 * located at: 73 * located at:
74 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 74 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
75 */ 75 */
76static int pmu_format(char *name, struct list_head *format) 76static 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];
@@ -162,7 +162,7 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
162 * Reading the pmu event aliases definition, which should be located at: 162 * Reading the pmu event aliases definition, which should be located at:
163 * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 163 * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
164 */ 164 */
165static int pmu_aliases(char *name, struct list_head *head) 165static int pmu_aliases(const char *name, struct list_head *head)
166{ 166{
167 struct stat st; 167 struct stat st;
168 char path[PATH_MAX]; 168 char path[PATH_MAX];
@@ -208,7 +208,7 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
208 * located at: 208 * located at:
209 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 209 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
210 */ 210 */
211static int pmu_type(char *name, __u32 *type) 211static int pmu_type(const char *name, __u32 *type)
212{ 212{
213 struct stat st; 213 struct stat st;
214 char path[PATH_MAX]; 214 char path[PATH_MAX];
@@ -266,7 +266,7 @@ static void pmu_read_sysfs(void)
266 closedir(dir); 266 closedir(dir);
267} 267}
268 268
269static struct cpu_map *pmu_cpumask(char *name) 269static struct cpu_map *pmu_cpumask(const char *name)
270{ 270{
271 struct stat st; 271 struct stat st;
272 char path[PATH_MAX]; 272 char path[PATH_MAX];
@@ -293,7 +293,7 @@ static struct cpu_map *pmu_cpumask(char *name)
293 return cpus; 293 return cpus;
294} 294}
295 295
296static struct perf_pmu *pmu_lookup(char *name) 296static struct perf_pmu *pmu_lookup(const char *name)
297{ 297{
298 struct perf_pmu *pmu; 298 struct perf_pmu *pmu;
299 LIST_HEAD(format); 299 LIST_HEAD(format);
@@ -330,7 +330,7 @@ static struct perf_pmu *pmu_lookup(char *name)
330 return pmu; 330 return pmu;
331} 331}
332 332
333static struct perf_pmu *pmu_find(char *name) 333static struct perf_pmu *pmu_find(const char *name)
334{ 334{
335 struct perf_pmu *pmu; 335 struct perf_pmu *pmu;
336 336
@@ -356,7 +356,7 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
356 return NULL; 356 return NULL;
357} 357}
358 358
359struct perf_pmu *perf_pmu__find(char *name) 359struct perf_pmu *perf_pmu__find(const char *name)
360{ 360{
361 struct perf_pmu *pmu; 361 struct perf_pmu *pmu;
362 362
@@ -564,3 +564,76 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
564 for (b = from; b <= to; b++) 564 for (b = from; b <= to; b++)
565 set_bit(b, bits); 565 set_bit(b, bits);
566} 566}
567
568static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
569 struct perf_pmu_alias *alias)
570{
571 snprintf(buf, len, "%s/%s/", pmu->name, alias->name);
572 return buf;
573}
574
575static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
576 struct perf_pmu_alias *alias)
577{
578 snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
579 return buf;
580}
581
582static int cmp_string(const void *a, const void *b)
583{
584 const char * const *as = a;
585 const char * const *bs = b;
586 return strcmp(*as, *bs);
587}
588
589void print_pmu_events(const char *event_glob, bool name_only)
590{
591 struct perf_pmu *pmu;
592 struct perf_pmu_alias *alias;
593 char buf[1024];
594 int printed = 0;
595 int len, j;
596 char **aliases;
597
598 pmu = NULL;
599 len = 0;
600 while ((pmu = perf_pmu__scan(pmu)) != NULL)
601 list_for_each_entry(alias, &pmu->aliases, list)
602 len++;
603 aliases = malloc(sizeof(char *) * len);
604 if (!aliases)
605 return;
606 pmu = NULL;
607 j = 0;
608 while ((pmu = perf_pmu__scan(pmu)) != NULL)
609 list_for_each_entry(alias, &pmu->aliases, list) {
610 char *name = format_alias(buf, sizeof(buf), pmu, alias);
611 bool is_cpu = !strcmp(pmu->name, "cpu");
612
613 if (event_glob != NULL &&
614 !(strglobmatch(name, event_glob) ||
615 (!is_cpu && strglobmatch(alias->name,
616 event_glob))))
617 continue;
618 aliases[j] = name;
619 if (is_cpu && !name_only)
620 aliases[j] = format_alias_or(buf, sizeof(buf),
621 pmu, alias);
622 aliases[j] = strdup(aliases[j]);
623 j++;
624 }
625 len = j;
626 qsort(aliases, len, sizeof(char *), cmp_string);
627 for (j = 0; j < len; j++) {
628 if (name_only) {
629 printf("%s ", aliases[j]);
630 continue;
631 }
632 printf(" %-50s [Kernel PMU event]\n", aliases[j]);
633 free(aliases[j]);
634 printed++;
635 }
636 if (printed)
637 printf("\n");
638 free(aliases);
639}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 32fe55b659fa..6b2cbe2d4cc3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/bitops.h> 4#include <linux/bitops.h>
5#include <linux/perf_event.h> 5#include <linux/perf_event.h>
6#include <stdbool.h>
6 7
7enum { 8enum {
8 PERF_PMU_FORMAT_VALUE_CONFIG, 9 PERF_PMU_FORMAT_VALUE_CONFIG,
@@ -21,7 +22,7 @@ struct perf_pmu {
21 struct list_head list; 22 struct list_head list;
22}; 23};
23 24
24struct perf_pmu *perf_pmu__find(char *name); 25struct perf_pmu *perf_pmu__find(const char *name);
25int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 26int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
26 struct list_head *head_terms); 27 struct list_head *head_terms);
27int perf_pmu__config_terms(struct list_head *formats, 28int perf_pmu__config_terms(struct list_head *formats,
@@ -40,5 +41,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
40 41
41struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 42struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
42 43
44void print_pmu_events(const char *event_glob, bool name_only);
45
43int perf_pmu__test(void); 46int perf_pmu__test(void);
44#endif /* __PMU_H */ 47#endif /* __PMU_H */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index be0329394d56..371476cb8ddc 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -118,7 +118,6 @@ static const Dwfl_Callbacks offline_callbacks = {
118static int debuginfo__init_offline_dwarf(struct debuginfo *self, 118static int debuginfo__init_offline_dwarf(struct debuginfo *self,
119 const char *path) 119 const char *path)
120{ 120{
121 Dwfl_Module *mod;
122 int fd; 121 int fd;
123 122
124 fd = open(path, O_RDONLY); 123 fd = open(path, O_RDONLY);
@@ -129,11 +128,11 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *self,
129 if (!self->dwfl) 128 if (!self->dwfl)
130 goto error; 129 goto error;
131 130
132 mod = dwfl_report_offline(self->dwfl, "", "", fd); 131 self->mod = dwfl_report_offline(self->dwfl, "", "", fd);
133 if (!mod) 132 if (!self->mod)
134 goto error; 133 goto error;
135 134
136 self->dbg = dwfl_module_getdwarf(mod, &self->bias); 135 self->dbg = dwfl_module_getdwarf(self->mod, &self->bias);
137 if (!self->dbg) 136 if (!self->dbg)
138 goto error; 137 goto error;
139 138
@@ -676,37 +675,42 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
676} 675}
677 676
678/* Convert subprogram DIE to trace point */ 677/* Convert subprogram DIE to trace point */
679static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, 678static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
680 bool retprobe, struct probe_trace_point *tp) 679 Dwarf_Addr paddr, bool retprobe,
680 struct probe_trace_point *tp)
681{ 681{
682 Dwarf_Addr eaddr, highaddr; 682 Dwarf_Addr eaddr, highaddr;
683 const char *name; 683 GElf_Sym sym;
684 684 const char *symbol;
685 /* Copy the name of probe point */ 685
686 name = dwarf_diename(sp_die); 686 /* Verify the address is correct */
687 if (name) { 687 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
688 if (dwarf_entrypc(sp_die, &eaddr) != 0) { 688 pr_warning("Failed to get entry address of %s\n",
689 pr_warning("Failed to get entry address of %s\n", 689 dwarf_diename(sp_die));
690 dwarf_diename(sp_die)); 690 return -ENOENT;
691 return -ENOENT; 691 }
692 } 692 if (dwarf_highpc(sp_die, &highaddr) != 0) {
693 if (dwarf_highpc(sp_die, &highaddr) != 0) { 693 pr_warning("Failed to get end address of %s\n",
694 pr_warning("Failed to get end address of %s\n", 694 dwarf_diename(sp_die));
695 dwarf_diename(sp_die)); 695 return -ENOENT;
696 return -ENOENT; 696 }
697 } 697 if (paddr > highaddr) {
698 if (paddr > highaddr) { 698 pr_warning("Offset specified is greater than size of %s\n",
699 pr_warning("Offset specified is greater than size of %s\n", 699 dwarf_diename(sp_die));
700 dwarf_diename(sp_die)); 700 return -EINVAL;
701 return -EINVAL; 701 }
702 } 702
703 tp->symbol = strdup(name); 703 /* Get an appropriate symbol from symtab */
704 if (tp->symbol == NULL) 704 symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
705 return -ENOMEM; 705 if (!symbol) {
706 tp->offset = (unsigned long)(paddr - eaddr); 706 pr_warning("Failed to find symbol at 0x%lx\n",
707 } else 707 (unsigned long)paddr);
708 /* This function has no name. */ 708 return -ENOENT;
709 tp->offset = (unsigned long)paddr; 709 }
710 tp->offset = (unsigned long)(paddr - sym.st_value);
711 tp->symbol = strdup(symbol);
712 if (!tp->symbol)
713 return -ENOMEM;
710 714
711 /* Return probe must be on the head of a subprogram */ 715 /* Return probe must be on the head of a subprogram */
712 if (retprobe) { 716 if (retprobe) {
@@ -734,7 +738,7 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
734 } 738 }
735 739
736 /* If not a real subprogram, find a real one */ 740 /* If not a real subprogram, find a real one */
737 if (dwarf_tag(sc_die) != DW_TAG_subprogram) { 741 if (!die_is_func_def(sc_die)) {
738 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 742 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
739 pr_warning("Failed to find probe point in any " 743 pr_warning("Failed to find probe point in any "
740 "functions.\n"); 744 "functions.\n");
@@ -980,12 +984,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
980 struct dwarf_callback_param *param = data; 984 struct dwarf_callback_param *param = data;
981 struct probe_finder *pf = param->data; 985 struct probe_finder *pf = param->data;
982 struct perf_probe_point *pp = &pf->pev->point; 986 struct perf_probe_point *pp = &pf->pev->point;
983 Dwarf_Attribute attr;
984 987
985 /* Check tag and diename */ 988 /* Check tag and diename */
986 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 989 if (!die_is_func_def(sp_die) ||
987 !die_compare_name(sp_die, pp->function) || 990 !die_compare_name(sp_die, pp->function))
988 dwarf_attr(sp_die, DW_AT_declaration, &attr))
989 return DWARF_CB_OK; 991 return DWARF_CB_OK;
990 992
991 /* Check declared file */ 993 /* Check declared file */
@@ -1151,7 +1153,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1151 tev = &tf->tevs[tf->ntevs++]; 1153 tev = &tf->tevs[tf->ntevs++];
1152 1154
1153 /* Trace point should be converted from subprogram DIE */ 1155 /* Trace point should be converted from subprogram DIE */
1154 ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1156 ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
1155 pf->pev->point.retprobe, &tev->point); 1157 pf->pev->point.retprobe, &tev->point);
1156 if (ret < 0) 1158 if (ret < 0)
1157 return ret; 1159 return ret;
@@ -1183,7 +1185,7 @@ int debuginfo__find_trace_events(struct debuginfo *self,
1183{ 1185{
1184 struct trace_event_finder tf = { 1186 struct trace_event_finder tf = {
1185 .pf = {.pev = pev, .callback = add_probe_trace_event}, 1187 .pf = {.pev = pev, .callback = add_probe_trace_event},
1186 .max_tevs = max_tevs}; 1188 .mod = self->mod, .max_tevs = max_tevs};
1187 int ret; 1189 int ret;
1188 1190
1189 /* Allocate result tevs array */ 1191 /* Allocate result tevs array */
@@ -1252,7 +1254,7 @@ static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
1252 vl = &af->vls[af->nvls++]; 1254 vl = &af->vls[af->nvls++];
1253 1255
1254 /* Trace point should be converted from subprogram DIE */ 1256 /* Trace point should be converted from subprogram DIE */
1255 ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1257 ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr,
1256 pf->pev->point.retprobe, &vl->point); 1258 pf->pev->point.retprobe, &vl->point);
1257 if (ret < 0) 1259 if (ret < 0)
1258 return ret; 1260 return ret;
@@ -1291,6 +1293,7 @@ int debuginfo__find_available_vars_at(struct debuginfo *self,
1291{ 1293{
1292 struct available_var_finder af = { 1294 struct available_var_finder af = {
1293 .pf = {.pev = pev, .callback = add_available_vars}, 1295 .pf = {.pev = pev, .callback = add_available_vars},
1296 .mod = self->mod,
1294 .max_vls = max_vls, .externs = externs}; 1297 .max_vls = max_vls, .externs = externs};
1295 int ret; 1298 int ret;
1296 1299
@@ -1474,7 +1477,7 @@ static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
1474 return 0; 1477 return 0;
1475} 1478}
1476 1479
1477/* Search function from function name */ 1480/* Search function definition from function name */
1478static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1481static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1479{ 1482{
1480 struct dwarf_callback_param *param = data; 1483 struct dwarf_callback_param *param = data;
@@ -1485,7 +1488,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1485 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 1488 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
1486 return DWARF_CB_OK; 1489 return DWARF_CB_OK;
1487 1490
1488 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1491 if (die_is_func_def(sp_die) &&
1489 die_compare_name(sp_die, lr->function)) { 1492 die_compare_name(sp_die, lr->function)) {
1490 lf->fname = dwarf_decl_file(sp_die); 1493 lf->fname = dwarf_decl_file(sp_die);
1491 dwarf_decl_line(sp_die, &lr->offset); 1494 dwarf_decl_line(sp_die, &lr->offset);
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 17e94d0c36f9..3b7d63018960 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -23,6 +23,7 @@ static inline int is_c_varname(const char *name)
23/* debug information structure */ 23/* debug information structure */
24struct debuginfo { 24struct debuginfo {
25 Dwarf *dbg; 25 Dwarf *dbg;
26 Dwfl_Module *mod;
26 Dwfl *dwfl; 27 Dwfl *dwfl;
27 Dwarf_Addr bias; 28 Dwarf_Addr bias;
28}; 29};
@@ -77,6 +78,7 @@ struct probe_finder {
77 78
78struct trace_event_finder { 79struct trace_event_finder {
79 struct probe_finder pf; 80 struct probe_finder pf;
81 Dwfl_Module *mod; /* For solving symbols */
80 struct probe_trace_event *tevs; /* Found trace events */ 82 struct probe_trace_event *tevs; /* Found trace events */
81 int ntevs; /* Number of trace events */ 83 int ntevs; /* Number of trace events */
82 int max_tevs; /* Max number of trace events */ 84 int max_tevs; /* Max number of trace events */
@@ -84,6 +86,7 @@ struct trace_event_finder {
84 86
85struct available_var_finder { 87struct available_var_finder {
86 struct probe_finder pf; 88 struct probe_finder pf;
89 Dwfl_Module *mod; /* For solving symbols */
87 struct variable_list *vls; /* Found variable lists */ 90 struct variable_list *vls; /* Found variable lists */
88 int nvls; /* Number of variable lists */ 91 int nvls; /* Number of variable lists */
89 int max_vls; /* Max no. of variable lists */ 92 int max_vls; /* Max no. of variable lists */
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 925e0c3e6d91..71b5412bbbb9 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -8,6 +8,26 @@
8#include "cpumap.h" 8#include "cpumap.h"
9#include "thread_map.h" 9#include "thread_map.h"
10 10
11/*
12 * Support debug printing even though util/debug.c is not linked. That means
13 * implementing 'verbose' and 'eprintf'.
14 */
15int verbose;
16
17int eprintf(int level, const char *fmt, ...)
18{
19 va_list args;
20 int ret = 0;
21
22 if (verbose >= level) {
23 va_start(args, fmt);
24 ret = vfprintf(stderr, fmt, args);
25 va_end(args);
26 }
27
28 return ret;
29}
30
11/* Define PyVarObject_HEAD_INIT for python 2.5 */ 31/* Define PyVarObject_HEAD_INIT for python 2.5 */
12#ifndef PyVarObject_HEAD_INIT 32#ifndef PyVarObject_HEAD_INIT
13# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, 33# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
@@ -967,6 +987,7 @@ static struct {
967 { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ }, 987 { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ },
968 { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS }, 988 { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS },
969 { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS }, 989 { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS },
990 { "COUNT_SW_DUMMY", PERF_COUNT_SW_DUMMY },
970 991
971 { "SAMPLE_IP", PERF_SAMPLE_IP }, 992 { "SAMPLE_IP", PERF_SAMPLE_IP },
972 { "SAMPLE_TID", PERF_SAMPLE_TID }, 993 { "SAMPLE_TID", PERF_SAMPLE_TID },
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
new file mode 100644
index 000000000000..18d73aa2f0f8
--- /dev/null
+++ b/tools/perf/util/record.c
@@ -0,0 +1,108 @@
1#include "evlist.h"
2#include "evsel.h"
3#include "cpumap.h"
4#include "parse-events.h"
5
6typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
7
8static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
9{
10 struct perf_evlist *evlist;
11 struct perf_evsel *evsel;
12 int err = -EAGAIN, fd;
13
14 evlist = perf_evlist__new();
15 if (!evlist)
16 return -ENOMEM;
17
18 if (parse_events(evlist, str))
19 goto out_delete;
20
21 evsel = perf_evlist__first(evlist);
22
23 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
24 if (fd < 0)
25 goto out_delete;
26 close(fd);
27
28 fn(evsel);
29
30 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
31 if (fd < 0) {
32 if (errno == EINVAL)
33 err = -EINVAL;
34 goto out_delete;
35 }
36 close(fd);
37 err = 0;
38
39out_delete:
40 perf_evlist__delete(evlist);
41 return err;
42}
43
44static bool perf_probe_api(setup_probe_fn_t fn)
45{
46 const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL};
47 struct cpu_map *cpus;
48 int cpu, ret, i = 0;
49
50 cpus = cpu_map__new(NULL);
51 if (!cpus)
52 return false;
53 cpu = cpus->map[0];
54 cpu_map__delete(cpus);
55
56 do {
57 ret = perf_do_probe_api(fn, cpu, try[i++]);
58 if (!ret)
59 return true;
60 } while (ret == -EAGAIN && try[i]);
61
62 return false;
63}
64
65static void perf_probe_sample_identifier(struct perf_evsel *evsel)
66{
67 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
68}
69
70bool perf_can_sample_identifier(void)
71{
72 return perf_probe_api(perf_probe_sample_identifier);
73}
74
75void perf_evlist__config(struct perf_evlist *evlist,
76 struct perf_record_opts *opts)
77{
78 struct perf_evsel *evsel;
79 bool use_sample_identifier = false;
80
81 /*
82 * Set the evsel leader links before we configure attributes,
83 * since some might depend on this info.
84 */
85 if (opts->group)
86 perf_evlist__set_leader(evlist);
87
88 if (evlist->cpus->map[0] < 0)
89 opts->no_inherit = true;
90
91 list_for_each_entry(evsel, &evlist->entries, node)
92 perf_evsel__config(evsel, opts);
93
94 if (evlist->nr_entries > 1) {
95 struct perf_evsel *first = perf_evlist__first(evlist);
96
97 list_for_each_entry(evsel, &evlist->entries, node) {
98 if (evsel->attr.sample_type == first->attr.sample_type)
99 continue;
100 use_sample_identifier = perf_can_sample_identifier();
101 break;
102 }
103 list_for_each_entry(evsel, &evlist->entries, node)
104 perf_evsel__set_sample_id(evsel, use_sample_identifier);
105 }
106
107 perf_evlist__set_id_pos(evlist);
108}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index eacec859f299..a85e4ae5f3ac 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -261,7 +261,8 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
261 struct perf_sample *sample, 261 struct perf_sample *sample,
262 struct perf_evsel *evsel, 262 struct perf_evsel *evsel,
263 struct machine *machine __maybe_unused, 263 struct machine *machine __maybe_unused,
264 struct addr_location *al) 264 struct thread *thread,
265 struct addr_location *al)
265{ 266{
266 struct format_field *field; 267 struct format_field *field;
267 static char handler[256]; 268 static char handler[256];
@@ -272,7 +273,6 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
272 int cpu = sample->cpu; 273 int cpu = sample->cpu;
273 void *data = sample->raw_data; 274 void *data = sample->raw_data;
274 unsigned long long nsecs = sample->time; 275 unsigned long long nsecs = sample->time;
275 struct thread *thread = al->thread;
276 char *comm = thread->comm; 276 char *comm = thread->comm;
277 277
278 dSP; 278 dSP;
@@ -351,7 +351,8 @@ static void perl_process_event_generic(union perf_event *event,
351 struct perf_sample *sample, 351 struct perf_sample *sample,
352 struct perf_evsel *evsel, 352 struct perf_evsel *evsel,
353 struct machine *machine __maybe_unused, 353 struct machine *machine __maybe_unused,
354 struct addr_location *al __maybe_unused) 354 struct thread *thread __maybe_unused,
355 struct addr_location *al __maybe_unused)
355{ 356{
356 dSP; 357 dSP;
357 358
@@ -377,10 +378,11 @@ static void perl_process_event(union perf_event *event,
377 struct perf_sample *sample, 378 struct perf_sample *sample,
378 struct perf_evsel *evsel, 379 struct perf_evsel *evsel,
379 struct machine *machine, 380 struct machine *machine,
380 struct addr_location *al) 381 struct thread *thread,
382 struct addr_location *al)
381{ 383{
382 perl_process_tracepoint(event, sample, evsel, machine, al); 384 perl_process_tracepoint(event, sample, evsel, machine, thread, al);
383 perl_process_event_generic(event, sample, evsel, machine, al); 385 perl_process_event_generic(event, sample, evsel, machine, thread, al);
384} 386}
385 387
386static void run_start_sub(void) 388static void run_start_sub(void)
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index e87aa5d9696b..cc75a3cef388 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -225,6 +225,7 @@ static void python_process_tracepoint(union perf_event *perf_event
225 struct perf_sample *sample, 225 struct perf_sample *sample,
226 struct perf_evsel *evsel, 226 struct perf_evsel *evsel,
227 struct machine *machine __maybe_unused, 227 struct machine *machine __maybe_unused,
228 struct thread *thread,
228 struct addr_location *al) 229 struct addr_location *al)
229{ 230{
230 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 231 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
@@ -238,7 +239,6 @@ static void python_process_tracepoint(union perf_event *perf_event
238 int cpu = sample->cpu; 239 int cpu = sample->cpu;
239 void *data = sample->raw_data; 240 void *data = sample->raw_data;
240 unsigned long long nsecs = sample->time; 241 unsigned long long nsecs = sample->time;
241 struct thread *thread = al->thread;
242 char *comm = thread->comm; 242 char *comm = thread->comm;
243 243
244 t = PyTuple_New(MAX_FIELDS); 244 t = PyTuple_New(MAX_FIELDS);
@@ -345,12 +345,12 @@ static void python_process_general_event(union perf_event *perf_event
345 struct perf_sample *sample, 345 struct perf_sample *sample,
346 struct perf_evsel *evsel, 346 struct perf_evsel *evsel,
347 struct machine *machine __maybe_unused, 347 struct machine *machine __maybe_unused,
348 struct thread *thread,
348 struct addr_location *al) 349 struct addr_location *al)
349{ 350{
350 PyObject *handler, *retval, *t, *dict; 351 PyObject *handler, *retval, *t, *dict;
351 static char handler_name[64]; 352 static char handler_name[64];
352 unsigned n = 0; 353 unsigned n = 0;
353 struct thread *thread = al->thread;
354 354
355 /* 355 /*
356 * Use the MAX_FIELDS to make the function expandable, though 356 * Use the MAX_FIELDS to make the function expandable, though
@@ -404,17 +404,18 @@ static void python_process_event(union perf_event *perf_event,
404 struct perf_sample *sample, 404 struct perf_sample *sample,
405 struct perf_evsel *evsel, 405 struct perf_evsel *evsel,
406 struct machine *machine, 406 struct machine *machine,
407 struct thread *thread,
407 struct addr_location *al) 408 struct addr_location *al)
408{ 409{
409 switch (evsel->attr.type) { 410 switch (evsel->attr.type) {
410 case PERF_TYPE_TRACEPOINT: 411 case PERF_TYPE_TRACEPOINT:
411 python_process_tracepoint(perf_event, sample, evsel, 412 python_process_tracepoint(perf_event, sample, evsel,
412 machine, al); 413 machine, thread, al);
413 break; 414 break;
414 /* Reserve for future process_hw/sw/raw APIs */ 415 /* Reserve for future process_hw/sw/raw APIs */
415 default: 416 default:
416 python_process_general_event(perf_event, sample, evsel, 417 python_process_general_event(perf_event, sample, evsel,
417 machine, al); 418 machine, thread, al);
418 } 419 }
419} 420}
420 421
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index cf1fe01b7e89..70ffa41518f3 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,4 +1,5 @@
1#include <linux/kernel.h> 1#include <linux/kernel.h>
2#include <traceevent/event-parse.h>
2 3
3#include <byteswap.h> 4#include <byteswap.h>
4#include <unistd.h> 5#include <unistd.h>
@@ -12,7 +13,6 @@
12#include "sort.h" 13#include "sort.h"
13#include "util.h" 14#include "util.h"
14#include "cpumap.h" 15#include "cpumap.h"
15#include "event-parse.h"
16#include "perf_regs.h" 16#include "perf_regs.h"
17#include "vdso.h" 17#include "vdso.h"
18 18
@@ -24,7 +24,7 @@ static int perf_session__open(struct perf_session *self, bool force)
24 self->fd_pipe = true; 24 self->fd_pipe = true;
25 self->fd = STDIN_FILENO; 25 self->fd = STDIN_FILENO;
26 26
27 if (perf_session__read_header(self, self->fd) < 0) 27 if (perf_session__read_header(self) < 0)
28 pr_err("incompatible file format (rerun with -v to learn more)"); 28 pr_err("incompatible file format (rerun with -v to learn more)");
29 29
30 return 0; 30 return 0;
@@ -56,7 +56,7 @@ static int perf_session__open(struct perf_session *self, bool force)
56 goto out_close; 56 goto out_close;
57 } 57 }
58 58
59 if (perf_session__read_header(self, self->fd) < 0) { 59 if (perf_session__read_header(self) < 0) {
60 pr_err("incompatible file format (rerun with -v to learn more)"); 60 pr_err("incompatible file format (rerun with -v to learn more)");
61 goto out_close; 61 goto out_close;
62 } 62 }
@@ -71,6 +71,11 @@ static int perf_session__open(struct perf_session *self, bool force)
71 goto out_close; 71 goto out_close;
72 } 72 }
73 73
74 if (!perf_evlist__valid_read_format(self->evlist)) {
75 pr_err("non matching read_format");
76 goto out_close;
77 }
78
74 self->size = input_stat.st_size; 79 self->size = input_stat.st_size;
75 return 0; 80 return 0;
76 81
@@ -193,7 +198,9 @@ void perf_session__delete(struct perf_session *self)
193 vdso__exit(); 198 vdso__exit();
194} 199}
195 200
196static int process_event_synth_tracing_data_stub(union perf_event *event 201static int process_event_synth_tracing_data_stub(struct perf_tool *tool
202 __maybe_unused,
203 union perf_event *event
197 __maybe_unused, 204 __maybe_unused,
198 struct perf_session *session 205 struct perf_session *session
199 __maybe_unused) 206 __maybe_unused)
@@ -202,7 +209,8 @@ static int process_event_synth_tracing_data_stub(union perf_event *event
202 return 0; 209 return 0;
203} 210}
204 211
205static int process_event_synth_attr_stub(union perf_event *event __maybe_unused, 212static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused,
213 union perf_event *event __maybe_unused,
206 struct perf_evlist **pevlist 214 struct perf_evlist **pevlist
207 __maybe_unused) 215 __maybe_unused)
208{ 216{
@@ -238,18 +246,11 @@ static int process_finished_round_stub(struct perf_tool *tool __maybe_unused,
238 return 0; 246 return 0;
239} 247}
240 248
241static int process_event_type_stub(struct perf_tool *tool __maybe_unused,
242 union perf_event *event __maybe_unused)
243{
244 dump_printf(": unhandled!\n");
245 return 0;
246}
247
248static int process_finished_round(struct perf_tool *tool, 249static int process_finished_round(struct perf_tool *tool,
249 union perf_event *event, 250 union perf_event *event,
250 struct perf_session *session); 251 struct perf_session *session);
251 252
252static void perf_tool__fill_defaults(struct perf_tool *tool) 253void perf_tool__fill_defaults(struct perf_tool *tool)
253{ 254{
254 if (tool->sample == NULL) 255 if (tool->sample == NULL)
255 tool->sample = process_event_sample_stub; 256 tool->sample = process_event_sample_stub;
@@ -271,8 +272,6 @@ static void perf_tool__fill_defaults(struct perf_tool *tool)
271 tool->unthrottle = process_event_stub; 272 tool->unthrottle = process_event_stub;
272 if (tool->attr == NULL) 273 if (tool->attr == NULL)
273 tool->attr = process_event_synth_attr_stub; 274 tool->attr = process_event_synth_attr_stub;
274 if (tool->event_type == NULL)
275 tool->event_type = process_event_type_stub;
276 if (tool->tracing_data == NULL) 275 if (tool->tracing_data == NULL)
277 tool->tracing_data = process_event_synth_tracing_data_stub; 276 tool->tracing_data = process_event_synth_tracing_data_stub;
278 if (tool->build_id == NULL) 277 if (tool->build_id == NULL)
@@ -352,6 +351,25 @@ static void perf_event__mmap_swap(union perf_event *event,
352 } 351 }
353} 352}
354 353
354static void perf_event__mmap2_swap(union perf_event *event,
355 bool sample_id_all)
356{
357 event->mmap2.pid = bswap_32(event->mmap2.pid);
358 event->mmap2.tid = bswap_32(event->mmap2.tid);
359 event->mmap2.start = bswap_64(event->mmap2.start);
360 event->mmap2.len = bswap_64(event->mmap2.len);
361 event->mmap2.pgoff = bswap_64(event->mmap2.pgoff);
362 event->mmap2.maj = bswap_32(event->mmap2.maj);
363 event->mmap2.min = bswap_32(event->mmap2.min);
364 event->mmap2.ino = bswap_64(event->mmap2.ino);
365
366 if (sample_id_all) {
367 void *data = &event->mmap2.filename;
368
369 data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
370 swap_sample_id_all(event, data);
371 }
372}
355static void perf_event__task_swap(union perf_event *event, bool sample_id_all) 373static void perf_event__task_swap(union perf_event *event, bool sample_id_all)
356{ 374{
357 event->fork.pid = bswap_32(event->fork.pid); 375 event->fork.pid = bswap_32(event->fork.pid);
@@ -456,6 +474,7 @@ typedef void (*perf_event__swap_op)(union perf_event *event,
456 474
457static perf_event__swap_op perf_event__swap_ops[] = { 475static perf_event__swap_op perf_event__swap_ops[] = {
458 [PERF_RECORD_MMAP] = perf_event__mmap_swap, 476 [PERF_RECORD_MMAP] = perf_event__mmap_swap,
477 [PERF_RECORD_MMAP2] = perf_event__mmap2_swap,
459 [PERF_RECORD_COMM] = perf_event__comm_swap, 478 [PERF_RECORD_COMM] = perf_event__comm_swap,
460 [PERF_RECORD_FORK] = perf_event__task_swap, 479 [PERF_RECORD_FORK] = perf_event__task_swap,
461 [PERF_RECORD_EXIT] = perf_event__task_swap, 480 [PERF_RECORD_EXIT] = perf_event__task_swap,
@@ -496,7 +515,7 @@ static int perf_session_deliver_event(struct perf_session *session,
496 u64 file_offset); 515 u64 file_offset);
497 516
498static int flush_sample_queue(struct perf_session *s, 517static int flush_sample_queue(struct perf_session *s,
499 struct perf_tool *tool) 518 struct perf_tool *tool)
500{ 519{
501 struct ordered_samples *os = &s->ordered_samples; 520 struct ordered_samples *os = &s->ordered_samples;
502 struct list_head *head = &os->samples; 521 struct list_head *head = &os->samples;
@@ -505,12 +524,16 @@ static int flush_sample_queue(struct perf_session *s,
505 u64 limit = os->next_flush; 524 u64 limit = os->next_flush;
506 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; 525 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
507 unsigned idx = 0, progress_next = os->nr_samples / 16; 526 unsigned idx = 0, progress_next = os->nr_samples / 16;
527 bool show_progress = limit == ULLONG_MAX;
508 int ret; 528 int ret;
509 529
510 if (!tool->ordered_samples || !limit) 530 if (!tool->ordered_samples || !limit)
511 return 0; 531 return 0;
512 532
513 list_for_each_entry_safe(iter, tmp, head, list) { 533 list_for_each_entry_safe(iter, tmp, head, list) {
534 if (session_done())
535 return 0;
536
514 if (iter->timestamp > limit) 537 if (iter->timestamp > limit)
515 break; 538 break;
516 539
@@ -527,7 +550,7 @@ static int flush_sample_queue(struct perf_session *s,
527 os->last_flush = iter->timestamp; 550 os->last_flush = iter->timestamp;
528 list_del(&iter->list); 551 list_del(&iter->list);
529 list_add(&iter->list, &os->sample_cache); 552 list_add(&iter->list, &os->sample_cache);
530 if (++idx >= progress_next) { 553 if (show_progress && (++idx >= progress_next)) {
531 progress_next += os->nr_samples / 16; 554 progress_next += os->nr_samples / 16;
532 ui_progress__update(idx, os->nr_samples, 555 ui_progress__update(idx, os->nr_samples,
533 "Processing time ordered events..."); 556 "Processing time ordered events...");
@@ -644,7 +667,7 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s)
644 667
645#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) 668#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue))
646 669
647static int perf_session_queue_event(struct perf_session *s, union perf_event *event, 670int perf_session_queue_event(struct perf_session *s, union perf_event *event,
648 struct perf_sample *sample, u64 file_offset) 671 struct perf_sample *sample, u64 file_offset)
649{ 672{
650 struct ordered_samples *os = &s->ordered_samples; 673 struct ordered_samples *os = &s->ordered_samples;
@@ -740,7 +763,7 @@ static void perf_session__print_tstamp(struct perf_session *session,
740 union perf_event *event, 763 union perf_event *event,
741 struct perf_sample *sample) 764 struct perf_sample *sample)
742{ 765{
743 u64 sample_type = perf_evlist__sample_type(session->evlist); 766 u64 sample_type = __perf_evlist__combined_sample_type(session->evlist);
744 767
745 if (event->header.type != PERF_RECORD_SAMPLE && 768 if (event->header.type != PERF_RECORD_SAMPLE &&
746 !perf_evlist__sample_id_all(session->evlist)) { 769 !perf_evlist__sample_id_all(session->evlist)) {
@@ -755,6 +778,36 @@ static void perf_session__print_tstamp(struct perf_session *session,
755 printf("%" PRIu64 " ", sample->time); 778 printf("%" PRIu64 " ", sample->time);
756} 779}
757 780
781static void sample_read__printf(struct perf_sample *sample, u64 read_format)
782{
783 printf("... sample_read:\n");
784
785 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
786 printf("...... time enabled %016" PRIx64 "\n",
787 sample->read.time_enabled);
788
789 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
790 printf("...... time running %016" PRIx64 "\n",
791 sample->read.time_running);
792
793 if (read_format & PERF_FORMAT_GROUP) {
794 u64 i;
795
796 printf(".... group nr %" PRIu64 "\n", sample->read.group.nr);
797
798 for (i = 0; i < sample->read.group.nr; i++) {
799 struct sample_read_value *value;
800
801 value = &sample->read.group.values[i];
802 printf("..... id %016" PRIx64
803 ", value %016" PRIx64 "\n",
804 value->id, value->value);
805 }
806 } else
807 printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n",
808 sample->read.one.id, sample->read.one.value);
809}
810
758static void dump_event(struct perf_session *session, union perf_event *event, 811static void dump_event(struct perf_session *session, union perf_event *event,
759 u64 file_offset, struct perf_sample *sample) 812 u64 file_offset, struct perf_sample *sample)
760{ 813{
@@ -804,11 +857,15 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
804 857
805 if (sample_type & PERF_SAMPLE_DATA_SRC) 858 if (sample_type & PERF_SAMPLE_DATA_SRC)
806 printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); 859 printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
860
861 if (sample_type & PERF_SAMPLE_READ)
862 sample_read__printf(sample, evsel->attr.read_format);
807} 863}
808 864
809static struct machine * 865static struct machine *
810 perf_session__find_machine_for_cpumode(struct perf_session *session, 866 perf_session__find_machine_for_cpumode(struct perf_session *session,
811 union perf_event *event) 867 union perf_event *event,
868 struct perf_sample *sample)
812{ 869{
813 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 870 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
814 871
@@ -817,10 +874,11 @@ static struct machine *
817 (cpumode == PERF_RECORD_MISC_GUEST_USER))) { 874 (cpumode == PERF_RECORD_MISC_GUEST_USER))) {
818 u32 pid; 875 u32 pid;
819 876
820 if (event->header.type == PERF_RECORD_MMAP) 877 if (event->header.type == PERF_RECORD_MMAP
878 || event->header.type == PERF_RECORD_MMAP2)
821 pid = event->mmap.pid; 879 pid = event->mmap.pid;
822 else 880 else
823 pid = event->ip.pid; 881 pid = sample->pid;
824 882
825 return perf_session__findnew_machine(session, pid); 883 return perf_session__findnew_machine(session, pid);
826 } 884 }
@@ -828,6 +886,75 @@ static struct machine *
828 return &session->machines.host; 886 return &session->machines.host;
829} 887}
830 888
889static int deliver_sample_value(struct perf_session *session,
890 struct perf_tool *tool,
891 union perf_event *event,
892 struct perf_sample *sample,
893 struct sample_read_value *v,
894 struct machine *machine)
895{
896 struct perf_sample_id *sid;
897
898 sid = perf_evlist__id2sid(session->evlist, v->id);
899 if (sid) {
900 sample->id = v->id;
901 sample->period = v->value - sid->period;
902 sid->period = v->value;
903 }
904
905 if (!sid || sid->evsel == NULL) {
906 ++session->stats.nr_unknown_id;
907 return 0;
908 }
909
910 return tool->sample(tool, event, sample, sid->evsel, machine);
911}
912
913static int deliver_sample_group(struct perf_session *session,
914 struct perf_tool *tool,
915 union perf_event *event,
916 struct perf_sample *sample,
917 struct machine *machine)
918{
919 int ret = -EINVAL;
920 u64 i;
921
922 for (i = 0; i < sample->read.group.nr; i++) {
923 ret = deliver_sample_value(session, tool, event, sample,
924 &sample->read.group.values[i],
925 machine);
926 if (ret)
927 break;
928 }
929
930 return ret;
931}
932
933static int
934perf_session__deliver_sample(struct perf_session *session,
935 struct perf_tool *tool,
936 union perf_event *event,
937 struct perf_sample *sample,
938 struct perf_evsel *evsel,
939 struct machine *machine)
940{
941 /* We know evsel != NULL. */
942 u64 sample_type = evsel->attr.sample_type;
943 u64 read_format = evsel->attr.read_format;
944
945 /* Standard sample delievery. */
946 if (!(sample_type & PERF_SAMPLE_READ))
947 return tool->sample(tool, event, sample, evsel, machine);
948
949 /* For PERF_SAMPLE_READ we have either single or group mode. */
950 if (read_format & PERF_FORMAT_GROUP)
951 return deliver_sample_group(session, tool, event, sample,
952 machine);
953 else
954 return deliver_sample_value(session, tool, event, sample,
955 &sample->read.one, machine);
956}
957
831static int perf_session_deliver_event(struct perf_session *session, 958static int perf_session_deliver_event(struct perf_session *session,
832 union perf_event *event, 959 union perf_event *event,
833 struct perf_sample *sample, 960 struct perf_sample *sample,
@@ -857,7 +984,8 @@ static int perf_session_deliver_event(struct perf_session *session,
857 hists__inc_nr_events(&evsel->hists, event->header.type); 984 hists__inc_nr_events(&evsel->hists, event->header.type);
858 } 985 }
859 986
860 machine = perf_session__find_machine_for_cpumode(session, event); 987 machine = perf_session__find_machine_for_cpumode(session, event,
988 sample);
861 989
862 switch (event->header.type) { 990 switch (event->header.type) {
863 case PERF_RECORD_SAMPLE: 991 case PERF_RECORD_SAMPLE:
@@ -870,9 +998,12 @@ static int perf_session_deliver_event(struct perf_session *session,
870 ++session->stats.nr_unprocessable_samples; 998 ++session->stats.nr_unprocessable_samples;
871 return 0; 999 return 0;
872 } 1000 }
873 return tool->sample(tool, event, sample, evsel, machine); 1001 return perf_session__deliver_sample(session, tool, event,
1002 sample, evsel, machine);
874 case PERF_RECORD_MMAP: 1003 case PERF_RECORD_MMAP:
875 return tool->mmap(tool, event, sample, machine); 1004 return tool->mmap(tool, event, sample, machine);
1005 case PERF_RECORD_MMAP2:
1006 return tool->mmap2(tool, event, sample, machine);
876 case PERF_RECORD_COMM: 1007 case PERF_RECORD_COMM:
877 return tool->comm(tool, event, sample, machine); 1008 return tool->comm(tool, event, sample, machine);
878 case PERF_RECORD_FORK: 1009 case PERF_RECORD_FORK:
@@ -895,22 +1026,6 @@ static int perf_session_deliver_event(struct perf_session *session,
895 } 1026 }
896} 1027}
897 1028
898static int perf_session__preprocess_sample(struct perf_session *session,
899 union perf_event *event, struct perf_sample *sample)
900{
901 if (event->header.type != PERF_RECORD_SAMPLE ||
902 !(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN))
903 return 0;
904
905 if (!ip_callchain__valid(sample->callchain, event)) {
906 pr_debug("call-chain problem with event, skipping it.\n");
907 ++session->stats.nr_invalid_chains;
908 session->stats.total_invalid_chains += sample->period;
909 return -EINVAL;
910 }
911 return 0;
912}
913
914static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 1029static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
915 struct perf_tool *tool, u64 file_offset) 1030 struct perf_tool *tool, u64 file_offset)
916{ 1031{
@@ -921,16 +1036,14 @@ static int perf_session__process_user_event(struct perf_session *session, union
921 /* These events are processed right away */ 1036 /* These events are processed right away */
922 switch (event->header.type) { 1037 switch (event->header.type) {
923 case PERF_RECORD_HEADER_ATTR: 1038 case PERF_RECORD_HEADER_ATTR:
924 err = tool->attr(event, &session->evlist); 1039 err = tool->attr(tool, event, &session->evlist);
925 if (err == 0) 1040 if (err == 0)
926 perf_session__set_id_hdr_size(session); 1041 perf_session__set_id_hdr_size(session);
927 return err; 1042 return err;
928 case PERF_RECORD_HEADER_EVENT_TYPE:
929 return tool->event_type(tool, event);
930 case PERF_RECORD_HEADER_TRACING_DATA: 1043 case PERF_RECORD_HEADER_TRACING_DATA:
931 /* setup for reading amidst mmap */ 1044 /* setup for reading amidst mmap */
932 lseek(session->fd, file_offset, SEEK_SET); 1045 lseek(session->fd, file_offset, SEEK_SET);
933 return tool->tracing_data(event, session); 1046 return tool->tracing_data(tool, event, session);
934 case PERF_RECORD_HEADER_BUILD_ID: 1047 case PERF_RECORD_HEADER_BUILD_ID:
935 return tool->build_id(tool, event, session); 1048 return tool->build_id(tool, event, session);
936 case PERF_RECORD_FINISHED_ROUND: 1049 case PERF_RECORD_FINISHED_ROUND:
@@ -975,10 +1088,6 @@ static int perf_session__process_event(struct perf_session *session,
975 if (ret) 1088 if (ret)
976 return ret; 1089 return ret;
977 1090
978 /* Preprocess sample records - precheck callchains */
979 if (perf_session__preprocess_sample(session, event, &sample))
980 return 0;
981
982 if (tool->ordered_samples) { 1091 if (tool->ordered_samples) {
983 ret = perf_session_queue_event(session, event, &sample, 1092 ret = perf_session_queue_event(session, event, &sample,
984 file_offset); 1093 file_offset);
@@ -999,7 +1108,7 @@ void perf_event_header__bswap(struct perf_event_header *self)
999 1108
1000struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 1109struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1001{ 1110{
1002 return machine__findnew_thread(&session->machines.host, pid); 1111 return machine__findnew_thread(&session->machines.host, 0, pid);
1003} 1112}
1004 1113
1005static struct thread *perf_session__register_idle_thread(struct perf_session *self) 1114static struct thread *perf_session__register_idle_thread(struct perf_session *self)
@@ -1054,7 +1163,6 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
1054 } 1163 }
1055} 1164}
1056 1165
1057#define session_done() (*(volatile int *)(&session_done))
1058volatile int session_done; 1166volatile int session_done;
1059 1167
1060static int __perf_session__process_pipe_events(struct perf_session *self, 1168static int __perf_session__process_pipe_events(struct perf_session *self,
@@ -1091,8 +1199,10 @@ more:
1091 perf_event_header__bswap(&event->header); 1199 perf_event_header__bswap(&event->header);
1092 1200
1093 size = event->header.size; 1201 size = event->header.size;
1094 if (size == 0) 1202 if (size < sizeof(struct perf_event_header)) {
1095 size = 8; 1203 pr_err("bad event header size\n");
1204 goto out_err;
1205 }
1096 1206
1097 if (size > cur_size) { 1207 if (size > cur_size) {
1098 void *new = realloc(buf, size); 1208 void *new = realloc(buf, size);
@@ -1161,8 +1271,12 @@ fetch_mmaped_event(struct perf_session *session,
1161 if (session->header.needs_swap) 1271 if (session->header.needs_swap)
1162 perf_event_header__bswap(&event->header); 1272 perf_event_header__bswap(&event->header);
1163 1273
1164 if (head + event->header.size > mmap_size) 1274 if (head + event->header.size > mmap_size) {
1275 /* We're not fetching the event so swap back again */
1276 if (session->header.needs_swap)
1277 perf_event_header__bswap(&event->header);
1165 return NULL; 1278 return NULL;
1279 }
1166 1280
1167 return event; 1281 return event;
1168} 1282}
@@ -1242,7 +1356,7 @@ more:
1242 1356
1243 size = event->header.size; 1357 size = event->header.size;
1244 1358
1245 if (size == 0 || 1359 if (size < sizeof(struct perf_event_header) ||
1246 perf_session__process_event(session, event, tool, file_pos) < 0) { 1360 perf_session__process_event(session, event, tool, file_pos) < 0) {
1247 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", 1361 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1248 file_offset + head, event->header.size, 1362 file_offset + head, event->header.size,
@@ -1260,10 +1374,13 @@ more:
1260 "Processing events..."); 1374 "Processing events...");
1261 } 1375 }
1262 1376
1377 err = 0;
1378 if (session_done())
1379 goto out_err;
1380
1263 if (file_pos < file_size) 1381 if (file_pos < file_size)
1264 goto more; 1382 goto more;
1265 1383
1266 err = 0;
1267 /* do the final flush for ordered samples */ 1384 /* do the final flush for ordered samples */
1268 session->ordered_samples.next_flush = ULLONG_MAX; 1385 session->ordered_samples.next_flush = ULLONG_MAX;
1269 err = flush_sample_queue(session, tool); 1386 err = flush_sample_queue(session, tool);
@@ -1295,12 +1412,15 @@ int perf_session__process_events(struct perf_session *self,
1295 1412
1296bool perf_session__has_traces(struct perf_session *session, const char *msg) 1413bool perf_session__has_traces(struct perf_session *session, const char *msg)
1297{ 1414{
1298 if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) { 1415 struct perf_evsel *evsel;
1299 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg); 1416
1300 return false; 1417 list_for_each_entry(evsel, &session->evlist->entries, node) {
1418 if (evsel->attr.type == PERF_TYPE_TRACEPOINT)
1419 return true;
1301 } 1420 }
1302 1421
1303 return true; 1422 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
1423 return false;
1304} 1424}
1305 1425
1306int maps__set_kallsyms_ref_reloc_sym(struct map **maps, 1426int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
@@ -1383,13 +1503,18 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1383 1503
1384void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, 1504void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1385 struct perf_sample *sample, struct machine *machine, 1505 struct perf_sample *sample, struct machine *machine,
1386 int print_sym, int print_dso, int print_symoffset) 1506 unsigned int print_opts, unsigned int stack_depth)
1387{ 1507{
1388 struct addr_location al; 1508 struct addr_location al;
1389 struct callchain_cursor_node *node; 1509 struct callchain_cursor_node *node;
1390 1510 int print_ip = print_opts & PRINT_IP_OPT_IP;
1391 if (perf_event__preprocess_sample(event, machine, &al, sample, 1511 int print_sym = print_opts & PRINT_IP_OPT_SYM;
1392 NULL) < 0) { 1512 int print_dso = print_opts & PRINT_IP_OPT_DSO;
1513 int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET;
1514 int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
1515 char s = print_oneline ? ' ' : '\t';
1516
1517 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
1393 error("problem processing %d event, skipping it.\n", 1518 error("problem processing %d event, skipping it.\n",
1394 event->header.type); 1519 event->header.type);
1395 return; 1520 return;
@@ -1397,37 +1522,50 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1397 1522
1398 if (symbol_conf.use_callchain && sample->callchain) { 1523 if (symbol_conf.use_callchain && sample->callchain) {
1399 1524
1400
1401 if (machine__resolve_callchain(machine, evsel, al.thread, 1525 if (machine__resolve_callchain(machine, evsel, al.thread,
1402 sample, NULL) != 0) { 1526 sample, NULL, NULL) != 0) {
1403 if (verbose) 1527 if (verbose)
1404 error("Failed to resolve callchain. Skipping\n"); 1528 error("Failed to resolve callchain. Skipping\n");
1405 return; 1529 return;
1406 } 1530 }
1407 callchain_cursor_commit(&callchain_cursor); 1531 callchain_cursor_commit(&callchain_cursor);
1408 1532
1409 while (1) { 1533 while (stack_depth) {
1410 node = callchain_cursor_current(&callchain_cursor); 1534 node = callchain_cursor_current(&callchain_cursor);
1411 if (!node) 1535 if (!node)
1412 break; 1536 break;
1413 1537
1414 printf("\t%16" PRIx64, node->ip); 1538 if (print_ip)
1539 printf("%c%16" PRIx64, s, node->ip);
1540
1415 if (print_sym) { 1541 if (print_sym) {
1416 printf(" "); 1542 printf(" ");
1417 symbol__fprintf_symname(node->sym, stdout); 1543 if (print_symoffset) {
1544 al.addr = node->ip;
1545 al.map = node->map;
1546 symbol__fprintf_symname_offs(node->sym, &al, stdout);
1547 } else
1548 symbol__fprintf_symname(node->sym, stdout);
1418 } 1549 }
1550
1419 if (print_dso) { 1551 if (print_dso) {
1420 printf(" ("); 1552 printf(" (");
1421 map__fprintf_dsoname(node->map, stdout); 1553 map__fprintf_dsoname(node->map, stdout);
1422 printf(")"); 1554 printf(")");
1423 } 1555 }
1424 printf("\n"); 1556
1557 if (!print_oneline)
1558 printf("\n");
1425 1559
1426 callchain_cursor_advance(&callchain_cursor); 1560 callchain_cursor_advance(&callchain_cursor);
1561
1562 stack_depth--;
1427 } 1563 }
1428 1564
1429 } else { 1565 } else {
1430 printf("%16" PRIx64, sample->ip); 1566 if (print_ip)
1567 printf("%16" PRIx64, sample->ip);
1568
1431 if (print_sym) { 1569 if (print_sym) {
1432 printf(" "); 1570 printf(" ");
1433 if (print_symoffset) 1571 if (print_symoffset)
@@ -1510,52 +1648,26 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
1510 const struct perf_evsel_str_handler *assocs, 1648 const struct perf_evsel_str_handler *assocs,
1511 size_t nr_assocs) 1649 size_t nr_assocs)
1512{ 1650{
1513 struct perf_evlist *evlist = session->evlist;
1514 struct event_format *format;
1515 struct perf_evsel *evsel; 1651 struct perf_evsel *evsel;
1516 char *tracepoint, *name;
1517 size_t i; 1652 size_t i;
1518 int err; 1653 int err;
1519 1654
1520 for (i = 0; i < nr_assocs; i++) { 1655 for (i = 0; i < nr_assocs; i++) {
1521 err = -ENOMEM; 1656 /*
1522 tracepoint = strdup(assocs[i].name); 1657 * Adding a handler for an event not in the session,
1523 if (tracepoint == NULL) 1658 * just ignore it.
1524 goto out; 1659 */
1525 1660 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, assocs[i].name);
1526 err = -ENOENT;
1527 name = strchr(tracepoint, ':');
1528 if (name == NULL)
1529 goto out_free;
1530
1531 *name++ = '\0';
1532 format = pevent_find_event_by_name(session->pevent,
1533 tracepoint, name);
1534 if (format == NULL) {
1535 /*
1536 * Adding a handler for an event not in the session,
1537 * just ignore it.
1538 */
1539 goto next;
1540 }
1541
1542 evsel = perf_evlist__find_tracepoint_by_id(evlist, format->id);
1543 if (evsel == NULL) 1661 if (evsel == NULL)
1544 goto next; 1662 continue;
1545 1663
1546 err = -EEXIST; 1664 err = -EEXIST;
1547 if (evsel->handler.func != NULL) 1665 if (evsel->handler.func != NULL)
1548 goto out_free; 1666 goto out;
1549 evsel->handler.func = assocs[i].handler; 1667 evsel->handler.func = assocs[i].handler;
1550next:
1551 free(tracepoint);
1552 } 1668 }
1553 1669
1554 err = 0; 1670 err = 0;
1555out: 1671out:
1556 return err; 1672 return err;
1557
1558out_free:
1559 free(tracepoint);
1560 goto out;
1561} 1673}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 6b51d47acdba..04bf7373a7e5 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -37,12 +37,16 @@ struct perf_session {
37 int fd; 37 int fd;
38 bool fd_pipe; 38 bool fd_pipe;
39 bool repipe; 39 bool repipe;
40 int cwdlen;
41 char *cwd;
42 struct ordered_samples ordered_samples; 40 struct ordered_samples ordered_samples;
43 char filename[1]; 41 char filename[1];
44}; 42};
45 43
44#define PRINT_IP_OPT_IP (1<<0)
45#define PRINT_IP_OPT_SYM (1<<1)
46#define PRINT_IP_OPT_DSO (1<<2)
47#define PRINT_IP_OPT_SYMOFFSET (1<<3)
48#define PRINT_IP_OPT_ONELINE (1<<4)
49
46struct perf_tool; 50struct perf_tool;
47 51
48struct perf_session *perf_session__new(const char *filename, int mode, 52struct perf_session *perf_session__new(const char *filename, int mode,
@@ -58,6 +62,11 @@ int __perf_session__process_events(struct perf_session *self,
58int perf_session__process_events(struct perf_session *self, 62int perf_session__process_events(struct perf_session *self,
59 struct perf_tool *tool); 63 struct perf_tool *tool);
60 64
65int perf_session_queue_event(struct perf_session *s, union perf_event *event,
66 struct perf_sample *sample, u64 file_offset);
67
68void perf_tool__fill_defaults(struct perf_tool *tool);
69
61int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel, 70int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel,
62 struct thread *thread, 71 struct thread *thread,
63 struct ip_callchain *chain, 72 struct ip_callchain *chain,
@@ -100,7 +109,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
100 109
101void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, 110void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
102 struct perf_sample *sample, struct machine *machine, 111 struct perf_sample *sample, struct machine *machine,
103 int print_sym, int print_dso, int print_symoffset); 112 unsigned int print_opts, unsigned int stack_depth);
104 113
105int perf_session__cpu_bitmap(struct perf_session *session, 114int perf_session__cpu_bitmap(struct perf_session *session,
106 const char *cpu_list, unsigned long *cpu_bitmap); 115 const char *cpu_list, unsigned long *cpu_bitmap);
@@ -115,4 +124,8 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
115 124
116#define perf_session__set_tracepoints_handlers(session, array) \ 125#define perf_session__set_tracepoints_handlers(session, array) \
117 __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array)) 126 __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array))
127
128extern volatile int session_done;
129
130#define session_done() (*(volatile int *)(&session_done))
118#endif /* __PERF_SESSION_H */ 131#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 6b0ed322907e..58ea5ca6c255 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -18,8 +18,9 @@ class install_lib(_install_lib):
18 self.build_dir = build_lib 18 self.build_dir = build_lib
19 19
20 20
21cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] 21cflags = getenv('CFLAGS', '').split()
22cflags += getenv('CFLAGS', '').split() 22# switch off several checks (need to be at the end of cflags list)
23cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ]
23 24
24build_lib = getenv('PYTHON_EXTBUILD_LIB') 25build_lib = getenv('PYTHON_EXTBUILD_LIB')
25build_tmp = getenv('PYTHON_EXTBUILD_TMP') 26build_tmp = getenv('PYTHON_EXTBUILD_TMP')
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 5f52d492590c..5f118a089519 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,15 +1,18 @@
1#include "sort.h" 1#include "sort.h"
2#include "hist.h" 2#include "hist.h"
3#include "symbol.h"
3 4
4regex_t parent_regex; 5regex_t parent_regex;
5const char default_parent_pattern[] = "^sys_|^do_page_fault"; 6const char default_parent_pattern[] = "^sys_|^do_page_fault";
6const char *parent_pattern = default_parent_pattern; 7const char *parent_pattern = default_parent_pattern;
7const char default_sort_order[] = "comm,dso,symbol"; 8const char default_sort_order[] = "comm,dso,symbol";
8const char *sort_order = default_sort_order; 9const char *sort_order = default_sort_order;
10regex_t ignore_callees_regex;
11int have_ignore_callees = 0;
9int sort__need_collapse = 0; 12int sort__need_collapse = 0;
10int sort__has_parent = 0; 13int sort__has_parent = 0;
11int sort__has_sym = 0; 14int sort__has_sym = 0;
12int sort__branch_mode = -1; /* -1 = means not set */ 15enum sort_mode sort__mode = SORT_MODE__NORMAL;
13 16
14enum sort_type sort__first_dimension; 17enum sort_type sort__first_dimension;
15 18
@@ -54,14 +57,14 @@ static int64_t cmp_null(void *l, void *r)
54static int64_t 57static int64_t
55sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) 58sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
56{ 59{
57 return right->thread->pid - left->thread->pid; 60 return right->thread->tid - left->thread->tid;
58} 61}
59 62
60static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, 63static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
61 size_t size, unsigned int width) 64 size_t size, unsigned int width)
62{ 65{
63 return repsep_snprintf(bf, size, "%*s:%5d", width - 6, 66 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
64 self->thread->comm ?: "", self->thread->pid); 67 self->thread->comm ?: "", self->thread->tid);
65} 68}
66 69
67struct sort_entry sort_thread = { 70struct sort_entry sort_thread = {
@@ -76,7 +79,7 @@ struct sort_entry sort_thread = {
76static int64_t 79static int64_t
77sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 80sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
78{ 81{
79 return right->thread->pid - left->thread->pid; 82 return right->thread->tid - left->thread->tid;
80} 83}
81 84
82static int64_t 85static int64_t
@@ -194,7 +197,7 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
194 if (verbose) { 197 if (verbose) {
195 char o = map ? dso__symtab_origin(map->dso) : '!'; 198 char o = map ? dso__symtab_origin(map->dso) : '!';
196 ret += repsep_snprintf(bf, size, "%-#*llx %c ", 199 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
197 BITS_PER_LONG / 4, ip, o); 200 BITS_PER_LONG / 4 + 2, ip, o);
198 } 201 }
199 202
200 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); 203 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
@@ -873,12 +876,6 @@ static struct sort_dimension common_sort_dimensions[] = {
873 DIM(SORT_SRCLINE, "srcline", sort_srcline), 876 DIM(SORT_SRCLINE, "srcline", sort_srcline),
874 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), 877 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
875 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 878 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
876 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
877 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
878 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
879 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
880 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
881 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
882}; 879};
883 880
884#undef DIM 881#undef DIM
@@ -895,6 +892,34 @@ static struct sort_dimension bstack_sort_dimensions[] = {
895 892
896#undef DIM 893#undef DIM
897 894
895#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
896
897static struct sort_dimension memory_sort_dimensions[] = {
898 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
899 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
900 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
901 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
902 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
903 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
904};
905
906#undef DIM
907
908static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
909{
910 if (sd->taken)
911 return;
912
913 if (sd->entry->se_collapse)
914 sort__need_collapse = 1;
915
916 if (list_empty(&hist_entry__sort_list))
917 sort__first_dimension = idx;
918
919 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
920 sd->taken = 1;
921}
922
898int sort_dimension__add(const char *tok) 923int sort_dimension__add(const char *tok)
899{ 924{
900 unsigned int i; 925 unsigned int i;
@@ -915,25 +940,11 @@ int sort_dimension__add(const char *tok)
915 return -EINVAL; 940 return -EINVAL;
916 } 941 }
917 sort__has_parent = 1; 942 sort__has_parent = 1;
918 } else if (sd->entry == &sort_sym || 943 } else if (sd->entry == &sort_sym) {
919 sd->entry == &sort_sym_from ||
920 sd->entry == &sort_sym_to ||
921 sd->entry == &sort_mem_daddr_sym) {
922 sort__has_sym = 1; 944 sort__has_sym = 1;
923 } 945 }
924 946
925 if (sd->taken) 947 __sort_dimension__add(sd, i);
926 return 0;
927
928 if (sd->entry->se_collapse)
929 sort__need_collapse = 1;
930
931 if (list_empty(&hist_entry__sort_list))
932 sort__first_dimension = i;
933
934 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
935 sd->taken = 1;
936
937 return 0; 948 return 0;
938 } 949 }
939 950
@@ -943,24 +954,29 @@ int sort_dimension__add(const char *tok)
943 if (strncasecmp(tok, sd->name, strlen(tok))) 954 if (strncasecmp(tok, sd->name, strlen(tok)))
944 continue; 955 continue;
945 956
946 if (sort__branch_mode != 1) 957 if (sort__mode != SORT_MODE__BRANCH)
947 return -EINVAL; 958 return -EINVAL;
948 959
949 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 960 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
950 sort__has_sym = 1; 961 sort__has_sym = 1;
951 962
952 if (sd->taken) 963 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
953 return 0; 964 return 0;
965 }
954 966
955 if (sd->entry->se_collapse) 967 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
956 sort__need_collapse = 1; 968 struct sort_dimension *sd = &memory_sort_dimensions[i];
957 969
958 if (list_empty(&hist_entry__sort_list)) 970 if (strncasecmp(tok, sd->name, strlen(tok)))
959 sort__first_dimension = i + __SORT_BRANCH_STACK; 971 continue;
960 972
961 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 973 if (sort__mode != SORT_MODE__MEMORY)
962 sd->taken = 1; 974 return -EINVAL;
963 975
976 if (sd->entry == &sort_mem_daddr_sym)
977 sort__has_sym = 1;
978
979 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
964 return 0; 980 return 0;
965 } 981 }
966 982
@@ -993,8 +1009,9 @@ int setup_sorting(void)
993 return ret; 1009 return ret;
994} 1010}
995 1011
996void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 1012static void sort_entry__setup_elide(struct sort_entry *self,
997 const char *list_name, FILE *fp) 1013 struct strlist *list,
1014 const char *list_name, FILE *fp)
998{ 1015{
999 if (list && strlist__nr_entries(list) == 1) { 1016 if (list && strlist__nr_entries(list) == 1) {
1000 if (fp != NULL) 1017 if (fp != NULL)
@@ -1003,3 +1020,42 @@ void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
1003 self->elide = true; 1020 self->elide = true;
1004 } 1021 }
1005} 1022}
1023
1024void sort__setup_elide(FILE *output)
1025{
1026 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1027 "dso", output);
1028 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1029 "comm", output);
1030 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1031 "symbol", output);
1032
1033 if (sort__mode == SORT_MODE__BRANCH) {
1034 sort_entry__setup_elide(&sort_dso_from,
1035 symbol_conf.dso_from_list,
1036 "dso_from", output);
1037 sort_entry__setup_elide(&sort_dso_to,
1038 symbol_conf.dso_to_list,
1039 "dso_to", output);
1040 sort_entry__setup_elide(&sort_sym_from,
1041 symbol_conf.sym_from_list,
1042 "sym_from", output);
1043 sort_entry__setup_elide(&sort_sym_to,
1044 symbol_conf.sym_to_list,
1045 "sym_to", output);
1046 } else if (sort__mode == SORT_MODE__MEMORY) {
1047 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1048 "symbol_daddr", output);
1049 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1050 "dso_daddr", output);
1051 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1052 "mem", output);
1053 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1054 "local_weight", output);
1055 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1056 "tlb", output);
1057 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1058 "snoop", output);
1059 }
1060
1061}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index f24bdf64238c..4e80dbd271e7 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -29,10 +29,12 @@ extern const char *sort_order;
29extern const char default_parent_pattern[]; 29extern const char default_parent_pattern[];
30extern const char *parent_pattern; 30extern const char *parent_pattern;
31extern const char default_sort_order[]; 31extern const char default_sort_order[];
32extern regex_t ignore_callees_regex;
33extern int have_ignore_callees;
32extern int sort__need_collapse; 34extern int sort__need_collapse;
33extern int sort__has_parent; 35extern int sort__has_parent;
34extern int sort__has_sym; 36extern int sort__has_sym;
35extern int sort__branch_mode; 37extern enum sort_mode sort__mode;
36extern struct sort_entry sort_comm; 38extern struct sort_entry sort_comm;
37extern struct sort_entry sort_dso; 39extern struct sort_entry sort_dso;
38extern struct sort_entry sort_sym; 40extern struct sort_entry sort_sym;
@@ -87,6 +89,9 @@ struct hist_entry {
87 89
88 struct hist_entry_diff diff; 90 struct hist_entry_diff diff;
89 91
92 /* We are added by hists__add_dummy_entry. */
93 bool dummy;
94
90 /* XXX These two should move to some tree widget lib */ 95 /* XXX These two should move to some tree widget lib */
91 u16 row_offset; 96 u16 row_offset;
92 u16 nr_rows; 97 u16 nr_rows;
@@ -117,12 +122,18 @@ static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he)
117 return NULL; 122 return NULL;
118} 123}
119 124
120static inline void hist_entry__add_pair(struct hist_entry *he, 125static inline void hist_entry__add_pair(struct hist_entry *pair,
121 struct hist_entry *pair) 126 struct hist_entry *he)
122{ 127{
123 list_add_tail(&he->pairs.head, &pair->pairs.node); 128 list_add_tail(&pair->pairs.node, &he->pairs.head);
124} 129}
125 130
131enum sort_mode {
132 SORT_MODE__NORMAL,
133 SORT_MODE__BRANCH,
134 SORT_MODE__MEMORY,
135};
136
126enum sort_type { 137enum sort_type {
127 /* common sort keys */ 138 /* common sort keys */
128 SORT_PID, 139 SORT_PID,
@@ -134,12 +145,6 @@ enum sort_type {
134 SORT_SRCLINE, 145 SORT_SRCLINE,
135 SORT_LOCAL_WEIGHT, 146 SORT_LOCAL_WEIGHT,
136 SORT_GLOBAL_WEIGHT, 147 SORT_GLOBAL_WEIGHT,
137 SORT_MEM_DADDR_SYMBOL,
138 SORT_MEM_DADDR_DSO,
139 SORT_MEM_LOCKED,
140 SORT_MEM_TLB,
141 SORT_MEM_LVL,
142 SORT_MEM_SNOOP,
143 148
144 /* branch stack specific sort keys */ 149 /* branch stack specific sort keys */
145 __SORT_BRANCH_STACK, 150 __SORT_BRANCH_STACK,
@@ -148,6 +153,15 @@ enum sort_type {
148 SORT_SYM_FROM, 153 SORT_SYM_FROM,
149 SORT_SYM_TO, 154 SORT_SYM_TO,
150 SORT_MISPREDICT, 155 SORT_MISPREDICT,
156
157 /* memory mode specific sort keys */
158 __SORT_MEMORY_MODE,
159 SORT_MEM_DADDR_SYMBOL = __SORT_MEMORY_MODE,
160 SORT_MEM_DADDR_DSO,
161 SORT_MEM_LOCKED,
162 SORT_MEM_TLB,
163 SORT_MEM_LVL,
164 SORT_MEM_SNOOP,
151}; 165};
152 166
153/* 167/*
@@ -172,7 +186,8 @@ extern struct list_head hist_entry__sort_list;
172 186
173int setup_sorting(void); 187int setup_sorting(void);
174extern int sort_dimension__add(const char *); 188extern int sort_dimension__add(const char *);
175void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 189void sort__setup_elide(FILE *fp);
176 const char *list_name, FILE *fp); 190
191int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
177 192
178#endif /* __PERF_SORT_H */ 193#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 23742126f47c..6506b3dfb605 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -10,6 +10,12 @@ void update_stats(struct stats *stats, u64 val)
10 delta = val - stats->mean; 10 delta = val - stats->mean;
11 stats->mean += delta / stats->n; 11 stats->mean += delta / stats->n;
12 stats->M2 += delta*(val - stats->mean); 12 stats->M2 += delta*(val - stats->mean);
13
14 if (val > stats->max)
15 stats->max = val;
16
17 if (val < stats->min)
18 stats->min = val;
13} 19}
14 20
15double avg_stats(struct stats *stats) 21double avg_stats(struct stats *stats)
@@ -37,7 +43,7 @@ double stddev_stats(struct stats *stats)
37{ 43{
38 double variance, variance_mean; 44 double variance, variance_mean;
39 45
40 if (!stats->n) 46 if (stats->n < 2)
41 return 0.0; 47 return 0.0;
42 48
43 variance = stats->M2 / (stats->n - 1); 49 variance = stats->M2 / (stats->n - 1);
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 588367c3c767..ae8ccd7227cf 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -6,6 +6,7 @@
6struct stats 6struct stats
7{ 7{
8 double n, mean, M2; 8 double n, mean, M2;
9 u64 max, min;
9}; 10};
10 11
11void update_stats(struct stats *stats, u64 val); 12void update_stats(struct stats *stats, u64 val);
@@ -13,4 +14,12 @@ double avg_stats(struct stats *stats);
13double stddev_stats(struct stats *stats); 14double stddev_stats(struct stats *stats);
14double rel_stddev_stats(double stddev, double avg); 15double rel_stddev_stats(double stddev, double avg);
15 16
17static inline void init_stats(struct stats *stats)
18{
19 stats->n = 0.0;
20 stats->mean = 0.0;
21 stats->M2 = 0.0;
22 stats->min = (u64) -1;
23 stats->max = 0;
24}
16#endif 25#endif
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 29c7b2cb2521..f0b0c008c507 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -387,3 +387,27 @@ void *memdup(const void *src, size_t len)
387 387
388 return p; 388 return p;
389} 389}
390
391/**
392 * str_append - reallocate string and append another
393 * @s: pointer to string pointer
394 * @len: pointer to len (initialized)
395 * @a: string to append.
396 */
397int str_append(char **s, int *len, const char *a)
398{
399 int olen = *s ? strlen(*s) : 0;
400 int nlen = olen + strlen(a) + 1;
401 if (*len < nlen) {
402 *len = *len * 2;
403 if (*len < nlen)
404 *len = nlen;
405 *s = realloc(*s, *len);
406 if (!*s)
407 return -ENOMEM;
408 if (olen == 0)
409 **s = 0;
410 }
411 strcat(*s, a);
412 return 0;
413}
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 4b12bf850325..a9c829be5216 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -8,6 +8,22 @@
8#include "symbol.h" 8#include "symbol.h"
9#include "debug.h" 9#include "debug.h"
10 10
11#ifndef HAVE_ELF_GETPHDRNUM
12static int elf_getphdrnum(Elf *elf, size_t *dst)
13{
14 GElf_Ehdr gehdr;
15 GElf_Ehdr *ehdr;
16
17 ehdr = gelf_getehdr(elf, &gehdr);
18 if (!ehdr)
19 return -1;
20
21 *dst = ehdr->e_phnum;
22
23 return 0;
24}
25#endif
26
11#ifndef NT_GNU_BUILD_ID 27#ifndef NT_GNU_BUILD_ID
12#define NT_GNU_BUILD_ID 3 28#define NT_GNU_BUILD_ID 3
13#endif 29#endif
@@ -599,11 +615,13 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
599 if (dso->kernel == DSO_TYPE_USER) { 615 if (dso->kernel == DSO_TYPE_USER) {
600 GElf_Shdr shdr; 616 GElf_Shdr shdr;
601 ss->adjust_symbols = (ehdr.e_type == ET_EXEC || 617 ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
618 ehdr.e_type == ET_REL ||
602 elf_section_by_name(elf, &ehdr, &shdr, 619 elf_section_by_name(elf, &ehdr, &shdr,
603 ".gnu.prelink_undo", 620 ".gnu.prelink_undo",
604 NULL) != NULL); 621 NULL) != NULL);
605 } else { 622 } else {
606 ss->adjust_symbols = 0; 623 ss->adjust_symbols = ehdr.e_type == ET_EXEC ||
624 ehdr.e_type == ET_REL;
607 } 625 }
608 626
609 ss->name = strdup(name); 627 ss->name = strdup(name);
@@ -624,6 +642,37 @@ out_close:
624 return err; 642 return err;
625} 643}
626 644
645/**
646 * ref_reloc_sym_not_found - has kernel relocation symbol been found.
647 * @kmap: kernel maps and relocation reference symbol
648 *
649 * This function returns %true if we are dealing with the kernel maps and the
650 * relocation reference symbol has not yet been found. Otherwise %false is
651 * returned.
652 */
653static bool ref_reloc_sym_not_found(struct kmap *kmap)
654{
655 return kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
656 !kmap->ref_reloc_sym->unrelocated_addr;
657}
658
659/**
660 * ref_reloc - kernel relocation offset.
661 * @kmap: kernel maps and relocation reference symbol
662 *
663 * This function returns the offset of kernel addresses as determined by using
664 * the relocation reference symbol i.e. if the kernel has not been relocated
665 * then the return value is zero.
666 */
667static u64 ref_reloc(struct kmap *kmap)
668{
669 if (kmap && kmap->ref_reloc_sym &&
670 kmap->ref_reloc_sym->unrelocated_addr)
671 return kmap->ref_reloc_sym->addr -
672 kmap->ref_reloc_sym->unrelocated_addr;
673 return 0;
674}
675
627int dso__load_sym(struct dso *dso, struct map *map, 676int dso__load_sym(struct dso *dso, struct map *map,
628 struct symsrc *syms_ss, struct symsrc *runtime_ss, 677 struct symsrc *syms_ss, struct symsrc *runtime_ss,
629 symbol_filter_t filter, int kmodule) 678 symbol_filter_t filter, int kmodule)
@@ -642,8 +691,17 @@ int dso__load_sym(struct dso *dso, struct map *map,
642 Elf_Scn *sec, *sec_strndx; 691 Elf_Scn *sec, *sec_strndx;
643 Elf *elf; 692 Elf *elf;
644 int nr = 0; 693 int nr = 0;
694 bool remap_kernel = false, adjust_kernel_syms = false;
645 695
646 dso->symtab_type = syms_ss->type; 696 dso->symtab_type = syms_ss->type;
697 dso->rel = syms_ss->ehdr.e_type == ET_REL;
698
699 /*
700 * Modules may already have symbols from kallsyms, but those symbols
701 * have the wrong values for the dso maps, so remove them.
702 */
703 if (kmodule && syms_ss->symtab)
704 symbols__delete(&dso->symbols[map->type]);
647 705
648 if (!syms_ss->symtab) { 706 if (!syms_ss->symtab) {
649 syms_ss->symtab = syms_ss->dynsym; 707 syms_ss->symtab = syms_ss->dynsym;
@@ -681,7 +739,31 @@ int dso__load_sym(struct dso *dso, struct map *map,
681 nr_syms = shdr.sh_size / shdr.sh_entsize; 739 nr_syms = shdr.sh_size / shdr.sh_entsize;
682 740
683 memset(&sym, 0, sizeof(sym)); 741 memset(&sym, 0, sizeof(sym));
684 dso->adjust_symbols = runtime_ss->adjust_symbols; 742
743 /*
744 * The kernel relocation symbol is needed in advance in order to adjust
745 * kernel maps correctly.
746 */
747 if (ref_reloc_sym_not_found(kmap)) {
748 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
749 const char *elf_name = elf_sym__name(&sym, symstrs);
750
751 if (strcmp(elf_name, kmap->ref_reloc_sym->name))
752 continue;
753 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
754 break;
755 }
756 }
757
758 dso->adjust_symbols = runtime_ss->adjust_symbols || ref_reloc(kmap);
759 /*
760 * Initial kernel and module mappings do not map to the dso. For
761 * function mappings, flag the fixups.
762 */
763 if (map->type == MAP__FUNCTION && (dso->kernel || kmodule)) {
764 remap_kernel = true;
765 adjust_kernel_syms = dso->adjust_symbols;
766 }
685 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 767 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
686 struct symbol *f; 768 struct symbol *f;
687 const char *elf_name = elf_sym__name(&sym, symstrs); 769 const char *elf_name = elf_sym__name(&sym, symstrs);
@@ -690,10 +772,6 @@ int dso__load_sym(struct dso *dso, struct map *map,
690 const char *section_name; 772 const char *section_name;
691 bool used_opd = false; 773 bool used_opd = false;
692 774
693 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
694 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
695 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
696
697 if (!is_label && !elf_sym__is_a(&sym, map->type)) 775 if (!is_label && !elf_sym__is_a(&sym, map->type))
698 continue; 776 continue;
699 777
@@ -745,20 +823,55 @@ int dso__load_sym(struct dso *dso, struct map *map,
745 (sym.st_value & 1)) 823 (sym.st_value & 1))
746 --sym.st_value; 824 --sym.st_value;
747 825
748 if (dso->kernel != DSO_TYPE_USER || kmodule) { 826 if (dso->kernel || kmodule) {
749 char dso_name[PATH_MAX]; 827 char dso_name[PATH_MAX];
750 828
829 /* Adjust symbol to map to file offset */
830 if (adjust_kernel_syms)
831 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
832
751 if (strcmp(section_name, 833 if (strcmp(section_name,
752 (curr_dso->short_name + 834 (curr_dso->short_name +
753 dso->short_name_len)) == 0) 835 dso->short_name_len)) == 0)
754 goto new_symbol; 836 goto new_symbol;
755 837
756 if (strcmp(section_name, ".text") == 0) { 838 if (strcmp(section_name, ".text") == 0) {
839 /*
840 * The initial kernel mapping is based on
841 * kallsyms and identity maps. Overwrite it to
842 * map to the kernel dso.
843 */
844 if (remap_kernel && dso->kernel) {
845 remap_kernel = false;
846 map->start = shdr.sh_addr +
847 ref_reloc(kmap);
848 map->end = map->start + shdr.sh_size;
849 map->pgoff = shdr.sh_offset;
850 map->map_ip = map__map_ip;
851 map->unmap_ip = map__unmap_ip;
852 /* Ensure maps are correctly ordered */
853 map_groups__remove(kmap->kmaps, map);
854 map_groups__insert(kmap->kmaps, map);
855 }
856
857 /*
858 * The initial module mapping is based on
859 * /proc/modules mapped to offset zero.
860 * Overwrite it to map to the module dso.
861 */
862 if (remap_kernel && kmodule) {
863 remap_kernel = false;
864 map->pgoff = shdr.sh_offset;
865 }
866
757 curr_map = map; 867 curr_map = map;
758 curr_dso = dso; 868 curr_dso = dso;
759 goto new_symbol; 869 goto new_symbol;
760 } 870 }
761 871
872 if (!kmap)
873 goto new_symbol;
874
762 snprintf(dso_name, sizeof(dso_name), 875 snprintf(dso_name, sizeof(dso_name),
763 "%s%s", dso->short_name, section_name); 876 "%s%s", dso->short_name, section_name);
764 877
@@ -781,8 +894,16 @@ int dso__load_sym(struct dso *dso, struct map *map,
781 dso__delete(curr_dso); 894 dso__delete(curr_dso);
782 goto out_elf_end; 895 goto out_elf_end;
783 } 896 }
784 curr_map->map_ip = identity__map_ip; 897 if (adjust_kernel_syms) {
785 curr_map->unmap_ip = identity__map_ip; 898 curr_map->start = shdr.sh_addr +
899 ref_reloc(kmap);
900 curr_map->end = curr_map->start +
901 shdr.sh_size;
902 curr_map->pgoff = shdr.sh_offset;
903 } else {
904 curr_map->map_ip = identity__map_ip;
905 curr_map->unmap_ip = identity__map_ip;
906 }
786 curr_dso->symtab_type = dso->symtab_type; 907 curr_dso->symtab_type = dso->symtab_type;
787 map_groups__insert(kmap->kmaps, curr_map); 908 map_groups__insert(kmap->kmaps, curr_map);
788 dsos__add(&dso->node, curr_dso); 909 dsos__add(&dso->node, curr_dso);
@@ -846,6 +967,57 @@ out_elf_end:
846 return err; 967 return err;
847} 968}
848 969
970static int elf_read_maps(Elf *elf, bool exe, mapfn_t mapfn, void *data)
971{
972 GElf_Phdr phdr;
973 size_t i, phdrnum;
974 int err;
975 u64 sz;
976
977 if (elf_getphdrnum(elf, &phdrnum))
978 return -1;
979
980 for (i = 0; i < phdrnum; i++) {
981 if (gelf_getphdr(elf, i, &phdr) == NULL)
982 return -1;
983 if (phdr.p_type != PT_LOAD)
984 continue;
985 if (exe) {
986 if (!(phdr.p_flags & PF_X))
987 continue;
988 } else {
989 if (!(phdr.p_flags & PF_R))
990 continue;
991 }
992 sz = min(phdr.p_memsz, phdr.p_filesz);
993 if (!sz)
994 continue;
995 err = mapfn(phdr.p_vaddr, sz, phdr.p_offset, data);
996 if (err)
997 return err;
998 }
999 return 0;
1000}
1001
1002int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
1003 bool *is_64_bit)
1004{
1005 int err;
1006 Elf *elf;
1007
1008 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1009 if (elf == NULL)
1010 return -1;
1011
1012 if (is_64_bit)
1013 *is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
1014
1015 err = elf_read_maps(elf, exe, mapfn, data);
1016
1017 elf_end(elf);
1018 return err;
1019}
1020
849void symbol__elf_init(void) 1021void symbol__elf_init(void)
850{ 1022{
851 elf_version(EV_CURRENT); 1023 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index a7390cde63bc..3a802c300fc5 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -301,6 +301,13 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
301 return 0; 301 return 0;
302} 302}
303 303
304int file__read_maps(int fd __maybe_unused, bool exe __maybe_unused,
305 mapfn_t mapfn __maybe_unused, void *data __maybe_unused,
306 bool *is_64_bit __maybe_unused)
307{
308 return -1;
309}
310
304void symbol__elf_init(void) 311void symbol__elf_init(void)
305{ 312{
306} 313}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 8cf3b5426a9a..7eb0362f4ffd 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -32,7 +32,6 @@ int vmlinux_path__nr_entries;
32char **vmlinux_path; 32char **vmlinux_path;
33 33
34struct symbol_conf symbol_conf = { 34struct symbol_conf symbol_conf = {
35 .exclude_other = true,
36 .use_modules = true, 35 .use_modules = true,
37 .try_vmlinux_path = true, 36 .try_vmlinux_path = true,
38 .annotate_src = true, 37 .annotate_src = true,
@@ -88,6 +87,7 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
88{ 87{
89 s64 a; 88 s64 a;
90 s64 b; 89 s64 b;
90 size_t na, nb;
91 91
92 /* Prefer a symbol with non zero length */ 92 /* Prefer a symbol with non zero length */
93 a = syma->end - syma->start; 93 a = syma->end - syma->start;
@@ -121,11 +121,21 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
121 else if (a > b) 121 else if (a > b)
122 return SYMBOL_B; 122 return SYMBOL_B;
123 123
124 /* If all else fails, choose the symbol with the longest name */ 124 /* Choose the symbol with the longest name */
125 if (strlen(syma->name) >= strlen(symb->name)) 125 na = strlen(syma->name);
126 nb = strlen(symb->name);
127 if (na > nb)
126 return SYMBOL_A; 128 return SYMBOL_A;
127 else 129 else if (na < nb)
130 return SYMBOL_B;
131
132 /* Avoid "SyS" kernel syscall aliases */
133 if (na >= 3 && !strncmp(syma->name, "SyS", 3))
134 return SYMBOL_B;
135 if (na >= 10 && !strncmp(syma->name, "compat_SyS", 10))
128 return SYMBOL_B; 136 return SYMBOL_B;
137
138 return SYMBOL_A;
129} 139}
130 140
131void symbols__fixup_duplicate(struct rb_root *symbols) 141void symbols__fixup_duplicate(struct rb_root *symbols)
@@ -249,7 +259,10 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym,
249 if (sym && sym->name) { 259 if (sym && sym->name) {
250 length = fprintf(fp, "%s", sym->name); 260 length = fprintf(fp, "%s", sym->name);
251 if (al) { 261 if (al) {
252 offset = al->addr - sym->start; 262 if (al->addr < sym->end)
263 offset = al->addr - sym->start;
264 else
265 offset = al->addr - al->map->start - sym->start;
253 length += fprintf(fp, "+0x%lx", offset); 266 length += fprintf(fp, "+0x%lx", offset);
254 } 267 }
255 return length; 268 return length;
@@ -317,6 +330,16 @@ static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
317 return NULL; 330 return NULL;
318} 331}
319 332
333static struct symbol *symbols__first(struct rb_root *symbols)
334{
335 struct rb_node *n = rb_first(symbols);
336
337 if (n)
338 return rb_entry(n, struct symbol, rb_node);
339
340 return NULL;
341}
342
320struct symbol_name_rb_node { 343struct symbol_name_rb_node {
321 struct rb_node rb_node; 344 struct rb_node rb_node;
322 struct symbol sym; 345 struct symbol sym;
@@ -387,6 +410,11 @@ struct symbol *dso__find_symbol(struct dso *dso,
387 return symbols__find(&dso->symbols[type], addr); 410 return symbols__find(&dso->symbols[type], addr);
388} 411}
389 412
413struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
414{
415 return symbols__first(&dso->symbols[type]);
416}
417
390struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 418struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
391 const char *name) 419 const char *name)
392{ 420{
@@ -523,6 +551,53 @@ static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
523 return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 551 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
524} 552}
525 553
554static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
555 symbol_filter_t filter)
556{
557 struct map_groups *kmaps = map__kmap(map)->kmaps;
558 struct map *curr_map;
559 struct symbol *pos;
560 int count = 0, moved = 0;
561 struct rb_root *root = &dso->symbols[map->type];
562 struct rb_node *next = rb_first(root);
563
564 while (next) {
565 char *module;
566
567 pos = rb_entry(next, struct symbol, rb_node);
568 next = rb_next(&pos->rb_node);
569
570 module = strchr(pos->name, '\t');
571 if (module)
572 *module = '\0';
573
574 curr_map = map_groups__find(kmaps, map->type, pos->start);
575
576 if (!curr_map || (filter && filter(curr_map, pos))) {
577 rb_erase(&pos->rb_node, root);
578 symbol__delete(pos);
579 } else {
580 pos->start -= curr_map->start - curr_map->pgoff;
581 if (pos->end)
582 pos->end -= curr_map->start - curr_map->pgoff;
583 if (curr_map != map) {
584 rb_erase(&pos->rb_node, root);
585 symbols__insert(
586 &curr_map->dso->symbols[curr_map->type],
587 pos);
588 ++moved;
589 } else {
590 ++count;
591 }
592 }
593 }
594
595 /* Symbols have been adjusted */
596 dso->adjust_symbols = 1;
597
598 return count + moved;
599}
600
526/* 601/*
527 * Split the symbols into maps, making sure there are no overlaps, i.e. the 602 * Split the symbols into maps, making sure there are no overlaps, i.e. the
528 * kernel range is broken in several maps, named [kernel].N, as we don't have 603 * kernel range is broken in several maps, named [kernel].N, as we don't have
@@ -664,6 +739,161 @@ bool symbol__restricted_filename(const char *filename,
664 return restricted; 739 return restricted;
665} 740}
666 741
742struct kcore_mapfn_data {
743 struct dso *dso;
744 enum map_type type;
745 struct list_head maps;
746};
747
748static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
749{
750 struct kcore_mapfn_data *md = data;
751 struct map *map;
752
753 map = map__new2(start, md->dso, md->type);
754 if (map == NULL)
755 return -ENOMEM;
756
757 map->end = map->start + len;
758 map->pgoff = pgoff;
759
760 list_add(&map->node, &md->maps);
761
762 return 0;
763}
764
765/*
766 * If kallsyms is referenced by name then we look for kcore in the same
767 * directory.
768 */
769static bool kcore_filename_from_kallsyms_filename(char *kcore_filename,
770 const char *kallsyms_filename)
771{
772 char *name;
773
774 strcpy(kcore_filename, kallsyms_filename);
775 name = strrchr(kcore_filename, '/');
776 if (!name)
777 return false;
778
779 if (!strcmp(name, "/kallsyms")) {
780 strcpy(name, "/kcore");
781 return true;
782 }
783
784 return false;
785}
786
787static int dso__load_kcore(struct dso *dso, struct map *map,
788 const char *kallsyms_filename)
789{
790 struct map_groups *kmaps = map__kmap(map)->kmaps;
791 struct machine *machine = kmaps->machine;
792 struct kcore_mapfn_data md;
793 struct map *old_map, *new_map, *replacement_map = NULL;
794 bool is_64_bit;
795 int err, fd;
796 char kcore_filename[PATH_MAX];
797 struct symbol *sym;
798
799 /* This function requires that the map is the kernel map */
800 if (map != machine->vmlinux_maps[map->type])
801 return -EINVAL;
802
803 if (!kcore_filename_from_kallsyms_filename(kcore_filename,
804 kallsyms_filename))
805 return -EINVAL;
806
807 md.dso = dso;
808 md.type = map->type;
809 INIT_LIST_HEAD(&md.maps);
810
811 fd = open(kcore_filename, O_RDONLY);
812 if (fd < 0)
813 return -EINVAL;
814
815 /* Read new maps into temporary lists */
816 err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
817 &is_64_bit);
818 if (err)
819 goto out_err;
820
821 if (list_empty(&md.maps)) {
822 err = -EINVAL;
823 goto out_err;
824 }
825
826 /* Remove old maps */
827 old_map = map_groups__first(kmaps, map->type);
828 while (old_map) {
829 struct map *next = map_groups__next(old_map);
830
831 if (old_map != map)
832 map_groups__remove(kmaps, old_map);
833 old_map = next;
834 }
835
836 /* Find the kernel map using the first symbol */
837 sym = dso__first_symbol(dso, map->type);
838 list_for_each_entry(new_map, &md.maps, node) {
839 if (sym && sym->start >= new_map->start &&
840 sym->start < new_map->end) {
841 replacement_map = new_map;
842 break;
843 }
844 }
845
846 if (!replacement_map)
847 replacement_map = list_entry(md.maps.next, struct map, node);
848
849 /* Add new maps */
850 while (!list_empty(&md.maps)) {
851 new_map = list_entry(md.maps.next, struct map, node);
852 list_del(&new_map->node);
853 if (new_map == replacement_map) {
854 map->start = new_map->start;
855 map->end = new_map->end;
856 map->pgoff = new_map->pgoff;
857 map->map_ip = new_map->map_ip;
858 map->unmap_ip = new_map->unmap_ip;
859 map__delete(new_map);
860 /* Ensure maps are correctly ordered */
861 map_groups__remove(kmaps, map);
862 map_groups__insert(kmaps, map);
863 } else {
864 map_groups__insert(kmaps, new_map);
865 }
866 }
867
868 /*
869 * Set the data type and long name so that kcore can be read via
870 * dso__data_read_addr().
871 */
872 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
873 dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE;
874 else
875 dso->data_type = DSO_BINARY_TYPE__KCORE;
876 dso__set_long_name(dso, strdup(kcore_filename));
877
878 close(fd);
879
880 if (map->type == MAP__FUNCTION)
881 pr_debug("Using %s for kernel object code\n", kcore_filename);
882 else
883 pr_debug("Using %s for kernel data\n", kcore_filename);
884
885 return 0;
886
887out_err:
888 while (!list_empty(&md.maps)) {
889 map = list_entry(md.maps.next, struct map, node);
890 list_del(&map->node);
891 map__delete(map);
892 }
893 close(fd);
894 return -EINVAL;
895}
896
667int dso__load_kallsyms(struct dso *dso, const char *filename, 897int dso__load_kallsyms(struct dso *dso, const char *filename,
668 struct map *map, symbol_filter_t filter) 898 struct map *map, symbol_filter_t filter)
669{ 899{
@@ -681,7 +911,10 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
681 else 911 else
682 dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 912 dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
683 913
684 return dso__split_kallsyms(dso, map, filter); 914 if (!dso__load_kcore(dso, map, filename))
915 return dso__split_kallsyms_for_kcore(dso, map, filter);
916 else
917 return dso__split_kallsyms(dso, map, filter);
685} 918}
686 919
687static int dso__load_perf_map(struct dso *dso, struct map *map, 920static int dso__load_perf_map(struct dso *dso, struct map *map,
@@ -844,10 +1077,15 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
844 if (!runtime_ss && syms_ss) 1077 if (!runtime_ss && syms_ss)
845 runtime_ss = syms_ss; 1078 runtime_ss = syms_ss;
846 1079
847 if (syms_ss) 1080 if (syms_ss) {
848 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0); 1081 int km;
849 else 1082
1083 km = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1084 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
1085 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, km);
1086 } else {
850 ret = -1; 1087 ret = -1;
1088 }
851 1089
852 if (ret > 0) { 1090 if (ret > 0) {
853 int nr_plt; 1091 int nr_plt;
@@ -889,8 +1127,11 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
889 char symfs_vmlinux[PATH_MAX]; 1127 char symfs_vmlinux[PATH_MAX];
890 enum dso_binary_type symtab_type; 1128 enum dso_binary_type symtab_type;
891 1129
892 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", 1130 if (vmlinux[0] == '/')
893 symbol_conf.symfs, vmlinux); 1131 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
1132 else
1133 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
1134 symbol_conf.symfs, vmlinux);
894 1135
895 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1136 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
896 symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 1137 symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
@@ -904,6 +1145,10 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
904 symsrc__destroy(&ss); 1145 symsrc__destroy(&ss);
905 1146
906 if (err > 0) { 1147 if (err > 0) {
1148 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1149 dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
1150 else
1151 dso->data_type = DSO_BINARY_TYPE__VMLINUX;
907 dso__set_long_name(dso, (char *)vmlinux); 1152 dso__set_long_name(dso, (char *)vmlinux);
908 dso__set_loaded(dso, map->type); 1153 dso__set_loaded(dso, map->type);
909 pr_debug("Using %s for symbols\n", symfs_vmlinux); 1154 pr_debug("Using %s for symbols\n", symfs_vmlinux);
@@ -976,7 +1221,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
976 dso__set_long_name(dso, 1221 dso__set_long_name(dso,
977 strdup(symbol_conf.vmlinux_name)); 1222 strdup(symbol_conf.vmlinux_name));
978 dso->lname_alloc = 1; 1223 dso->lname_alloc = 1;
979 goto out_fixup; 1224 return err;
980 } 1225 }
981 return err; 1226 return err;
982 } 1227 }
@@ -984,7 +1229,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
984 if (vmlinux_path != NULL) { 1229 if (vmlinux_path != NULL) {
985 err = dso__load_vmlinux_path(dso, map, filter); 1230 err = dso__load_vmlinux_path(dso, map, filter);
986 if (err > 0) 1231 if (err > 0)
987 goto out_fixup; 1232 return err;
988 } 1233 }
989 1234
990 /* do not try local files if a symfs was given */ 1235 /* do not try local files if a symfs was given */
@@ -1043,9 +1288,8 @@ do_kallsyms:
1043 pr_debug("Using %s for symbols\n", kallsyms_filename); 1288 pr_debug("Using %s for symbols\n", kallsyms_filename);
1044 free(kallsyms_allocated_filename); 1289 free(kallsyms_allocated_filename);
1045 1290
1046 if (err > 0) { 1291 if (err > 0 && !dso__is_kcore(dso)) {
1047 dso__set_long_name(dso, strdup("[kernel.kallsyms]")); 1292 dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
1048out_fixup:
1049 map__fixup_start(map); 1293 map__fixup_start(map);
1050 map__fixup_end(map); 1294 map__fixup_end(map);
1051 } 1295 }
@@ -1076,7 +1320,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1076 if (symbol_conf.default_guest_vmlinux_name != NULL) { 1320 if (symbol_conf.default_guest_vmlinux_name != NULL) {
1077 err = dso__load_vmlinux(dso, map, 1321 err = dso__load_vmlinux(dso, map,
1078 symbol_conf.default_guest_vmlinux_name, filter); 1322 symbol_conf.default_guest_vmlinux_name, filter);
1079 goto out_try_fixup; 1323 return err;
1080 } 1324 }
1081 1325
1082 kallsyms_filename = symbol_conf.default_guest_kallsyms; 1326 kallsyms_filename = symbol_conf.default_guest_kallsyms;
@@ -1090,13 +1334,9 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1090 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 1334 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
1091 if (err > 0) 1335 if (err > 0)
1092 pr_debug("Using %s for symbols\n", kallsyms_filename); 1336 pr_debug("Using %s for symbols\n", kallsyms_filename);
1093 1337 if (err > 0 && !dso__is_kcore(dso)) {
1094out_try_fixup: 1338 machine__mmap_name(machine, path, sizeof(path));
1095 if (err > 0) { 1339 dso__set_long_name(dso, strdup(path));
1096 if (kallsyms_filename != NULL) {
1097 machine__mmap_name(machine, path, sizeof(path));
1098 dso__set_long_name(dso, strdup(path));
1099 }
1100 map__fixup_start(map); 1340 map__fixup_start(map);
1101 map__fixup_end(map); 1341 map__fixup_end(map);
1102 } 1342 }
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 5f720dc076da..fd5b70ea2981 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -215,6 +215,7 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
215 u64 addr); 215 u64 addr);
216struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 216struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
217 const char *name); 217 const char *name);
218struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
218 219
219int filename__read_build_id(const char *filename, void *bf, size_t size); 220int filename__read_build_id(const char *filename, void *bf, size_t size);
220int sysfs__read_build_id(const char *filename, void *bf, size_t size); 221int sysfs__read_build_id(const char *filename, void *bf, size_t size);
@@ -247,4 +248,8 @@ void symbols__fixup_duplicate(struct rb_root *symbols);
247void symbols__fixup_end(struct rb_root *symbols); 248void symbols__fixup_end(struct rb_root *symbols);
248void __map_groups__fixup_end(struct map_groups *mg, enum map_type type); 249void __map_groups__fixup_end(struct map_groups *mg, enum map_type type);
249 250
251typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
252int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
253 bool *is_64_bit);
254
250#endif /* __PERF_SYMBOL */ 255#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 632e40e5ceca..e3d4a550a703 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,16 +7,18 @@
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9 9
10struct thread *thread__new(pid_t pid) 10struct thread *thread__new(pid_t pid, pid_t tid)
11{ 11{
12 struct thread *self = zalloc(sizeof(*self)); 12 struct thread *self = zalloc(sizeof(*self));
13 13
14 if (self != NULL) { 14 if (self != NULL) {
15 map_groups__init(&self->mg); 15 map_groups__init(&self->mg);
16 self->pid = pid; 16 self->pid_ = pid;
17 self->tid = tid;
18 self->ppid = -1;
17 self->comm = malloc(32); 19 self->comm = malloc(32);
18 if (self->comm) 20 if (self->comm)
19 snprintf(self->comm, 32, ":%d", self->pid); 21 snprintf(self->comm, 32, ":%d", self->tid);
20 } 22 }
21 23
22 return self; 24 return self;
@@ -56,7 +58,7 @@ int thread__comm_len(struct thread *self)
56 58
57size_t thread__fprintf(struct thread *thread, FILE *fp) 59size_t thread__fprintf(struct thread *thread, FILE *fp)
58{ 60{
59 return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) + 61 return fprintf(fp, "Thread %d %s\n", thread->tid, thread->comm) +
60 map_groups__fprintf(&thread->mg, verbose, fp); 62 map_groups__fprintf(&thread->mg, verbose, fp);
61} 63}
62 64
@@ -82,5 +84,8 @@ int thread__fork(struct thread *self, struct thread *parent)
82 for (i = 0; i < MAP__NR_TYPES; ++i) 84 for (i = 0; i < MAP__NR_TYPES; ++i)
83 if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 85 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
84 return -ENOMEM; 86 return -ENOMEM;
87
88 self->ppid = parent->tid;
89
85 return 0; 90 return 0;
86} 91}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 5ad266403098..4ebbb40d46d4 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -12,9 +12,12 @@ struct thread {
12 struct list_head node; 12 struct list_head node;
13 }; 13 };
14 struct map_groups mg; 14 struct map_groups mg;
15 pid_t pid; 15 pid_t pid_; /* Not all tools update this */
16 pid_t tid;
17 pid_t ppid;
16 char shortname[3]; 18 char shortname[3];
17 bool comm_set; 19 bool comm_set;
20 bool dead; /* if set thread has exited */
18 char *comm; 21 char *comm;
19 int comm_len; 22 int comm_len;
20 23
@@ -23,8 +26,12 @@ struct thread {
23 26
24struct machine; 27struct machine;
25 28
26struct thread *thread__new(pid_t pid); 29struct thread *thread__new(pid_t pid, pid_t tid);
27void thread__delete(struct thread *self); 30void thread__delete(struct thread *self);
31static inline void thread__exited(struct thread *thread)
32{
33 thread->dead = true;
34}
28 35
29int thread__set_comm(struct thread *self, const char *comm); 36int thread__set_comm(struct thread *self, const char *comm);
30int thread__comm_len(struct thread *self); 37int thread__comm_len(struct thread *self);
@@ -44,6 +51,15 @@ void thread__find_addr_map(struct thread *thread, struct machine *machine,
44 51
45void thread__find_addr_location(struct thread *thread, struct machine *machine, 52void thread__find_addr_location(struct thread *thread, struct machine *machine,
46 u8 cpumode, enum map_type type, u64 addr, 53 u8 cpumode, enum map_type type, u64 addr,
47 struct addr_location *al, 54 struct addr_location *al);
48 symbol_filter_t filter); 55
56static inline void *thread__priv(struct thread *thread)
57{
58 return thread->priv;
59}
60
61static inline void thread__set_priv(struct thread *thread, void *p)
62{
63 thread->priv = p;
64}
49#endif /* __PERF_THREAD_H */ 65#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index b0e1aadba8d5..4385816d3d49 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -18,12 +18,9 @@ typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event,
18typedef int (*event_op)(struct perf_tool *tool, union perf_event *event, 18typedef int (*event_op)(struct perf_tool *tool, union perf_event *event,
19 struct perf_sample *sample, struct machine *machine); 19 struct perf_sample *sample, struct machine *machine);
20 20
21typedef int (*event_attr_op)(union perf_event *event, 21typedef int (*event_attr_op)(struct perf_tool *tool,
22 union perf_event *event,
22 struct perf_evlist **pevlist); 23 struct perf_evlist **pevlist);
23typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event);
24
25typedef int (*event_synth_op)(union perf_event *event,
26 struct perf_session *session);
27 24
28typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event, 25typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
29 struct perf_session *session); 26 struct perf_session *session);
@@ -32,6 +29,7 @@ struct perf_tool {
32 event_sample sample, 29 event_sample sample,
33 read; 30 read;
34 event_op mmap, 31 event_op mmap,
32 mmap2,
35 comm, 33 comm,
36 fork, 34 fork,
37 exit, 35 exit,
@@ -39,8 +37,7 @@ struct perf_tool {
39 throttle, 37 throttle,
40 unthrottle; 38 unthrottle;
41 event_attr_op attr; 39 event_attr_op attr;
42 event_synth_op tracing_data; 40 event_op2 tracing_data;
43 event_simple_op event_type;
44 event_op2 finished_round, 41 event_op2 finished_round,
45 build_id; 42 build_id;
46 bool ordered_samples; 43 bool ordered_samples;
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 54d37a4753c5..f857b51b6bde 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -23,20 +23,31 @@
23 23
24size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) 24size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
25{ 25{
26 float samples_per_sec = top->samples / top->delay_secs; 26 float samples_per_sec;
27 float ksamples_per_sec = top->kernel_samples / top->delay_secs; 27 float ksamples_per_sec;
28 float esamples_percent = (100.0 * top->exact_samples) / top->samples; 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 perf_target *target = &opts->target;
31 size_t ret = 0; 31 size_t ret = 0;
32 32
33 if (top->samples) {
34 samples_per_sec = top->samples / top->delay_secs;
35 ksamples_per_sec = top->kernel_samples / top->delay_secs;
36 esamples_percent = (100.0 * top->exact_samples) / top->samples;
37 } else {
38 samples_per_sec = ksamples_per_sec = esamples_percent = 0.0;
39 }
40
33 if (!perf_guest) { 41 if (!perf_guest) {
42 float ksamples_percent = 0.0;
43
44 if (samples_per_sec)
45 ksamples_percent = (100.0 * ksamples_per_sec) /
46 samples_per_sec;
34 ret = SNPRINTF(bf, size, 47 ret = SNPRINTF(bf, size,
35 " PerfTop:%8.0f irqs/sec kernel:%4.1f%%" 48 " PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
36 " exact: %4.1f%% [", samples_per_sec, 49 " exact: %4.1f%% [", samples_per_sec,
37 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / 50 ksamples_percent, esamples_percent);
38 samples_per_sec)),
39 esamples_percent);
40 } else { 51 } else {
41 float us_samples_per_sec = top->us_samples / top->delay_secs; 52 float us_samples_per_sec = top->us_samples / top->delay_secs;
42 float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs; 53 float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs;
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 7ebf357dc9e1..b554ffc462b6 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -26,7 +26,6 @@ struct perf_top {
26 int print_entries, count_filter, delay_secs; 26 int print_entries, count_filter, delay_secs;
27 bool hide_kernel_symbols, hide_user_symbols, zero; 27 bool hide_kernel_symbols, hide_user_symbols, zero;
28 bool use_tui, use_stdio; 28 bool use_tui, use_stdio;
29 bool sort_has_symbols;
30 bool kptr_restrict_warned; 29 bool kptr_restrict_warned;
31 bool vmlinux_warned; 30 bool vmlinux_warned;
32 bool dump_symtab; 31 bool dump_symtab;
@@ -37,8 +36,11 @@ struct perf_top {
37 int realtime_prio; 36 int realtime_prio;
38 int sym_pcnt_filter; 37 int sym_pcnt_filter;
39 const char *sym_filter; 38 const char *sym_filter;
39 float min_percent;
40}; 40};
41 41
42#define CONSOLE_CLEAR ""
43
42size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 44size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
43void perf_top__reset_sample_counters(struct perf_top *top); 45void perf_top__reset_sample_counters(struct perf_top *top);
44#endif /* __PERF_TOP_H */ 46#endif /* __PERF_TOP_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 3917eb9a8479..f3c9e551bd35 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -46,65 +46,6 @@
46static int output_fd; 46static int output_fd;
47 47
48 48
49static const char *find_debugfs(void)
50{
51 const char *path = perf_debugfs_mount(NULL);
52
53 if (!path)
54 pr_debug("Your kernel does not support the debugfs filesystem");
55
56 return path;
57}
58
59/*
60 * Finds the path to the debugfs/tracing
61 * Allocates the string and stores it.
62 */
63static const char *find_tracing_dir(void)
64{
65 static char *tracing;
66 static int tracing_found;
67 const char *debugfs;
68
69 if (tracing_found)
70 return tracing;
71
72 debugfs = find_debugfs();
73 if (!debugfs)
74 return NULL;
75
76 tracing = malloc(strlen(debugfs) + 9);
77 if (!tracing)
78 return NULL;
79
80 sprintf(tracing, "%s/tracing", debugfs);
81
82 tracing_found = 1;
83 return tracing;
84}
85
86static char *get_tracing_file(const char *name)
87{
88 const char *tracing;
89 char *file;
90
91 tracing = find_tracing_dir();
92 if (!tracing)
93 return NULL;
94
95 file = malloc(strlen(tracing) + strlen(name) + 2);
96 if (!file)
97 return NULL;
98
99 sprintf(file, "%s/%s", tracing, name);
100 return file;
101}
102
103static void put_tracing_file(char *file)
104{
105 free(file);
106}
107
108int bigendian(void) 49int bigendian(void)
109{ 50{
110 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; 51 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
@@ -160,7 +101,7 @@ out:
160 return err; 101 return err;
161} 102}
162 103
163static int read_header_files(void) 104static int record_header_files(void)
164{ 105{
165 char *path; 106 char *path;
166 struct stat st; 107 struct stat st;
@@ -299,7 +240,7 @@ out:
299 return err; 240 return err;
300} 241}
301 242
302static int read_ftrace_files(struct tracepoint_path *tps) 243static int record_ftrace_files(struct tracepoint_path *tps)
303{ 244{
304 char *path; 245 char *path;
305 int ret; 246 int ret;
@@ -328,7 +269,7 @@ static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
328 return false; 269 return false;
329} 270}
330 271
331static int read_event_files(struct tracepoint_path *tps) 272static int record_event_files(struct tracepoint_path *tps)
332{ 273{
333 struct dirent *dent; 274 struct dirent *dent;
334 struct stat st; 275 struct stat st;
@@ -403,7 +344,7 @@ out:
403 return err; 344 return err;
404} 345}
405 346
406static int read_proc_kallsyms(void) 347static int record_proc_kallsyms(void)
407{ 348{
408 unsigned int size; 349 unsigned int size;
409 const char *path = "/proc/kallsyms"; 350 const char *path = "/proc/kallsyms";
@@ -421,7 +362,7 @@ static int read_proc_kallsyms(void)
421 return record_file(path, 4); 362 return record_file(path, 4);
422} 363}
423 364
424static int read_ftrace_printk(void) 365static int record_ftrace_printk(void)
425{ 366{
426 unsigned int size; 367 unsigned int size;
427 char *path; 368 char *path;
@@ -473,12 +414,27 @@ get_tracepoints_path(struct list_head *pattrs)
473 if (pos->attr.type != PERF_TYPE_TRACEPOINT) 414 if (pos->attr.type != PERF_TYPE_TRACEPOINT)
474 continue; 415 continue;
475 ++nr_tracepoints; 416 ++nr_tracepoints;
417
418 if (pos->name) {
419 ppath->next = tracepoint_name_to_path(pos->name);
420 if (ppath->next)
421 goto next;
422
423 if (strchr(pos->name, ':') == NULL)
424 goto try_id;
425
426 goto error;
427 }
428
429try_id:
476 ppath->next = tracepoint_id_to_path(pos->attr.config); 430 ppath->next = tracepoint_id_to_path(pos->attr.config);
477 if (!ppath->next) { 431 if (!ppath->next) {
432error:
478 pr_debug("No memory to alloc tracepoints list\n"); 433 pr_debug("No memory to alloc tracepoints list\n");
479 put_tracepoints_path(&path); 434 put_tracepoints_path(&path);
480 return NULL; 435 return NULL;
481 } 436 }
437next:
482 ppath = ppath->next; 438 ppath = ppath->next;
483 } 439 }
484 440
@@ -520,8 +476,6 @@ static int tracing_data_header(void)
520 else 476 else
521 buf[0] = 0; 477 buf[0] = 0;
522 478
523 read_trace_init(buf[0], buf[0]);
524
525 if (write(output_fd, buf, 1) != 1) 479 if (write(output_fd, buf, 1) != 1)
526 return -1; 480 return -1;
527 481
@@ -583,19 +537,19 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
583 err = tracing_data_header(); 537 err = tracing_data_header();
584 if (err) 538 if (err)
585 goto out; 539 goto out;
586 err = read_header_files(); 540 err = record_header_files();
587 if (err) 541 if (err)
588 goto out; 542 goto out;
589 err = read_ftrace_files(tps); 543 err = record_ftrace_files(tps);
590 if (err) 544 if (err)
591 goto out; 545 goto out;
592 err = read_event_files(tps); 546 err = record_event_files(tps);
593 if (err) 547 if (err)
594 goto out; 548 goto out;
595 err = read_proc_kallsyms(); 549 err = record_proc_kallsyms();
596 if (err) 550 if (err)
597 goto out; 551 goto out;
598 err = read_ftrace_printk(); 552 err = record_ftrace_printk();
599 553
600out: 554out:
601 /* 555 /*
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 4454835a9ebc..e9e1c03f927d 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -28,12 +28,6 @@
28#include "util.h" 28#include "util.h"
29#include "trace-event.h" 29#include "trace-event.h"
30 30
31int header_page_size_size;
32int header_page_ts_size;
33int header_page_data_offset;
34
35bool latency_format;
36
37struct pevent *read_trace_init(int file_bigendian, int host_bigendian) 31struct pevent *read_trace_init(int file_bigendian, int host_bigendian)
38{ 32{
39 struct pevent *pevent = pevent_alloc(); 33 struct pevent *pevent = pevent_alloc();
@@ -192,7 +186,7 @@ void parse_proc_kallsyms(struct pevent *pevent,
192 char *next = NULL; 186 char *next = NULL;
193 char *addr_str; 187 char *addr_str;
194 char *mod; 188 char *mod;
195 char *fmt; 189 char *fmt = NULL;
196 190
197 line = strtok_r(file, "\n", &next); 191 line = strtok_r(file, "\n", &next);
198 while (line) { 192 while (line) {
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index af215c0d2379..f2112270c663 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -39,10 +39,6 @@
39 39
40static int input_fd; 40static int input_fd;
41 41
42int file_bigendian;
43int host_bigendian;
44static int long_size;
45
46static ssize_t trace_data_size; 42static ssize_t trace_data_size;
47static bool repipe; 43static bool repipe;
48 44
@@ -216,7 +212,7 @@ static int read_ftrace_printk(struct pevent *pevent)
216static int read_header_files(struct pevent *pevent) 212static int read_header_files(struct pevent *pevent)
217{ 213{
218 unsigned long long size; 214 unsigned long long size;
219 char *header_event; 215 char *header_page;
220 char buf[BUFSIZ]; 216 char buf[BUFSIZ];
221 int ret = 0; 217 int ret = 0;
222 218
@@ -229,13 +225,26 @@ static int read_header_files(struct pevent *pevent)
229 } 225 }
230 226
231 size = read8(pevent); 227 size = read8(pevent);
232 skip(size);
233 228
234 /* 229 header_page = malloc(size);
235 * The size field in the page is of type long, 230 if (header_page == NULL)
236 * use that instead, since it represents the kernel. 231 return -1;
237 */ 232
238 long_size = header_page_size_size; 233 if (do_read(header_page, size) < 0) {
234 pr_debug("did not read header page");
235 free(header_page);
236 return -1;
237 }
238
239 if (!pevent_parse_header_page(pevent, header_page, size,
240 pevent_get_long_size(pevent))) {
241 /*
242 * The commit field in the page is of type long,
243 * use that instead, since it represents the kernel.
244 */
245 pevent_set_long_size(pevent, pevent->header_page_size_size);
246 }
247 free(header_page);
239 248
240 if (do_read(buf, 13) < 0) 249 if (do_read(buf, 13) < 0)
241 return -1; 250 return -1;
@@ -246,14 +255,8 @@ static int read_header_files(struct pevent *pevent)
246 } 255 }
247 256
248 size = read8(pevent); 257 size = read8(pevent);
249 header_event = malloc(size); 258 skip(size);
250 if (header_event == NULL)
251 return -1;
252
253 if (do_read(header_event, size) < 0)
254 ret = -1;
255 259
256 free(header_event);
257 return ret; 260 return ret;
258} 261}
259 262
@@ -349,6 +352,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
349 int show_funcs = 0; 352 int show_funcs = 0;
350 int show_printk = 0; 353 int show_printk = 0;
351 ssize_t size = -1; 354 ssize_t size = -1;
355 int file_bigendian;
356 int host_bigendian;
357 int file_long_size;
358 int file_page_size;
352 struct pevent *pevent; 359 struct pevent *pevent;
353 int err; 360 int err;
354 361
@@ -391,12 +398,15 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
391 398
392 if (do_read(buf, 1) < 0) 399 if (do_read(buf, 1) < 0)
393 goto out; 400 goto out;
394 long_size = buf[0]; 401 file_long_size = buf[0];
395 402
396 page_size = read4(pevent); 403 file_page_size = read4(pevent);
397 if (!page_size) 404 if (!file_page_size)
398 goto out; 405 goto out;
399 406
407 pevent_set_long_size(pevent, file_long_size);
408 pevent_set_page_size(pevent, file_page_size);
409
400 err = read_header_files(pevent); 410 err = read_header_files(pevent);
401 if (err) 411 if (err)
402 goto out; 412 goto out;
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index 8715a1006d00..95199e4eea97 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -39,7 +39,8 @@ static void process_event_unsupported(union perf_event *event __maybe_unused,
39 struct perf_sample *sample __maybe_unused, 39 struct perf_sample *sample __maybe_unused,
40 struct perf_evsel *evsel __maybe_unused, 40 struct perf_evsel *evsel __maybe_unused,
41 struct machine *machine __maybe_unused, 41 struct machine *machine __maybe_unused,
42 struct addr_location *al __maybe_unused) 42 struct thread *thread __maybe_unused,
43 struct addr_location *al __maybe_unused)
43{ 44{
44} 45}
45 46
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 1978c398ad87..fafe1a40444a 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,32 +1,18 @@
1#ifndef _PERF_UTIL_TRACE_EVENT_H 1#ifndef _PERF_UTIL_TRACE_EVENT_H
2#define _PERF_UTIL_TRACE_EVENT_H 2#define _PERF_UTIL_TRACE_EVENT_H
3 3
4#include <traceevent/event-parse.h>
4#include "parse-events.h" 5#include "parse-events.h"
5#include "event-parse.h"
6#include "session.h" 6#include "session.h"
7 7
8struct machine; 8struct machine;
9struct perf_sample; 9struct perf_sample;
10union perf_event; 10union perf_event;
11struct perf_tool; 11struct perf_tool;
12struct thread;
12 13
13extern int header_page_size_size;
14extern int header_page_ts_size;
15extern int header_page_data_offset;
16
17extern bool latency_format;
18extern struct pevent *perf_pevent; 14extern struct pevent *perf_pevent;
19 15
20enum {
21 RINGBUF_TYPE_PADDING = 29,
22 RINGBUF_TYPE_TIME_EXTEND = 30,
23 RINGBUF_TYPE_TIME_STAMP = 31,
24};
25
26#ifndef TS_SHIFT
27#define TS_SHIFT 27
28#endif
29
30int bigendian(void); 16int bigendian(void);
31 17
32struct pevent *read_trace_init(int file_bigendian, int host_bigendian); 18struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
@@ -83,7 +69,8 @@ struct scripting_ops {
83 struct perf_sample *sample, 69 struct perf_sample *sample,
84 struct perf_evsel *evsel, 70 struct perf_evsel *evsel,
85 struct machine *machine, 71 struct machine *machine,
86 struct addr_location *al); 72 struct thread *thread,
73 struct addr_location *al);
87 int (*generate_script) (struct pevent *pevent, const char *outfile); 74 int (*generate_script) (struct pevent *pevent, const char *outfile);
88}; 75};
89 76
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 958723ba3d2e..2f891f7e70bf 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -473,7 +473,7 @@ static int entry(u64 ip, struct thread *thread, struct machine *machine,
473 473
474 thread__find_addr_location(thread, machine, 474 thread__find_addr_location(thread, machine,
475 PERF_RECORD_MISC_USER, 475 PERF_RECORD_MISC_USER,
476 MAP__FUNCTION, ip, &al, NULL); 476 MAP__FUNCTION, ip, &al);
477 477
478 e.ip = ip; 478 e.ip = ip;
479 e.map = al.map; 479 e.map = al.map;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 59d868add275..6d17b18e915d 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -269,3 +269,95 @@ void perf_debugfs_set_path(const char *mntpt)
269 snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt); 269 snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
270 set_tracing_events_path(mntpt); 270 set_tracing_events_path(mntpt);
271} 271}
272
273static const char *find_debugfs(void)
274{
275 const char *path = perf_debugfs_mount(NULL);
276
277 if (!path)
278 fprintf(stderr, "Your kernel does not support the debugfs filesystem");
279
280 return path;
281}
282
283/*
284 * Finds the path to the debugfs/tracing
285 * Allocates the string and stores it.
286 */
287const char *find_tracing_dir(void)
288{
289 static char *tracing;
290 static int tracing_found;
291 const char *debugfs;
292
293 if (tracing_found)
294 return tracing;
295
296 debugfs = find_debugfs();
297 if (!debugfs)
298 return NULL;
299
300 tracing = malloc(strlen(debugfs) + 9);
301 if (!tracing)
302 return NULL;
303
304 sprintf(tracing, "%s/tracing", debugfs);
305
306 tracing_found = 1;
307 return tracing;
308}
309
310char *get_tracing_file(const char *name)
311{
312 const char *tracing;
313 char *file;
314
315 tracing = find_tracing_dir();
316 if (!tracing)
317 return NULL;
318
319 file = malloc(strlen(tracing) + strlen(name) + 2);
320 if (!file)
321 return NULL;
322
323 sprintf(file, "%s/%s", tracing, name);
324 return file;
325}
326
327void put_tracing_file(char *file)
328{
329 free(file);
330}
331
332int parse_nsec_time(const char *str, u64 *ptime)
333{
334 u64 time_sec, time_nsec;
335 char *end;
336
337 time_sec = strtoul(str, &end, 10);
338 if (*end != '.' && *end != '\0')
339 return -1;
340
341 if (*end == '.') {
342 int i;
343 char nsec_buf[10];
344
345 if (strlen(++end) > 9)
346 return -1;
347
348 strncpy(nsec_buf, end, 9);
349 nsec_buf[9] = '\0';
350
351 /* make it nsec precision */
352 for (i = strlen(nsec_buf); i < 9; i++)
353 nsec_buf[i] = '0';
354
355 time_nsec = strtoul(nsec_buf, &end, 10);
356 if (*end != '\0')
357 return -1;
358 } else
359 time_nsec = 0;
360
361 *ptime = time_sec * NSEC_PER_SEC + time_nsec;
362 return 0;
363}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index a45710b70a55..a53535949043 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -72,6 +72,7 @@
72#include "types.h" 72#include "types.h"
73#include <sys/ttydefaults.h> 73#include <sys/ttydefaults.h>
74#include <lk/debugfs.h> 74#include <lk/debugfs.h>
75#include <termios.h>
75 76
76extern const char *graph_line; 77extern const char *graph_line;
77extern const char *graph_dotted_line; 78extern const char *graph_dotted_line;
@@ -79,6 +80,9 @@ extern char buildid_dir[];
79extern char tracing_events_path[]; 80extern char tracing_events_path[];
80extern void perf_debugfs_set_path(const char *mountpoint); 81extern void perf_debugfs_set_path(const char *mountpoint);
81const char *perf_debugfs_mount(const char *mountpoint); 82const char *perf_debugfs_mount(const char *mountpoint);
83const char *find_tracing_dir(void);
84char *get_tracing_file(const char *name);
85void put_tracing_file(char *file);
82 86
83/* On most systems <limits.h> would have given us this, but 87/* On most systems <limits.h> would have given us this, but
84 * not on some systems (e.g. GNU/Hurd). 88 * not on some systems (e.g. GNU/Hurd).
@@ -204,6 +208,8 @@ static inline int has_extension(const char *filename, const char *ext)
204#define NSEC_PER_MSEC 1000000L 208#define NSEC_PER_MSEC 1000000L
205#endif 209#endif
206 210
211int parse_nsec_time(const char *str, u64 *ptime);
212
207extern unsigned char sane_ctype[256]; 213extern unsigned char sane_ctype[256];
208#define GIT_SPACE 0x01 214#define GIT_SPACE 0x01
209#define GIT_DIGIT 0x02 215#define GIT_DIGIT 0x02
@@ -221,8 +227,8 @@ extern unsigned char sane_ctype[256];
221#define isalpha(x) sane_istest(x,GIT_ALPHA) 227#define isalpha(x) sane_istest(x,GIT_ALPHA)
222#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 228#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
223#define isprint(x) sane_istest(x,GIT_PRINT) 229#define isprint(x) sane_istest(x,GIT_PRINT)
224#define islower(x) (sane_istest(x,GIT_ALPHA) && sane_istest(x,0x20)) 230#define islower(x) (sane_istest(x,GIT_ALPHA) && (x & 0x20))
225#define isupper(x) (sane_istest(x,GIT_ALPHA) && !sane_istest(x,0x20)) 231#define isupper(x) (sane_istest(x,GIT_ALPHA) && !(x & 0x20))
226#define tolower(x) sane_case((unsigned char)(x), 0x20) 232#define tolower(x) sane_case((unsigned char)(x), 0x20)
227#define toupper(x) sane_case((unsigned char)(x), 0) 233#define toupper(x) sane_case((unsigned char)(x), 0)
228 234
@@ -274,6 +280,5 @@ void dump_stack(void);
274 280
275extern unsigned int page_size; 281extern unsigned int page_size;
276 282
277struct winsize;
278void get_term_dimensions(struct winsize *ws); 283void get_term_dimensions(struct winsize *ws);
279#endif /* GIT_COMPAT_UTIL_H */ 284#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
index e60951fcdb12..39159822d58f 100644
--- a/tools/perf/util/vdso.c
+++ b/tools/perf/util/vdso.c
@@ -91,7 +91,7 @@ void vdso__exit(void)
91 91
92struct dso *vdso__dso_findnew(struct list_head *head) 92struct dso *vdso__dso_findnew(struct list_head *head)
93{ 93{
94 struct dso *dso = dsos__find(head, VDSO__MAP_NAME); 94 struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true);
95 95
96 if (!dso) { 96 if (!dso) {
97 char *file; 97 char *file;
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index d875a74a3bdf..cbfec92af327 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -128,10 +128,12 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \
128 utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ 128 utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \
129 utils/helpers/pci.o utils/helpers/bitmask.o \ 129 utils/helpers/pci.o utils/helpers/bitmask.o \
130 utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ 130 utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \
131 utils/idle_monitor/hsw_ext_idle.o \
131 utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ 132 utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \
132 utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ 133 utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \
133 utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ 134 utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \
134 utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o 135 utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o \
136 utils/cpuidle-set.o
135 137
136UTIL_SRC := $(UTIL_OBJS:.o=.c) 138UTIL_SRC := $(UTIL_OBJS:.o=.c)
137 139
diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1
index e01c35d13b6e..914cbb9d9cd0 100644
--- a/tools/power/cpupower/man/cpupower-monitor.1
+++ b/tools/power/cpupower/man/cpupower-monitor.1
@@ -110,13 +110,21 @@ May work poorly on Linux-2.6.20 through 2.6.29, as the \fBacpi-cpufreq \fP
110kernel frequency driver periodically cleared aperf/mperf registers in those 110kernel frequency driver periodically cleared aperf/mperf registers in those
111kernels. 111kernels.
112 112
113.SS "Nehalem" "SandyBridge" 113.SS "Nehalem" "SandyBridge" "HaswellExtended"
114Intel Core and Package sleep state counters. 114Intel Core and Package sleep state counters.
115Threads (hyperthreaded cores) may not be able to enter deeper core states if 115Threads (hyperthreaded cores) may not be able to enter deeper core states if
116its sibling is utilized. 116its sibling is utilized.
117Deepest package sleep states may in reality show up as machine/platform wide 117Deepest package sleep states may in reality show up as machine/platform wide
118sleep states and can only be entered if all cores are idle. Look up Intel 118sleep states and can only be entered if all cores are idle. Look up Intel
119manuals (some are provided in the References section) for further details. 119manuals (some are provided in the References section) for further details.
120The monitors are named after the CPU family where the sleep state capabilities
121got introduced and may not match exactly the CPU name of the platform.
122For example an IvyBridge processor has sleep state capabilities which got
123introduced in Nehalem and SandyBridge processor families.
124Thus on an IvyBridge processor one will get Nehalem and SandyBridge sleep
125state monitors.
126HaswellExtended extra package sleep state capabilities are available only in a
127specific Haswell (family 0x45) and probably also other future processors.
120 128
121.SS "Fam_12h" "Fam_14h" 129.SS "Fam_12h" "Fam_14h"
122AMD laptop and desktop processor (family 12h and 14h) sleep state counters. 130AMD laptop and desktop processor (family 12h and 14h) sleep state counters.
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h
index c10496fbe3c6..2284c8ea4e2a 100644
--- a/tools/power/cpupower/utils/builtin.h
+++ b/tools/power/cpupower/utils/builtin.h
@@ -5,6 +5,7 @@ extern int cmd_set(int argc, const char **argv);
5extern int cmd_info(int argc, const char **argv); 5extern int cmd_info(int argc, const char **argv);
6extern int cmd_freq_set(int argc, const char **argv); 6extern int cmd_freq_set(int argc, const char **argv);
7extern int cmd_freq_info(int argc, const char **argv); 7extern int cmd_freq_info(int argc, const char **argv);
8extern int cmd_idle_set(int argc, const char **argv);
8extern int cmd_idle_info(int argc, const char **argv); 9extern int cmd_idle_info(int argc, const char **argv);
9extern int cmd_monitor(int argc, const char **argv); 10extern int cmd_monitor(int argc, const char **argv);
10 11
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index 8145af5f93a6..75e66de7e7a7 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -22,7 +22,7 @@
22 22
23static void cpuidle_cpu_output(unsigned int cpu, int verbose) 23static void cpuidle_cpu_output(unsigned int cpu, int verbose)
24{ 24{
25 int idlestates, idlestate; 25 unsigned int idlestates, idlestate;
26 char *tmp; 26 char *tmp;
27 27
28 printf(_ ("Analyzing CPU %d:\n"), cpu); 28 printf(_ ("Analyzing CPU %d:\n"), cpu);
@@ -31,10 +31,8 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
31 if (idlestates == 0) { 31 if (idlestates == 0) {
32 printf(_("CPU %u: No idle states\n"), cpu); 32 printf(_("CPU %u: No idle states\n"), cpu);
33 return; 33 return;
34 } else if (idlestates <= 0) {
35 printf(_("CPU %u: Can't read idle state info\n"), cpu);
36 return;
37 } 34 }
35
38 printf(_("Number of idle states: %d\n"), idlestates); 36 printf(_("Number of idle states: %d\n"), idlestates);
39 printf(_("Available idle states:")); 37 printf(_("Available idle states:"));
40 for (idlestate = 0; idlestate < idlestates; idlestate++) { 38 for (idlestate = 0; idlestate < idlestates; idlestate++) {
@@ -50,10 +48,14 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
50 return; 48 return;
51 49
52 for (idlestate = 0; idlestate < idlestates; idlestate++) { 50 for (idlestate = 0; idlestate < idlestates; idlestate++) {
51 int disabled = sysfs_is_idlestate_disabled(cpu, idlestate);
52 /* Disabled interface not supported on older kernels */
53 if (disabled < 0)
54 disabled = 0;
53 tmp = sysfs_get_idlestate_name(cpu, idlestate); 55 tmp = sysfs_get_idlestate_name(cpu, idlestate);
54 if (!tmp) 56 if (!tmp)
55 continue; 57 continue;
56 printf("%s:\n", tmp); 58 printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : "");
57 free(tmp); 59 free(tmp);
58 60
59 tmp = sysfs_get_idlestate_desc(cpu, idlestate); 61 tmp = sysfs_get_idlestate_desc(cpu, idlestate);
@@ -98,21 +100,13 @@ static void cpuidle_general_output(void)
98static void proc_cpuidle_cpu_output(unsigned int cpu) 100static void proc_cpuidle_cpu_output(unsigned int cpu)
99{ 101{
100 long max_allowed_cstate = 2000000000; 102 long max_allowed_cstate = 2000000000;
101 int cstates, cstate; 103 unsigned int cstate, cstates;
102 104
103 cstates = sysfs_get_idlestate_count(cpu); 105 cstates = sysfs_get_idlestate_count(cpu);
104 if (cstates == 0) { 106 if (cstates == 0) {
105 /* 107 printf(_("CPU %u: No C-states info\n"), cpu);
106 * Go on and print same useless info as you'd see with
107 * cat /proc/acpi/processor/../power
108 * printf(_("CPU %u: No C-states available\n"), cpu);
109 * return;
110 */
111 } else if (cstates <= 0) {
112 printf(_("CPU %u: Can't read C-state info\n"), cpu);
113 return; 108 return;
114 } 109 }
115 /* printf("Cstates: %d\n", cstates); */
116 110
117 printf(_("active state: C0\n")); 111 printf(_("active state: C0\n"));
118 printf(_("max_cstate: C%u\n"), cstates-1); 112 printf(_("max_cstate: C%u\n"), cstates-1);
diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c
new file mode 100644
index 000000000000..c78141c5dfac
--- /dev/null
+++ b/tools/power/cpupower/utils/cpuidle-set.c
@@ -0,0 +1,118 @@
1#include <unistd.h>
2#include <stdio.h>
3#include <errno.h>
4#include <stdlib.h>
5#include <limits.h>
6#include <string.h>
7#include <ctype.h>
8
9#include <getopt.h>
10
11#include "cpufreq.h"
12#include "helpers/helpers.h"
13#include "helpers/sysfs.h"
14
15static struct option info_opts[] = {
16 { .name = "disable", .has_arg = required_argument, .flag = NULL, .val = 'd'},
17 { .name = "enable", .has_arg = required_argument, .flag = NULL, .val = 'e'},
18 { },
19};
20
21
22int cmd_idle_set(int argc, char **argv)
23{
24 extern char *optarg;
25 extern int optind, opterr, optopt;
26 int ret = 0, cont = 1, param = 0, idlestate = 0;
27 unsigned int cpu = 0;
28
29 do {
30 ret = getopt_long(argc, argv, "d:e:", info_opts, NULL);
31 if (ret == -1)
32 break;
33 switch (ret) {
34 case '?':
35 param = '?';
36 cont = 0;
37 break;
38 case 'd':
39 if (param) {
40 param = -1;
41 cont = 0;
42 break;
43 }
44 param = ret;
45 idlestate = atoi(optarg);
46 break;
47 case 'e':
48 if (param) {
49 param = -1;
50 cont = 0;
51 break;
52 }
53 param = ret;
54 idlestate = atoi(optarg);
55 break;
56 case -1:
57 cont = 0;
58 break;
59 }
60 } while (cont);
61
62 switch (param) {
63 case -1:
64 printf(_("You can't specify more than one "
65 "output-specific argument\n"));
66 exit(EXIT_FAILURE);
67 case '?':
68 printf(_("invalid or unknown argument\n"));
69 exit(EXIT_FAILURE);
70 }
71
72 /* Default is: set all CPUs */
73 if (bitmask_isallclear(cpus_chosen))
74 bitmask_setall(cpus_chosen);
75
76 for (cpu = bitmask_first(cpus_chosen);
77 cpu <= bitmask_last(cpus_chosen); cpu++) {
78
79 if (!bitmask_isbitset(cpus_chosen, cpu))
80 continue;
81
82 switch (param) {
83
84 case 'd':
85 ret = sysfs_idlestate_disable(cpu, idlestate, 1);
86 if (ret == 0)
87 printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu);
88 else if (ret == -1)
89 printf(_("Idlestate %u not available on CPU %u\n"),
90 idlestate, cpu);
91 else if (ret == -2)
92 printf(_("Idlestate disabling not supported by kernel\n"));
93 else
94 printf(_("Idlestate %u not disabled on CPU %u\n"),
95 idlestate, cpu);
96 break;
97 case 'e':
98 ret = sysfs_idlestate_disable(cpu, idlestate, 0);
99 if (ret == 0)
100 printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu);
101 else if (ret == -1)
102 printf(_("Idlestate %u not available on CPU %u\n"),
103 idlestate, cpu);
104 else if (ret == -2)
105 printf(_("Idlestate enabling not supported by kernel\n"));
106 else
107 printf(_("Idlestate %u not enabled on CPU %u\n"),
108 idlestate, cpu);
109 break;
110 default:
111 /* Not reachable with proper args checking */
112 printf(_("Invalid or unknown argument\n"));
113 exit(EXIT_FAILURE);
114 break;
115 }
116 }
117 return EXIT_SUCCESS;
118}
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
index 52bee591c1c5..7efc570ffbaa 100644
--- a/tools/power/cpupower/utils/cpupower.c
+++ b/tools/power/cpupower/utils/cpupower.c
@@ -17,12 +17,6 @@
17#include "helpers/helpers.h" 17#include "helpers/helpers.h"
18#include "helpers/bitmask.h" 18#include "helpers/bitmask.h"
19 19
20struct cmd_struct {
21 const char *cmd;
22 int (*main)(int, const char **);
23 int needs_root;
24};
25
26#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 20#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
27 21
28static int cmd_help(int argc, const char **argv); 22static int cmd_help(int argc, const char **argv);
@@ -43,10 +37,17 @@ int be_verbose;
43 37
44static void print_help(void); 38static void print_help(void);
45 39
40struct cmd_struct {
41 const char *cmd;
42 int (*main)(int, const char **);
43 int needs_root;
44};
45
46static struct cmd_struct commands[] = { 46static struct cmd_struct commands[] = {
47 { "frequency-info", cmd_freq_info, 0 }, 47 { "frequency-info", cmd_freq_info, 0 },
48 { "frequency-set", cmd_freq_set, 1 }, 48 { "frequency-set", cmd_freq_set, 1 },
49 { "idle-info", cmd_idle_info, 0 }, 49 { "idle-info", cmd_idle_info, 0 },
50 { "idle-set", cmd_idle_set, 1 },
50 { "set", cmd_set, 1 }, 51 { "set", cmd_set, 1 },
51 { "info", cmd_info, 0 }, 52 { "info", cmd_info, 0 },
52 { "monitor", cmd_monitor, 0 }, 53 { "monitor", cmd_monitor, 0 },
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 38ab91629463..5cdc600e8152 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -89,6 +89,33 @@ int sysfs_is_cpu_online(unsigned int cpu)
89 89
90/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ 90/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
91 91
92
93/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
94
95/*
96 * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
97 * exists.
98 * For example the functionality to disable c-states was introduced in later
99 * kernel versions, this function can be used to explicitly check for this
100 * feature.
101 *
102 * returns 1 if the file exists, 0 otherwise.
103 */
104unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
105 unsigned int idlestate,
106 const char *fname)
107{
108 char path[SYSFS_PATH_MAX];
109 struct stat statbuf;
110
111
112 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
113 cpu, idlestate, fname);
114 if (stat(path, &statbuf) != 0)
115 return 0;
116 return 1;
117}
118
92/* 119/*
93 * helper function to read file from /sys into given buffer 120 * helper function to read file from /sys into given buffer
94 * fname is a relative path under "cpuX/cpuidle/stateX/" dir 121 * fname is a relative path under "cpuX/cpuidle/stateX/" dir
@@ -121,6 +148,40 @@ unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
121 return (unsigned int) numread; 148 return (unsigned int) numread;
122} 149}
123 150
151/*
152 * helper function to write a new value to a /sys file
153 * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
154 *
155 * Returns the number of bytes written or 0 on error
156 */
157static
158unsigned int sysfs_idlestate_write_file(unsigned int cpu,
159 unsigned int idlestate,
160 const char *fname,
161 const char *value, size_t len)
162{
163 char path[SYSFS_PATH_MAX];
164 int fd;
165 ssize_t numwrite;
166
167 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
168 cpu, idlestate, fname);
169
170 fd = open(path, O_WRONLY);
171 if (fd == -1)
172 return 0;
173
174 numwrite = write(fd, value, len);
175 if (numwrite < 1) {
176 close(fd);
177 return 0;
178 }
179
180 close(fd);
181
182 return (unsigned int) numwrite;
183}
184
124/* read access to files which contain one numeric value */ 185/* read access to files which contain one numeric value */
125 186
126enum idlestate_value { 187enum idlestate_value {
@@ -128,6 +189,7 @@ enum idlestate_value {
128 IDLESTATE_POWER, 189 IDLESTATE_POWER,
129 IDLESTATE_LATENCY, 190 IDLESTATE_LATENCY,
130 IDLESTATE_TIME, 191 IDLESTATE_TIME,
192 IDLESTATE_DISABLE,
131 MAX_IDLESTATE_VALUE_FILES 193 MAX_IDLESTATE_VALUE_FILES
132}; 194};
133 195
@@ -136,6 +198,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
136 [IDLESTATE_POWER] = "power", 198 [IDLESTATE_POWER] = "power",
137 [IDLESTATE_LATENCY] = "latency", 199 [IDLESTATE_LATENCY] = "latency",
138 [IDLESTATE_TIME] = "time", 200 [IDLESTATE_TIME] = "time",
201 [IDLESTATE_DISABLE] = "disable",
139}; 202};
140 203
141static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu, 204static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
@@ -205,8 +268,59 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu,
205 return result; 268 return result;
206} 269}
207 270
271/*
272 * Returns:
273 * 1 if disabled
274 * 0 if enabled
275 * -1 if idlestate is not available
276 * -2 if disabling is not supported by the kernel
277 */
278int sysfs_is_idlestate_disabled(unsigned int cpu,
279 unsigned int idlestate)
280{
281 if (sysfs_get_idlestate_count(cpu) < idlestate)
282 return -1;
283
284 if (!sysfs_idlestate_file_exists(cpu, idlestate,
285 idlestate_value_files[IDLESTATE_DISABLE]))
286 return -2;
287 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
288}
289
290/*
291 * Pass 1 as last argument to disable or 0 to enable the state
292 * Returns:
293 * 0 on success
294 * negative values on error, for example:
295 * -1 if idlestate is not available
296 * -2 if disabling is not supported by the kernel
297 * -3 No write access to disable/enable C-states
298 */
299int sysfs_idlestate_disable(unsigned int cpu,
300 unsigned int idlestate,
301 unsigned int disable)
302{
303 char value[SYSFS_PATH_MAX];
304 int bytes_written;
305
306 if (sysfs_get_idlestate_count(cpu) < idlestate)
307 return -1;
308
309 if (!sysfs_idlestate_file_exists(cpu, idlestate,
310 idlestate_value_files[IDLESTATE_DISABLE]))
311 return -2;
312
313 snprintf(value, SYSFS_PATH_MAX, "%u", disable);
314
315 bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable",
316 value, sizeof(disable));
317 if (bytes_written)
318 return 0;
319 return -3;
320}
321
208unsigned long sysfs_get_idlestate_latency(unsigned int cpu, 322unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
209 unsigned int idlestate) 323 unsigned int idlestate)
210{ 324{
211 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); 325 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
212} 326}
@@ -238,7 +352,7 @@ char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
238 * Negativ in error case 352 * Negativ in error case
239 * Zero if cpuidle does not export any C-states 353 * Zero if cpuidle does not export any C-states
240 */ 354 */
241int sysfs_get_idlestate_count(unsigned int cpu) 355unsigned int sysfs_get_idlestate_count(unsigned int cpu)
242{ 356{
243 char file[SYSFS_PATH_MAX]; 357 char file[SYSFS_PATH_MAX];
244 struct stat statbuf; 358 struct stat statbuf;
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h
index 8cb797bbceb0..d28f11fedbda 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.h
+++ b/tools/power/cpupower/utils/helpers/sysfs.h
@@ -7,8 +7,16 @@
7 7
8extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); 8extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
9 9
10extern unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
11 unsigned int idlestate,
12 const char *fname);
13
10extern int sysfs_is_cpu_online(unsigned int cpu); 14extern int sysfs_is_cpu_online(unsigned int cpu);
11 15
16extern int sysfs_is_idlestate_disabled(unsigned int cpu,
17 unsigned int idlestate);
18extern int sysfs_idlestate_disable(unsigned int cpu, unsigned int idlestate,
19 unsigned int disable);
12extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, 20extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
13 unsigned int idlestate); 21 unsigned int idlestate);
14extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, 22extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
@@ -19,7 +27,7 @@ extern char *sysfs_get_idlestate_name(unsigned int cpu,
19 unsigned int idlestate); 27 unsigned int idlestate);
20extern char *sysfs_get_idlestate_desc(unsigned int cpu, 28extern char *sysfs_get_idlestate_desc(unsigned int cpu,
21 unsigned int idlestate); 29 unsigned int idlestate);
22extern int sysfs_get_idlestate_count(unsigned int cpu); 30extern unsigned int sysfs_get_idlestate_count(unsigned int cpu);
23 31
24extern char *sysfs_get_cpuidle_governor(void); 32extern char *sysfs_get_cpuidle_governor(void);
25extern char *sysfs_get_cpuidle_driver(void); 33extern char *sysfs_get_cpuidle_driver(void);
diff --git a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
new file mode 100644
index 000000000000..ebeaba6571a3
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
@@ -0,0 +1,196 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * Based on SandyBridge monitor. Implements the new package C-states
7 * (PC8, PC9, PC10) coming with a specific Haswell (family 0x45) CPU.
8 */
9
10#if defined(__i386__) || defined(__x86_64__)
11
12#include <stdio.h>
13#include <stdint.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include "helpers/helpers.h"
18#include "idle_monitor/cpupower-monitor.h"
19
20#define MSR_PKG_C8_RESIDENCY 0x00000630
21#define MSR_PKG_C9_RESIDENCY 0x00000631
22#define MSR_PKG_C10_RESIDENCY 0x00000632
23
24#define MSR_TSC 0x10
25
26enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT,
27 TSC = 0xFFFF };
28
29static int hsw_ext_get_count_percent(unsigned int self_id, double *percent,
30 unsigned int cpu);
31
32static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = {
33 {
34 .name = "PC8",
35 .desc = N_("Processor Package C8"),
36 .id = PC8,
37 .range = RANGE_PACKAGE,
38 .get_count_percent = hsw_ext_get_count_percent,
39 },
40 {
41 .name = "PC9",
42 .desc = N_("Processor Package C9"),
43 .desc = N_("Processor Package C2"),
44 .id = PC9,
45 .range = RANGE_PACKAGE,
46 .get_count_percent = hsw_ext_get_count_percent,
47 },
48 {
49 .name = "PC10",
50 .desc = N_("Processor Package C10"),
51 .id = PC10,
52 .range = RANGE_PACKAGE,
53 .get_count_percent = hsw_ext_get_count_percent,
54 },
55};
56
57static unsigned long long tsc_at_measure_start;
58static unsigned long long tsc_at_measure_end;
59static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT];
60static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT];
61/* valid flag for all CPUs. If a MSR read failed it will be zero */
62static int *is_valid;
63
64static int hsw_ext_get_count(enum intel_hsw_ext_id id, unsigned long long *val,
65 unsigned int cpu)
66{
67 int msr;
68
69 switch (id) {
70 case PC8:
71 msr = MSR_PKG_C8_RESIDENCY;
72 break;
73 case PC9:
74 msr = MSR_PKG_C9_RESIDENCY;
75 break;
76 case PC10:
77 msr = MSR_PKG_C10_RESIDENCY;
78 break;
79 case TSC:
80 msr = MSR_TSC;
81 break;
82 default:
83 return -1;
84 };
85 if (read_msr(cpu, msr, val))
86 return -1;
87 return 0;
88}
89
90static int hsw_ext_get_count_percent(unsigned int id, double *percent,
91 unsigned int cpu)
92{
93 *percent = 0.0;
94
95 if (!is_valid[cpu])
96 return -1;
97
98 *percent = (100.0 *
99 (current_count[id][cpu] - previous_count[id][cpu])) /
100 (tsc_at_measure_end - tsc_at_measure_start);
101
102 dprint("%s: previous: %llu - current: %llu - (%u)\n",
103 hsw_ext_cstates[id].name, previous_count[id][cpu],
104 current_count[id][cpu], cpu);
105
106 dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
107 hsw_ext_cstates[id].name,
108 (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
109 current_count[id][cpu] - previous_count[id][cpu],
110 *percent, cpu);
111
112 return 0;
113}
114
115static int hsw_ext_start(void)
116{
117 int num, cpu;
118 unsigned long long val;
119
120 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
121 for (cpu = 0; cpu < cpu_count; cpu++) {
122 hsw_ext_get_count(num, &val, cpu);
123 previous_count[num][cpu] = val;
124 }
125 }
126 hsw_ext_get_count(TSC, &tsc_at_measure_start, 0);
127 return 0;
128}
129
130static int hsw_ext_stop(void)
131{
132 unsigned long long val;
133 int num, cpu;
134
135 hsw_ext_get_count(TSC, &tsc_at_measure_end, 0);
136
137 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
138 for (cpu = 0; cpu < cpu_count; cpu++) {
139 is_valid[cpu] = !hsw_ext_get_count(num, &val, cpu);
140 current_count[num][cpu] = val;
141 }
142 }
143 return 0;
144}
145
146struct cpuidle_monitor intel_hsw_ext_monitor;
147
148static struct cpuidle_monitor *hsw_ext_register(void)
149{
150 int num;
151
152 if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL
153 || cpupower_cpu_info.family != 6)
154 return NULL;
155
156 switch (cpupower_cpu_info.model) {
157 case 0x45: /* HSW */
158 break;
159 default:
160 return NULL;
161 }
162
163 is_valid = calloc(cpu_count, sizeof(int));
164 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
165 previous_count[num] = calloc(cpu_count,
166 sizeof(unsigned long long));
167 current_count[num] = calloc(cpu_count,
168 sizeof(unsigned long long));
169 }
170 intel_hsw_ext_monitor.name_len = strlen(intel_hsw_ext_monitor.name);
171 return &intel_hsw_ext_monitor;
172}
173
174void hsw_ext_unregister(void)
175{
176 int num;
177 free(is_valid);
178 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
179 free(previous_count[num]);
180 free(current_count[num]);
181 }
182}
183
184struct cpuidle_monitor intel_hsw_ext_monitor = {
185 .name = "HaswellExtended",
186 .hw_states = hsw_ext_cstates,
187 .hw_states_num = HSW_EXT_CSTATE_COUNT,
188 .start = hsw_ext_start,
189 .stop = hsw_ext_stop,
190 .do_register = hsw_ext_register,
191 .unregister = hsw_ext_unregister,
192 .needs_root = 1,
193 .overflow_s = 922000000 /* 922337203 seconds TSC overflow
194 at 20GHz */
195};
196#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
index e3f8d9b2b18f..0d6ba4dbb9c7 100644
--- a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
+++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
@@ -2,6 +2,7 @@
2DEF(amd_fam14h) 2DEF(amd_fam14h)
3DEF(intel_nhm) 3DEF(intel_nhm)
4DEF(intel_snb) 4DEF(intel_snb)
5DEF(intel_hsw_ext)
5DEF(mperf) 6DEF(mperf)
6#endif 7#endif
7DEF(cpuidle_sysfs) 8DEF(cpuidle_sysfs)
diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
index a99b43b97d6d..efc8a69c9aba 100644
--- a/tools/power/cpupower/utils/idle_monitor/snb_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
@@ -155,6 +155,10 @@ static struct cpuidle_monitor *snb_register(void)
155 case 0x2D: /* SNB Xeon */ 155 case 0x2D: /* SNB Xeon */
156 case 0x3A: /* IVB */ 156 case 0x3A: /* IVB */
157 case 0x3E: /* IVB Xeon */ 157 case 0x3E: /* IVB Xeon */
158 case 0x3C: /* HSW */
159 case 0x3F: /* HSW */
160 case 0x45: /* HSW */
161 case 0x46: /* HSW */
158 break; 162 break;
159 default: 163 default:
160 return NULL; 164 return NULL;
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 9e9d34871195..fe702076ca46 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -2191,7 +2191,7 @@ int initialize_counters(int cpu_id)
2191 2191
2192void allocate_output_buffer() 2192void allocate_output_buffer()
2193{ 2193{
2194 output_buffer = calloc(1, (1 + topo.num_cpus) * 128); 2194 output_buffer = calloc(1, (1 + topo.num_cpus) * 256);
2195 outp = output_buffer; 2195 outp = output_buffer;
2196 if (outp == NULL) { 2196 if (outp == NULL) {
2197 perror("calloc"); 2197 perror("calloc");
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index f03e681f8891..0d0506d55c71 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -59,7 +59,7 @@ 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)
62ifndef V 62ifneq ($(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 $@;
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 0d7fd8b51544..999eab1bc64f 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -1796,7 +1796,7 @@ sub monitor {
1796 # We already booted into the kernel we are testing, 1796 # We already booted into the kernel we are testing,
1797 # but now we booted into another kernel? 1797 # but now we booted into another kernel?
1798 # Consider this a triple fault. 1798 # Consider this a triple fault.
1799 doprint "Aleady booted in Linux kernel $version, but now\n"; 1799 doprint "Already booted in Linux kernel $version, but now\n";
1800 doprint "we booted into Linux kernel $1.\n"; 1800 doprint "we booted into Linux kernel $1.\n";
1801 doprint "Assuming that this is a triple fault.\n"; 1801 doprint "Assuming that this is a triple fault.\n";
1802 doprint "To disable this: set DETECT_TRIPLE_FAULT to 0\n"; 1802 doprint "To disable this: set DETECT_TRIPLE_FAULT to 0\n";
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 0a63658065f0..9f3eae290900 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -6,7 +6,9 @@ TARGETS += memory-hotplug
6TARGETS += mqueue 6TARGETS += mqueue
7TARGETS += net 7TARGETS += net
8TARGETS += ptrace 8TARGETS += ptrace
9TARGETS += timers
9TARGETS += vm 10TARGETS += vm
11TARGETS += powerpc
10 12
11all: 13all:
12 for TARGET in $(TARGETS); do \ 14 for TARGET in $(TARGETS); do \
diff --git a/tools/testing/selftests/cpu-hotplug/Makefile b/tools/testing/selftests/cpu-hotplug/Makefile
index 12657a5e4bf9..ae5faf9aade2 100644
--- a/tools/testing/selftests/cpu-hotplug/Makefile
+++ b/tools/testing/selftests/cpu-hotplug/Makefile
@@ -1,6 +1,6 @@
1all: 1all:
2 2
3run_tests: 3run_tests:
4 @./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]" 4 @/bin/sh ./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]"
5 5
6clean: 6clean:
diff --git a/tools/testing/selftests/kcmp/.gitignore b/tools/testing/selftests/kcmp/.gitignore
new file mode 100644
index 000000000000..5a9b3732b2de
--- /dev/null
+++ b/tools/testing/selftests/kcmp/.gitignore
@@ -0,0 +1,2 @@
1kcmp_test
2kcmp-test-file
diff --git a/tools/testing/selftests/kcmp/Makefile b/tools/testing/selftests/kcmp/Makefile
index 56eb5523dbb8..d7d6bbeeff2f 100644
--- a/tools/testing/selftests/kcmp/Makefile
+++ b/tools/testing/selftests/kcmp/Makefile
@@ -25,5 +25,4 @@ run_tests: all
25 @./kcmp_test || echo "kcmp_test: [FAIL]" 25 @./kcmp_test || echo "kcmp_test: [FAIL]"
26 26
27clean: 27clean:
28 rm -fr ./run_test 28 $(RM) kcmp_test kcmp-test-file
29 rm -fr ./test-file
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile
index 0f49c3f5f58d..350bfeda3aa8 100644
--- a/tools/testing/selftests/memory-hotplug/Makefile
+++ b/tools/testing/selftests/memory-hotplug/Makefile
@@ -1,6 +1,6 @@
1all: 1all:
2 2
3run_tests: 3run_tests:
4 @./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]" 4 @/bin/sh ./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]"
5 5
6clean: 6clean:
diff --git a/tools/testing/selftests/net/psock_tpacket.c b/tools/testing/selftests/net/psock_tpacket.c
index c41b58640a05..24adf709bd9d 100644
--- a/tools/testing/selftests/net/psock_tpacket.c
+++ b/tools/testing/selftests/net/psock_tpacket.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * Copyright 2013 Red Hat, Inc. 2 * Copyright 2013 Red Hat, Inc.
3 * Author: Daniel Borkmann <dborkman@redhat.com> 3 * Author: Daniel Borkmann <dborkman@redhat.com>
4 * Chetan Loke <loke.chetan@gmail.com> (TPACKET_V3 usage example)
4 * 5 *
5 * A basic test of packet socket's TPACKET_V1/TPACKET_V2/TPACKET_V3 behavior. 6 * A basic test of packet socket's TPACKET_V1/TPACKET_V2/TPACKET_V3 behavior.
6 * 7 *
@@ -71,18 +72,8 @@
71# define __align_tpacket(x) __attribute__((aligned(TPACKET_ALIGN(x)))) 72# define __align_tpacket(x) __attribute__((aligned(TPACKET_ALIGN(x))))
72#endif 73#endif
73 74
74#define BLOCK_STATUS(x) ((x)->h1.block_status)
75#define BLOCK_NUM_PKTS(x) ((x)->h1.num_pkts)
76#define BLOCK_O2FP(x) ((x)->h1.offset_to_first_pkt)
77#define BLOCK_LEN(x) ((x)->h1.blk_len)
78#define BLOCK_SNUM(x) ((x)->h1.seq_num)
79#define BLOCK_O2PRIV(x) ((x)->offset_to_priv)
80#define BLOCK_PRIV(x) ((void *) ((uint8_t *) (x) + BLOCK_O2PRIV(x)))
81#define BLOCK_HDR_LEN (ALIGN_8(sizeof(struct block_desc)))
82#define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1))
83#define BLOCK_PLUS_PRIV(sz_pri) (BLOCK_HDR_LEN + ALIGN_8((sz_pri)))
84
85#define NUM_PACKETS 100 75#define NUM_PACKETS 100
76#define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1))
86 77
87struct ring { 78struct ring {
88 struct iovec *rd; 79 struct iovec *rd;
@@ -476,41 +467,30 @@ static uint64_t __v3_prev_block_seq_num = 0;
476 467
477void __v3_test_block_seq_num(struct block_desc *pbd) 468void __v3_test_block_seq_num(struct block_desc *pbd)
478{ 469{
479 if (__v3_prev_block_seq_num + 1 != BLOCK_SNUM(pbd)) { 470 if (__v3_prev_block_seq_num + 1 != pbd->h1.seq_num) {
480 fprintf(stderr, "\nprev_block_seq_num:%"PRIu64", expected " 471 fprintf(stderr, "\nprev_block_seq_num:%"PRIu64", expected "
481 "seq:%"PRIu64" != actual seq:%"PRIu64"\n", 472 "seq:%"PRIu64" != actual seq:%"PRIu64"\n",
482 __v3_prev_block_seq_num, __v3_prev_block_seq_num + 1, 473 __v3_prev_block_seq_num, __v3_prev_block_seq_num + 1,
483 (uint64_t) BLOCK_SNUM(pbd)); 474 (uint64_t) pbd->h1.seq_num);
484 exit(1); 475 exit(1);
485 } 476 }
486 477
487 __v3_prev_block_seq_num = BLOCK_SNUM(pbd); 478 __v3_prev_block_seq_num = pbd->h1.seq_num;
488} 479}
489 480
490static void __v3_test_block_len(struct block_desc *pbd, uint32_t bytes, int block_num) 481static void __v3_test_block_len(struct block_desc *pbd, uint32_t bytes, int block_num)
491{ 482{
492 if (BLOCK_NUM_PKTS(pbd)) { 483 if (pbd->h1.num_pkts && bytes != pbd->h1.blk_len) {
493 if (bytes != BLOCK_LEN(pbd)) { 484 fprintf(stderr, "\nblock:%u with %upackets, expected "
494 fprintf(stderr, "\nblock:%u with %upackets, expected " 485 "len:%u != actual len:%u\n", block_num,
495 "len:%u != actual len:%u\n", block_num, 486 pbd->h1.num_pkts, bytes, pbd->h1.blk_len);
496 BLOCK_NUM_PKTS(pbd), bytes, BLOCK_LEN(pbd)); 487 exit(1);
497 exit(1);
498 }
499 } else {
500 if (BLOCK_LEN(pbd) != BLOCK_PLUS_PRIV(13)) {
501 fprintf(stderr, "\nblock:%u, expected len:%lu != "
502 "actual len:%u\n", block_num, BLOCK_HDR_LEN,
503 BLOCK_LEN(pbd));
504 exit(1);
505 }
506 } 488 }
507} 489}
508 490
509static void __v3_test_block_header(struct block_desc *pbd, const int block_num) 491static void __v3_test_block_header(struct block_desc *pbd, const int block_num)
510{ 492{
511 uint32_t block_status = BLOCK_STATUS(pbd); 493 if ((pbd->h1.block_status & TP_STATUS_USER) == 0) {
512
513 if ((block_status & TP_STATUS_USER) == 0) {
514 fprintf(stderr, "\nblock %u: not in TP_STATUS_USER\n", block_num); 494 fprintf(stderr, "\nblock %u: not in TP_STATUS_USER\n", block_num);
515 exit(1); 495 exit(1);
516 } 496 }
@@ -520,14 +500,15 @@ static void __v3_test_block_header(struct block_desc *pbd, const int block_num)
520 500
521static void __v3_walk_block(struct block_desc *pbd, const int block_num) 501static void __v3_walk_block(struct block_desc *pbd, const int block_num)
522{ 502{
523 int num_pkts = BLOCK_NUM_PKTS(pbd), i; 503 int num_pkts = pbd->h1.num_pkts, i;
524 unsigned long bytes = 0; 504 unsigned long bytes = 0, bytes_with_padding = ALIGN_8(sizeof(*pbd));
525 unsigned long bytes_with_padding = BLOCK_PLUS_PRIV(13);
526 struct tpacket3_hdr *ppd; 505 struct tpacket3_hdr *ppd;
527 506
528 __v3_test_block_header(pbd, block_num); 507 __v3_test_block_header(pbd, block_num);
529 508
530 ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd + BLOCK_O2FP(pbd)); 509 ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd +
510 pbd->h1.offset_to_first_pkt);
511
531 for (i = 0; i < num_pkts; ++i) { 512 for (i = 0; i < num_pkts; ++i) {
532 bytes += ppd->tp_snaplen; 513 bytes += ppd->tp_snaplen;
533 514
@@ -551,7 +532,7 @@ static void __v3_walk_block(struct block_desc *pbd, const int block_num)
551 532
552void __v3_flush_block(struct block_desc *pbd) 533void __v3_flush_block(struct block_desc *pbd)
553{ 534{
554 BLOCK_STATUS(pbd) = TP_STATUS_KERNEL; 535 pbd->h1.block_status = TP_STATUS_KERNEL;
555 __sync_synchronize(); 536 __sync_synchronize();
556} 537}
557 538
@@ -577,7 +558,7 @@ static void walk_v3_rx(int sock, struct ring *ring)
577 while (total_packets < NUM_PACKETS * 2) { 558 while (total_packets < NUM_PACKETS * 2) {
578 pbd = (struct block_desc *) ring->rd[block_num].iov_base; 559 pbd = (struct block_desc *) ring->rd[block_num].iov_base;
579 560
580 while ((BLOCK_STATUS(pbd) & TP_STATUS_USER) == 0) 561 while ((pbd->h1.block_status & TP_STATUS_USER) == 0)
581 poll(&pfd, 1, 1); 562 poll(&pfd, 1, 1);
582 563
583 __v3_walk_block(pbd, block_num); 564 __v3_walk_block(pbd, block_num);
@@ -624,8 +605,8 @@ static void __v1_v2_fill(struct ring *ring, unsigned int blocks)
624static void __v3_fill(struct ring *ring, unsigned int blocks) 605static void __v3_fill(struct ring *ring, unsigned int blocks)
625{ 606{
626 ring->req3.tp_retire_blk_tov = 64; 607 ring->req3.tp_retire_blk_tov = 64;
627 ring->req3.tp_sizeof_priv = 13; 608 ring->req3.tp_sizeof_priv = 0;
628 ring->req3.tp_feature_req_word |= TP_FT_REQ_FILL_RXHASH; 609 ring->req3.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH;
629 610
630 ring->req3.tp_block_size = getpagesize() << 2; 611 ring->req3.tp_block_size = getpagesize() << 2;
631 ring->req3.tp_frame_size = TPACKET_ALIGNMENT << 7; 612 ring->req3.tp_frame_size = TPACKET_ALIGNMENT << 7;
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
new file mode 100644
index 000000000000..bd24ae5aaeab
--- /dev/null
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -0,0 +1,39 @@
1# Makefile for powerpc selftests
2
3# ARCH can be overridden by the user for cross compiling
4ARCH ?= $(shell uname -m)
5ARCH := $(shell echo $(ARCH) | sed -e s/ppc.*/powerpc/)
6
7ifeq ($(ARCH),powerpc)
8
9GIT_VERSION = $(shell git describe --always --long --dirty || echo "unknown")
10
11CC := $(CROSS_COMPILE)$(CC)
12CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CURDIR) $(CFLAGS)
13
14export CC CFLAGS
15
16TARGETS = pmu
17
18endif
19
20all:
21 @for TARGET in $(TARGETS); do \
22 $(MAKE) -C $$TARGET all; \
23 done;
24
25run_tests: all
26 @for TARGET in $(TARGETS); do \
27 $(MAKE) -C $$TARGET run_tests; \
28 done;
29
30clean:
31 @for TARGET in $(TARGETS); do \
32 $(MAKE) -C $$TARGET clean; \
33 done;
34 rm -f tags
35
36tags:
37 find . -name '*.c' -o -name '*.h' | xargs ctags
38
39.PHONY: all run_tests clean tags
diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c
new file mode 100644
index 000000000000..e80c42a584fe
--- /dev/null
+++ b/tools/testing/selftests/powerpc/harness.c
@@ -0,0 +1,105 @@
1/*
2 * Copyright 2013, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <errno.h>
7#include <signal.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <sys/types.h>
12#include <sys/wait.h>
13#include <unistd.h>
14
15#include "subunit.h"
16#include "utils.h"
17
18#define TIMEOUT 120
19#define KILL_TIMEOUT 5
20
21
22int run_test(int (test_function)(void), char *name)
23{
24 bool terminated;
25 int rc, status;
26 pid_t pid;
27
28 /* Make sure output is flushed before forking */
29 fflush(stdout);
30
31 pid = fork();
32 if (pid == 0) {
33 exit(test_function());
34 } else if (pid == -1) {
35 perror("fork");
36 return 1;
37 }
38
39 /* Wake us up in timeout seconds */
40 alarm(TIMEOUT);
41 terminated = false;
42
43wait:
44 rc = waitpid(pid, &status, 0);
45 if (rc == -1) {
46 if (errno != EINTR) {
47 printf("unknown error from waitpid\n");
48 return 1;
49 }
50
51 if (terminated) {
52 printf("!! force killing %s\n", name);
53 kill(pid, SIGKILL);
54 return 1;
55 } else {
56 printf("!! killing %s\n", name);
57 kill(pid, SIGTERM);
58 terminated = true;
59 alarm(KILL_TIMEOUT);
60 goto wait;
61 }
62 }
63
64 if (WIFEXITED(status))
65 status = WEXITSTATUS(status);
66 else {
67 if (WIFSIGNALED(status))
68 printf("!! child died by signal %d\n", WTERMSIG(status));
69 else
70 printf("!! child died by unknown cause\n");
71
72 status = 1; /* Signal or other */
73 }
74
75 return status;
76}
77
78static void alarm_handler(int signum)
79{
80 /* Jut wake us up from waitpid */
81}
82
83static struct sigaction alarm_action = {
84 .sa_handler = alarm_handler,
85};
86
87int test_harness(int (test_function)(void), char *name)
88{
89 int rc;
90
91 test_start(name);
92 test_set_git_version(GIT_VERSION);
93
94 if (sigaction(SIGALRM, &alarm_action, NULL)) {
95 perror("sigaction");
96 test_error(name);
97 return 1;
98 }
99
100 rc = run_test(test_function, name);
101
102 test_finish(name, rc);
103
104 return rc;
105}
diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile
new file mode 100644
index 000000000000..7216f0091655
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/Makefile
@@ -0,0 +1,23 @@
1noarg:
2 $(MAKE) -C ../
3
4PROGS := count_instructions
5EXTRA_SOURCES := ../harness.c event.c
6
7all: $(PROGS)
8
9$(PROGS): $(EXTRA_SOURCES)
10
11# loop.S can only be built 64-bit
12count_instructions: loop.S count_instructions.c $(EXTRA_SOURCES)
13 $(CC) $(CFLAGS) -m64 -o $@ $^
14
15run_tests: all
16 @-for PROG in $(PROGS); do \
17 ./$$PROG; \
18 done;
19
20clean:
21 rm -f $(PROGS) loop.o
22
23.PHONY: all run_tests clean
diff --git a/tools/testing/selftests/powerpc/pmu/count_instructions.c b/tools/testing/selftests/powerpc/pmu/count_instructions.c
new file mode 100644
index 000000000000..312b4f0fd27c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/count_instructions.c
@@ -0,0 +1,135 @@
1/*
2 * Copyright 2013, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#define _GNU_SOURCE
7
8#include <stdio.h>
9#include <stdbool.h>
10#include <string.h>
11#include <sys/prctl.h>
12
13#include "event.h"
14#include "utils.h"
15
16extern void thirty_two_instruction_loop(u64 loops);
17
18static void setup_event(struct event *e, u64 config, char *name)
19{
20 event_init_opts(e, config, PERF_TYPE_HARDWARE, name);
21
22 e->attr.disabled = 1;
23 e->attr.exclude_kernel = 1;
24 e->attr.exclude_hv = 1;
25 e->attr.exclude_idle = 1;
26}
27
28static int do_count_loop(struct event *events, u64 instructions,
29 u64 overhead, bool report)
30{
31 s64 difference, expected;
32 double percentage;
33
34 prctl(PR_TASK_PERF_EVENTS_ENABLE);
35
36 /* Run for 1M instructions */
37 thirty_two_instruction_loop(instructions >> 5);
38
39 prctl(PR_TASK_PERF_EVENTS_DISABLE);
40
41 event_read(&events[0]);
42 event_read(&events[1]);
43
44 expected = instructions + overhead;
45 difference = events[0].result.value - expected;
46 percentage = (double)difference / events[0].result.value * 100;
47
48 if (report) {
49 event_report(&events[0]);
50 event_report(&events[1]);
51
52 printf("Looped for %llu instructions, overhead %llu\n", instructions, overhead);
53 printf("Expected %llu\n", expected);
54 printf("Actual %llu\n", events[0].result.value);
55 printf("Delta %lld, %f%%\n", difference, percentage);
56 }
57
58 event_reset(&events[0]);
59 event_reset(&events[1]);
60
61 if (difference < 0)
62 difference = -difference;
63
64 /* Tolerate a difference below 0.0001 % */
65 difference *= 10000 * 100;
66 if (difference / events[0].result.value)
67 return -1;
68
69 return 0;
70}
71
72/* Count how many instructions it takes to do a null loop */
73static u64 determine_overhead(struct event *events)
74{
75 u64 current, overhead;
76 int i;
77
78 do_count_loop(events, 0, 0, false);
79 overhead = events[0].result.value;
80
81 for (i = 0; i < 100; i++) {
82 do_count_loop(events, 0, 0, false);
83 current = events[0].result.value;
84 if (current < overhead) {
85 printf("Replacing overhead %llu with %llu\n", overhead, current);
86 overhead = current;
87 }
88 }
89
90 return overhead;
91}
92
93static int count_instructions(void)
94{
95 struct event events[2];
96 u64 overhead;
97
98 setup_event(&events[0], PERF_COUNT_HW_INSTRUCTIONS, "instructions");
99 setup_event(&events[1], PERF_COUNT_HW_CPU_CYCLES, "cycles");
100
101 if (event_open(&events[0])) {
102 perror("perf_event_open");
103 return -1;
104 }
105
106 if (event_open_with_group(&events[1], events[0].fd)) {
107 perror("perf_event_open");
108 return -1;
109 }
110
111 overhead = determine_overhead(events);
112 printf("Overhead of null loop: %llu instructions\n", overhead);
113
114 /* Run for 1M instructions */
115 FAIL_IF(do_count_loop(events, 0x100000, overhead, true));
116
117 /* Run for 10M instructions */
118 FAIL_IF(do_count_loop(events, 0xa00000, overhead, true));
119
120 /* Run for 100M instructions */
121 FAIL_IF(do_count_loop(events, 0x6400000, overhead, true));
122
123 /* Run for 1G instructions */
124 FAIL_IF(do_count_loop(events, 0x40000000, overhead, true));
125
126 event_close(&events[0]);
127 event_close(&events[1]);
128
129 return 0;
130}
131
132int main(void)
133{
134 return test_harness(count_instructions, "count_instructions");
135}
diff --git a/tools/testing/selftests/powerpc/pmu/event.c b/tools/testing/selftests/powerpc/pmu/event.c
new file mode 100644
index 000000000000..2b2d11df2450
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/event.c
@@ -0,0 +1,105 @@
1/*
2 * Copyright 2013, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#define _GNU_SOURCE
7#include <unistd.h>
8#include <sys/syscall.h>
9#include <string.h>
10#include <stdio.h>
11#include <sys/ioctl.h>
12
13#include "event.h"
14
15
16int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu,
17 int group_fd, unsigned long flags)
18{
19 return syscall(__NR_perf_event_open, attr, pid, cpu,
20 group_fd, flags);
21}
22
23void event_init_opts(struct event *e, u64 config, int type, char *name)
24{
25 memset(e, 0, sizeof(*e));
26
27 e->name = name;
28
29 e->attr.type = type;
30 e->attr.config = config;
31 e->attr.size = sizeof(e->attr);
32 /* This has to match the structure layout in the header */
33 e->attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | \
34 PERF_FORMAT_TOTAL_TIME_RUNNING;
35}
36
37void event_init_named(struct event *e, u64 config, char *name)
38{
39 event_init_opts(e, config, PERF_TYPE_RAW, name);
40}
41
42#define PERF_CURRENT_PID 0
43#define PERF_NO_CPU -1
44#define PERF_NO_GROUP -1
45
46int event_open_with_options(struct event *e, pid_t pid, int cpu, int group_fd)
47{
48 e->fd = perf_event_open(&e->attr, pid, cpu, group_fd, 0);
49 if (e->fd == -1) {
50 perror("perf_event_open");
51 return -1;
52 }
53
54 return 0;
55}
56
57int event_open_with_group(struct event *e, int group_fd)
58{
59 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, group_fd);
60}
61
62int event_open(struct event *e)
63{
64 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, PERF_NO_GROUP);
65}
66
67void event_close(struct event *e)
68{
69 close(e->fd);
70}
71
72int event_reset(struct event *e)
73{
74 return ioctl(e->fd, PERF_EVENT_IOC_RESET);
75}
76
77int event_read(struct event *e)
78{
79 int rc;
80
81 rc = read(e->fd, &e->result, sizeof(e->result));
82 if (rc != sizeof(e->result)) {
83 fprintf(stderr, "read error on event %p!\n", e);
84 return -1;
85 }
86
87 return 0;
88}
89
90void event_report_justified(struct event *e, int name_width, int result_width)
91{
92 printf("%*s: result %*llu ", name_width, e->name, result_width,
93 e->result.value);
94
95 if (e->result.running == e->result.enabled)
96 printf("running/enabled %llu\n", e->result.running);
97 else
98 printf("running %llu enabled %llu\n", e->result.running,
99 e->result.enabled);
100}
101
102void event_report(struct event *e)
103{
104 event_report_justified(e, 0, 0);
105}
diff --git a/tools/testing/selftests/powerpc/pmu/event.h b/tools/testing/selftests/powerpc/pmu/event.h
new file mode 100644
index 000000000000..e6993192ff34
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/event.h
@@ -0,0 +1,39 @@
1/*
2 * Copyright 2013, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef _SELFTESTS_POWERPC_PMU_EVENT_H
7#define _SELFTESTS_POWERPC_PMU_EVENT_H
8
9#include <unistd.h>
10#include <linux/perf_event.h>
11
12#include "utils.h"
13
14
15struct event {
16 struct perf_event_attr attr;
17 char *name;
18 int fd;
19 /* This must match the read_format we use */
20 struct {
21 u64 value;
22 u64 running;
23 u64 enabled;
24 } result;
25};
26
27void event_init(struct event *e, u64 config);
28void event_init_named(struct event *e, u64 config, char *name);
29void event_init_opts(struct event *e, u64 config, int type, char *name);
30int event_open_with_options(struct event *e, pid_t pid, int cpu, int group_fd);
31int event_open_with_group(struct event *e, int group_fd);
32int event_open(struct event *e);
33void event_close(struct event *e);
34int event_reset(struct event *e);
35int event_read(struct event *e);
36void event_report_justified(struct event *e, int name_width, int result_width);
37void event_report(struct event *e);
38
39#endif /* _SELFTESTS_POWERPC_PMU_EVENT_H */
diff --git a/tools/testing/selftests/powerpc/pmu/loop.S b/tools/testing/selftests/powerpc/pmu/loop.S
new file mode 100644
index 000000000000..8820e3df1444
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/loop.S
@@ -0,0 +1,46 @@
1/*
2 * Copyright 2013, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6 .text
7
8 .global thirty_two_instruction_loop
9 .type .thirty_two_instruction_loop,@function
10 .section ".opd","aw",@progbits
11thirty_two_instruction_loop:
12 .quad .thirty_two_instruction_loop, .TOC.@tocbase, 0
13 .previous
14.thirty_two_instruction_loop:
15 cmpwi %r3,0
16 beqlr
17 addi %r4,%r3,1
18 addi %r4,%r4,1
19 addi %r4,%r4,1
20 addi %r4,%r4,1
21 addi %r4,%r4,1
22 addi %r4,%r4,1
23 addi %r4,%r4,1
24 addi %r4,%r4,1
25 addi %r4,%r4,1
26 addi %r4,%r4,1
27 addi %r4,%r4,1
28 addi %r4,%r4,1
29 addi %r4,%r4,1
30 addi %r4,%r4,1
31 addi %r4,%r4,1
32 addi %r4,%r4,1
33 addi %r4,%r4,1
34 addi %r4,%r4,1
35 addi %r4,%r4,1
36 addi %r4,%r4,1
37 addi %r4,%r4,1
38 addi %r4,%r4,1
39 addi %r4,%r4,1
40 addi %r4,%r4,1
41 addi %r4,%r4,1
42 addi %r4,%r4,1
43 addi %r4,%r4,1
44 addi %r4,%r4,1 # 28 addi's
45 subi %r3,%r3,1
46 b .thirty_two_instruction_loop
diff --git a/tools/testing/selftests/powerpc/subunit.h b/tools/testing/selftests/powerpc/subunit.h
new file mode 100644
index 000000000000..98a22920792d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/subunit.h
@@ -0,0 +1,47 @@
1/*
2 * Copyright 2013, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef _SELFTESTS_POWERPC_SUBUNIT_H
7#define _SELFTESTS_POWERPC_SUBUNIT_H
8
9static inline void test_start(char *name)
10{
11 printf("test: %s\n", name);
12}
13
14static inline void test_failure_detail(char *name, char *detail)
15{
16 printf("failure: %s [%s]\n", name, detail);
17}
18
19static inline void test_failure(char *name)
20{
21 printf("failure: %s\n", name);
22}
23
24static inline void test_error(char *name)
25{
26 printf("error: %s\n", name);
27}
28
29static inline void test_success(char *name)
30{
31 printf("success: %s\n", name);
32}
33
34static inline void test_finish(char *name, int status)
35{
36 if (status)
37 test_failure(name);
38 else
39 test_success(name);
40}
41
42static inline void test_set_git_version(char *value)
43{
44 printf("tags: git_version:%s\n", value);
45}
46
47#endif /* _SELFTESTS_POWERPC_SUBUNIT_H */
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h
new file mode 100644
index 000000000000..5851c4b0f553
--- /dev/null
+++ b/tools/testing/selftests/powerpc/utils.h
@@ -0,0 +1,34 @@
1/*
2 * Copyright 2013, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef _SELFTESTS_POWERPC_UTILS_H
7#define _SELFTESTS_POWERPC_UTILS_H
8
9#include <stdint.h>
10#include <stdbool.h>
11
12/* Avoid headaches with PRI?64 - just use %ll? always */
13typedef unsigned long long u64;
14typedef signed long long s64;
15
16/* Just for familiarity */
17typedef uint32_t u32;
18typedef uint8_t u8;
19
20
21int test_harness(int (test_function)(void), char *name);
22
23
24/* Yes, this is evil */
25#define FAIL_IF(x) \
26do { \
27 if ((x)) { \
28 fprintf(stderr, \
29 "[FAIL] Test FAILED on line %d\n", __LINE__); \
30 return 1; \
31 } \
32} while (0)
33
34#endif /* _SELFTESTS_POWERPC_UTILS_H */
diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile
new file mode 100644
index 000000000000..eb2859f4ad21
--- /dev/null
+++ b/tools/testing/selftests/timers/Makefile
@@ -0,0 +1,8 @@
1all:
2 gcc posix_timers.c -o posix_timers -lrt
3
4run_tests: all
5 ./posix_timers
6
7clean:
8 rm -f ./posix_timers
diff --git a/tools/testing/selftests/timers/posix_timers.c b/tools/testing/selftests/timers/posix_timers.c
new file mode 100644
index 000000000000..4fa655d68a81
--- /dev/null
+++ b/tools/testing/selftests/timers/posix_timers.c
@@ -0,0 +1,221 @@
1/*
2 * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
3 *
4 * Licensed under the terms of the GNU GPL License version 2
5 *
6 * Selftests for a few posix timers interface.
7 *
8 * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
9 */
10
11#include <sys/time.h>
12#include <stdio.h>
13#include <signal.h>
14#include <unistd.h>
15#include <time.h>
16#include <pthread.h>
17
18#define DELAY 2
19#define USECS_PER_SEC 1000000
20
21static volatile int done;
22
23/* Busy loop in userspace to elapse ITIMER_VIRTUAL */
24static void user_loop(void)
25{
26 while (!done);
27}
28
29/*
30 * Try to spend as much time as possible in kernelspace
31 * to elapse ITIMER_PROF.
32 */
33static void kernel_loop(void)
34{
35 void *addr = sbrk(0);
36
37 while (!done) {
38 brk(addr + 4096);
39 brk(addr);
40 }
41}
42
43/*
44 * Sleep until ITIMER_REAL expiration.
45 */
46static void idle_loop(void)
47{
48 pause();
49}
50
51static void sig_handler(int nr)
52{
53 done = 1;
54}
55
56/*
57 * Check the expected timer expiration matches the GTOD elapsed delta since
58 * we armed the timer. Keep a 0.5 sec error margin due to various jitter.
59 */
60static int check_diff(struct timeval start, struct timeval end)
61{
62 long long diff;
63
64 diff = end.tv_usec - start.tv_usec;
65 diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC;
66
67 if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) {
68 printf("Diff too high: %lld..", diff);
69 return -1;
70 }
71
72 return 0;
73}
74
75static int check_itimer(int which)
76{
77 int err;
78 struct timeval start, end;
79 struct itimerval val = {
80 .it_value.tv_sec = DELAY,
81 };
82
83 printf("Check itimer ");
84
85 if (which == ITIMER_VIRTUAL)
86 printf("virtual... ");
87 else if (which == ITIMER_PROF)
88 printf("prof... ");
89 else if (which == ITIMER_REAL)
90 printf("real... ");
91
92 fflush(stdout);
93
94 done = 0;
95
96 if (which == ITIMER_VIRTUAL)
97 signal(SIGVTALRM, sig_handler);
98 else if (which == ITIMER_PROF)
99 signal(SIGPROF, sig_handler);
100 else if (which == ITIMER_REAL)
101 signal(SIGALRM, sig_handler);
102
103 err = gettimeofday(&start, NULL);
104 if (err < 0) {
105 perror("Can't call gettimeofday()\n");
106 return -1;
107 }
108
109 err = setitimer(which, &val, NULL);
110 if (err < 0) {
111 perror("Can't set timer\n");
112 return -1;
113 }
114
115 if (which == ITIMER_VIRTUAL)
116 user_loop();
117 else if (which == ITIMER_PROF)
118 kernel_loop();
119 else if (which == ITIMER_REAL)
120 idle_loop();
121
122 gettimeofday(&end, NULL);
123 if (err < 0) {
124 perror("Can't call gettimeofday()\n");
125 return -1;
126 }
127
128 if (!check_diff(start, end))
129 printf("[OK]\n");
130 else
131 printf("[FAIL]\n");
132
133 return 0;
134}
135
136static int check_timer_create(int which)
137{
138 int err;
139 timer_t id;
140 struct timeval start, end;
141 struct itimerspec val = {
142 .it_value.tv_sec = DELAY,
143 };
144
145 printf("Check timer_create() ");
146 if (which == CLOCK_THREAD_CPUTIME_ID) {
147 printf("per thread... ");
148 } else if (which == CLOCK_PROCESS_CPUTIME_ID) {
149 printf("per process... ");
150 }
151 fflush(stdout);
152
153 done = 0;
154 timer_create(which, NULL, &id);
155 if (err < 0) {
156 perror("Can't create timer\n");
157 return -1;
158 }
159 signal(SIGALRM, sig_handler);
160
161 err = gettimeofday(&start, NULL);
162 if (err < 0) {
163 perror("Can't call gettimeofday()\n");
164 return -1;
165 }
166
167 err = timer_settime(id, 0, &val, NULL);
168 if (err < 0) {
169 perror("Can't set timer\n");
170 return -1;
171 }
172
173 user_loop();
174
175 gettimeofday(&end, NULL);
176 if (err < 0) {
177 perror("Can't call gettimeofday()\n");
178 return -1;
179 }
180
181 if (!check_diff(start, end))
182 printf("[OK]\n");
183 else
184 printf("[FAIL]\n");
185
186 return 0;
187}
188
189int main(int argc, char **argv)
190{
191 int err;
192
193 printf("Testing posix timers. False negative may happen on CPU execution \n");
194 printf("based timers if other threads run on the CPU...\n");
195
196 if (check_itimer(ITIMER_VIRTUAL) < 0)
197 return -1;
198
199 if (check_itimer(ITIMER_PROF) < 0)
200 return -1;
201
202 if (check_itimer(ITIMER_REAL) < 0)
203 return -1;
204
205 if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0)
206 return -1;
207
208 /*
209 * It's unfortunately hard to reliably test a timer expiration
210 * on parallel multithread cputime. We could arm it to expire
211 * on DELAY * nr_threads, with nr_threads busy looping, then wait
212 * the normal DELAY since the time is elapsing nr_threads faster.
213 * But for that we need to ensure we have real physical free CPUs
214 * to ensure true parallelism. So test only one thread until we
215 * find a better solution.
216 */
217 if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
218 return -1;
219
220 return 0;
221}
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore
new file mode 100644
index 000000000000..ff1bb16cec4f
--- /dev/null
+++ b/tools/testing/selftests/vm/.gitignore
@@ -0,0 +1,4 @@
1hugepage-mmap
2hugepage-shm
3map_hugetlb
4thuge-gen
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
index 436d2e81868b..3f94e1afd6cf 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -2,13 +2,14 @@
2 2
3CC = $(CROSS_COMPILE)gcc 3CC = $(CROSS_COMPILE)gcc
4CFLAGS = -Wall 4CFLAGS = -Wall
5BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest
5 6
6all: hugepage-mmap hugepage-shm map_hugetlb thuge-gen 7all: $(BINARIES)
7%: %.c 8%: %.c
8 $(CC) $(CFLAGS) -o $@ $^ 9 $(CC) $(CFLAGS) -o $@ $^
9 10
10run_tests: all 11run_tests: all
11 @/bin/sh ./run_vmtests || echo "vmtests: [FAIL]" 12 @/bin/sh ./run_vmtests || (echo "vmtests: [FAIL]"; exit 1)
12 13
13clean: 14clean:
14 $(RM) hugepage-mmap hugepage-shm map_hugetlb 15 $(RM) $(BINARIES)
diff --git a/tools/testing/selftests/vm/hugetlbfstest.c b/tools/testing/selftests/vm/hugetlbfstest.c
new file mode 100644
index 000000000000..ea40ff8c2391
--- /dev/null
+++ b/tools/testing/selftests/vm/hugetlbfstest.c
@@ -0,0 +1,84 @@
1#define _GNU_SOURCE
2#include <assert.h>
3#include <fcntl.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <sys/mman.h>
8#include <sys/stat.h>
9#include <sys/types.h>
10#include <unistd.h>
11
12typedef unsigned long long u64;
13
14static size_t length = 1 << 24;
15
16static u64 read_rss(void)
17{
18 char buf[4096], *s = buf;
19 int i, fd;
20 u64 rss;
21
22 fd = open("/proc/self/statm", O_RDONLY);
23 assert(fd > 2);
24 memset(buf, 0, sizeof(buf));
25 read(fd, buf, sizeof(buf) - 1);
26 for (i = 0; i < 1; i++)
27 s = strchr(s, ' ') + 1;
28 rss = strtoull(s, NULL, 10);
29 return rss << 12; /* assumes 4k pagesize */
30}
31
32static void do_mmap(int fd, int extra_flags, int unmap)
33{
34 int *p;
35 int flags = MAP_PRIVATE | MAP_POPULATE | extra_flags;
36 u64 before, after;
37
38 before = read_rss();
39 p = mmap(NULL, length, PROT_READ | PROT_WRITE, flags, fd, 0);
40 assert(p != MAP_FAILED ||
41 !"mmap returned an unexpected error");
42 after = read_rss();
43 assert(llabs(after - before - length) < 0x40000 ||
44 !"rss didn't grow as expected");
45 if (!unmap)
46 return;
47 munmap(p, length);
48 after = read_rss();
49 assert(llabs(after - before) < 0x40000 ||
50 !"rss didn't shrink as expected");
51}
52
53static int open_file(const char *path)
54{
55 int fd, err;
56
57 unlink(path);
58 fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_EXCL
59 | O_LARGEFILE | O_CLOEXEC, 0600);
60 assert(fd > 2);
61 unlink(path);
62 err = ftruncate(fd, length);
63 assert(!err);
64 return fd;
65}
66
67int main(void)
68{
69 int hugefd, fd;
70
71 fd = open_file("/dev/shm/hugetlbhog");
72 hugefd = open_file("/hugepages/hugetlbhog");
73
74 system("echo 100 > /proc/sys/vm/nr_hugepages");
75 do_mmap(-1, MAP_ANONYMOUS, 1);
76 do_mmap(fd, 0, 1);
77 do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 1);
78 do_mmap(hugefd, 0, 1);
79 do_mmap(hugefd, MAP_HUGETLB, 1);
80 /* Leak the last one to test do_exit() */
81 do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 0);
82 printf("oll korrekt.\n");
83 return 0;
84}
diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests
index 4c53cae6c273..c87b6812300d 100644
--- a/tools/testing/selftests/vm/run_vmtests
+++ b/tools/testing/selftests/vm/run_vmtests
@@ -4,6 +4,7 @@
4#we need 256M, below is the size in kB 4#we need 256M, below is the size in kB
5needmem=262144 5needmem=262144
6mnt=./huge 6mnt=./huge
7exitcode=0
7 8
8#get pagesize and freepages from /proc/meminfo 9#get pagesize and freepages from /proc/meminfo
9while read name size unit; do 10while read name size unit; do
@@ -41,6 +42,7 @@ echo "--------------------"
41./hugepage-mmap 42./hugepage-mmap
42if [ $? -ne 0 ]; then 43if [ $? -ne 0 ]; then
43 echo "[FAIL]" 44 echo "[FAIL]"
45 exitcode=1
44else 46else
45 echo "[PASS]" 47 echo "[PASS]"
46fi 48fi
@@ -55,6 +57,7 @@ echo "--------------------"
55./hugepage-shm 57./hugepage-shm
56if [ $? -ne 0 ]; then 58if [ $? -ne 0 ]; then
57 echo "[FAIL]" 59 echo "[FAIL]"
60 exitcode=1
58else 61else
59 echo "[PASS]" 62 echo "[PASS]"
60fi 63fi
@@ -67,6 +70,18 @@ echo "--------------------"
67./map_hugetlb 70./map_hugetlb
68if [ $? -ne 0 ]; then 71if [ $? -ne 0 ]; then
69 echo "[FAIL]" 72 echo "[FAIL]"
73 exitcode=1
74else
75 echo "[PASS]"
76fi
77
78echo "--------------------"
79echo "running hugetlbfstest"
80echo "--------------------"
81./hugetlbfstest
82if [ $? -ne 0 ]; then
83 echo "[FAIL]"
84 exitcode=1
70else 85else
71 echo "[PASS]" 86 echo "[PASS]"
72fi 87fi
@@ -75,3 +90,4 @@ fi
75umount $mnt 90umount $mnt
76rm -rf $mnt 91rm -rf $mnt
77echo $nr_hugepgs > /proc/sys/vm/nr_hugepages 92echo $nr_hugepgs > /proc/sys/vm/nr_hugepages
93exit $exitcode
diff --git a/tools/virtio/.gitignore b/tools/virtio/.gitignore
new file mode 100644
index 000000000000..1cfbb0157a46
--- /dev/null
+++ b/tools/virtio/.gitignore
@@ -0,0 +1,3 @@
1*.d
2virtio_test
3vringh_test
diff --git a/tools/virtio/linux/module.h b/tools/virtio/linux/module.h
index 3039a7e972b6..28ce95a05997 100644
--- a/tools/virtio/linux/module.h
+++ b/tools/virtio/linux/module.h
@@ -1 +1,6 @@
1#include <linux/export.h> 1#include <linux/export.h>
2
3#define MODULE_LICENSE(__MODULE_LICENSE_value) \
4 static __attribute__((unused)) const char *__MODULE_LICENSE_name = \
5 __MODULE_LICENSE_value
6
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
index cd801838156f..844783040703 100644
--- a/tools/virtio/linux/virtio.h
+++ b/tools/virtio/linux/virtio.h
@@ -45,9 +45,6 @@ struct virtqueue {
45 void *priv; 45 void *priv;
46}; 46};
47 47
48#define MODULE_LICENSE(__MODULE_LICENSE_value) \
49 const char *__MODULE_LICENSE_name = __MODULE_LICENSE_value
50
51/* Interfaces exported by virtio_ring. */ 48/* Interfaces exported by virtio_ring. */
52int virtqueue_add_sgs(struct virtqueue *vq, 49int virtqueue_add_sgs(struct virtqueue *vq,
53 struct scatterlist *sgs[], 50 struct scatterlist *sgs[],