aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/hv/hv_kvp_daemon.c500
-rw-r--r--tools/perf/Documentation/perf-annotate.txt13
-rw-r--r--tools/perf/Documentation/perf-buildid-list.txt6
-rw-r--r--tools/perf/Documentation/perf-report.txt20
-rw-r--r--tools/perf/Documentation/perf-sched.txt6
-rw-r--r--tools/perf/Documentation/perf-script.txt7
-rw-r--r--tools/perf/Documentation/perf-stat.txt16
-rw-r--r--tools/perf/Documentation/perf-top.txt48
-rw-r--r--tools/perf/Documentation/perfconfig.example20
-rw-r--r--tools/perf/Makefile35
-rw-r--r--tools/perf/arch/arm/util/dwarf-regs.c3
-rw-r--r--tools/perf/arch/powerpc/Makefile1
-rw-r--r--tools/perf/arch/powerpc/util/header.c36
-rw-r--r--tools/perf/arch/x86/Makefile1
-rw-r--r--tools/perf/arch/x86/util/header.c59
-rw-r--r--tools/perf/builtin-annotate.c25
-rw-r--r--tools/perf/builtin-buildid-list.c52
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-lock.c8
-rw-r--r--tools/perf/builtin-probe.c14
-rw-r--r--tools/perf/builtin-record.c60
-rw-r--r--tools/perf/builtin-report.c43
-rw-r--r--tools/perf/builtin-sched.c24
-rw-r--r--tools/perf/builtin-script.c6
-rw-r--r--tools/perf/builtin-stat.c197
-rw-r--r--tools/perf/builtin-test.c2
-rw-r--r--tools/perf/builtin-top.c494
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/perf.c24
-rw-r--r--tools/perf/perf.h13
-rwxr-xr-xtools/perf/scripts/python/bin/net_dropmonitor-record2
-rwxr-xr-xtools/perf/scripts/python/bin/net_dropmonitor-report4
-rwxr-xr-xtools/perf/scripts/python/net_dropmonitor.py72
-rw-r--r--tools/perf/util/annotate.c11
-rw-r--r--tools/perf/util/annotate.h9
-rw-r--r--tools/perf/util/color.c2
-rw-r--r--tools/perf/util/config.c36
-rw-r--r--tools/perf/util/dwarf-aux.c210
-rw-r--r--tools/perf/util/dwarf-aux.h11
-rw-r--r--tools/perf/util/event.c5
-rw-r--r--tools/perf/util/event.h2
-rw-r--r--tools/perf/util/evlist.c43
-rw-r--r--tools/perf/util/evlist.h7
-rw-r--r--tools/perf/util/evsel.c58
-rw-r--r--tools/perf/util/header.c1250
-rw-r--r--tools/perf/util/header.h29
-rw-r--r--tools/perf/util/hist.c447
-rw-r--r--tools/perf/util/hist.h61
-rw-r--r--tools/perf/util/include/linux/compiler.h2
-rw-r--r--tools/perf/util/map.c102
-rw-r--r--tools/perf/util/map.h42
-rw-r--r--tools/perf/util/parse-events.c8
-rw-r--r--tools/perf/util/probe-event.c16
-rw-r--r--tools/perf/util/probe-finder.c231
-rw-r--r--tools/perf/util/probe-finder.h2
-rw-r--r--tools/perf/util/python.c117
-rw-r--r--tools/perf/util/session.c19
-rw-r--r--tools/perf/util/session.h4
-rw-r--r--tools/perf/util/setup.py21
-rw-r--r--tools/perf/util/sort.c14
-rw-r--r--tools/perf/util/sort.h2
-rw-r--r--tools/perf/util/symbol.c224
-rw-r--r--tools/perf/util/symbol.h6
-rw-r--r--tools/perf/util/top.c141
-rw-r--r--tools/perf/util/top.h39
-rw-r--r--tools/perf/util/trace-event-info.c112
-rw-r--r--tools/perf/util/trace-event.h13
-rw-r--r--tools/perf/util/ui/browser.c386
-rw-r--r--tools/perf/util/ui/browser.h12
-rw-r--r--tools/perf/util/ui/browsers/annotate.c201
-rw-r--r--tools/perf/util/ui/browsers/hists.c297
-rw-r--r--tools/perf/util/ui/browsers/map.c6
-rw-r--r--tools/perf/util/ui/browsers/top.c213
-rw-r--r--tools/perf/util/ui/helpline.h3
-rw-r--r--tools/perf/util/ui/keysyms.h25
-rw-r--r--tools/perf/util/ui/libslang.h2
-rw-r--r--tools/perf/util/ui/setup.c38
-rw-r--r--tools/power/cpupower/Makefile7
-rw-r--r--tools/power/cpupower/debug/x86_64/Makefile8
l---------tools/power/cpupower/debug/x86_64/centrino-decode.c1
l---------tools/power/cpupower/debug/x86_64/powernow-k8-decode.c1
-rw-r--r--tools/power/cpupower/man/cpupower-frequency-info.16
-rw-r--r--tools/power/cpupower/man/cpupower-frequency-set.18
-rw-r--r--tools/power/cpupower/man/cpupower.114
-rw-r--r--tools/power/cpupower/utils/builtin.h7
-rw-r--r--tools/power/cpupower/utils/cpufreq-info.c42
-rw-r--r--tools/power/cpupower/utils/cpufreq-set.c29
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c24
-rw-r--r--tools/power/cpupower/utils/cpupower-info.c20
-rw-r--r--tools/power/cpupower/utils/cpupower-set.c25
-rw-r--r--tools/power/cpupower/utils/cpupower.c91
-rw-r--r--tools/power/cpupower/utils/helpers/helpers.h12
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c50
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.h2
-rw-r--r--tools/power/cpupower/utils/helpers/topology.c5
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c2
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c66
-rw-r--r--tools/power/cpupower/utils/idle_monitor/mperf_monitor.c177
-rw-r--r--tools/slub/slabinfo.c10
99 files changed, 5138 insertions, 1762 deletions
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
new file mode 100644
index 000000000000..11224eddcdc2
--- /dev/null
+++ b/tools/hv/hv_kvp_daemon.c
@@ -0,0 +1,500 @@
1/*
2 * An implementation of key value pair (KVP) functionality for Linux.
3 *
4 *
5 * Copyright (C) 2010, Novell, Inc.
6 * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15 * NON INFRINGEMENT. See the GNU General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/poll.h>
28#include <sys/utsname.h>
29#include <linux/types.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
33#include <string.h>
34#include <errno.h>
35#include <arpa/inet.h>
36#include <linux/connector.h>
37#include <linux/netlink.h>
38#include <ifaddrs.h>
39#include <netdb.h>
40#include <syslog.h>
41
42/*
43 * KYS: TODO. Need to register these in the kernel.
44 *
45 * The following definitions are shared with the in-kernel component; do not
46 * change any of this without making the corresponding changes in
47 * the KVP kernel component.
48 */
49#define CN_KVP_IDX 0x9 /* MSFT KVP functionality */
50#define CN_KVP_VAL 0x1 /* This supports queries from the kernel */
51#define CN_KVP_USER_VAL 0x2 /* This supports queries from the user */
52
53/*
54 * KVP protocol: The user mode component first registers with the
55 * the kernel component. Subsequently, the kernel component requests, data
56 * for the specified keys. In response to this message the user mode component
57 * fills in the value corresponding to the specified key. We overload the
58 * sequence field in the cn_msg header to define our KVP message types.
59 *
60 * We use this infrastructure for also supporting queries from user mode
61 * application for state that may be maintained in the KVP kernel component.
62 *
63 * XXXKYS: Have a shared header file between the user and kernel (TODO)
64 */
65
66enum kvp_op {
67 KVP_REGISTER = 0, /* Register the user mode component*/
68 KVP_KERNEL_GET, /*Kernel is requesting the value for the specified key*/
69 KVP_KERNEL_SET, /*Kernel is providing the value for the specified key*/
70 KVP_USER_GET, /*User is requesting the value for the specified key*/
71 KVP_USER_SET /*User is providing the value for the specified key*/
72};
73
74#define HV_KVP_EXCHANGE_MAX_KEY_SIZE 512
75#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE 2048
76
77struct hv_ku_msg {
78 __u32 kvp_index;
79 __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
80 __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */
81};
82
83enum key_index {
84 FullyQualifiedDomainName = 0,
85 IntegrationServicesVersion, /*This key is serviced in the kernel*/
86 NetworkAddressIPv4,
87 NetworkAddressIPv6,
88 OSBuildNumber,
89 OSName,
90 OSMajorVersion,
91 OSMinorVersion,
92 OSVersion,
93 ProcessorArchitecture
94};
95
96/*
97 * End of shared definitions.
98 */
99
100static char kvp_send_buffer[4096];
101static char kvp_recv_buffer[4096];
102static struct sockaddr_nl addr;
103
104static char *os_name = "";
105static char *os_major = "";
106static char *os_minor = "";
107static char *processor_arch;
108static char *os_build;
109static char *lic_version;
110static struct utsname uts_buf;
111
112void kvp_get_os_info(void)
113{
114 FILE *file;
115 char *p, buf[512];
116
117 uname(&uts_buf);
118 os_build = uts_buf.release;
119 processor_arch = uts_buf.machine;
120
121 /*
122 * The current windows host (win7) expects the build
123 * string to be of the form: x.y.z
124 * Strip additional information we may have.
125 */
126 p = strchr(os_build, '-');
127 if (p)
128 *p = '\0';
129
130 file = fopen("/etc/SuSE-release", "r");
131 if (file != NULL)
132 goto kvp_osinfo_found;
133 file = fopen("/etc/redhat-release", "r");
134 if (file != NULL)
135 goto kvp_osinfo_found;
136 /*
137 * Add code for other supported platforms.
138 */
139
140 /*
141 * We don't have information about the os.
142 */
143 os_name = uts_buf.sysname;
144 return;
145
146kvp_osinfo_found:
147 /* up to three lines */
148 p = fgets(buf, sizeof(buf), file);
149 if (p) {
150 p = strchr(buf, '\n');
151 if (p)
152 *p = '\0';
153 p = strdup(buf);
154 if (!p)
155 goto done;
156 os_name = p;
157
158 /* second line */
159 p = fgets(buf, sizeof(buf), file);
160 if (p) {
161 p = strchr(buf, '\n');
162 if (p)
163 *p = '\0';
164 p = strdup(buf);
165 if (!p)
166 goto done;
167 os_major = p;
168
169 /* third line */
170 p = fgets(buf, sizeof(buf), file);
171 if (p) {
172 p = strchr(buf, '\n');
173 if (p)
174 *p = '\0';
175 p = strdup(buf);
176 if (p)
177 os_minor = p;
178 }
179 }
180 }
181
182done:
183 fclose(file);
184 return;
185}
186
187static int
188kvp_get_ip_address(int family, char *buffer, int length)
189{
190 struct ifaddrs *ifap;
191 struct ifaddrs *curp;
192 int ipv4_len = strlen("255.255.255.255") + 1;
193 int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
194 int offset = 0;
195 const char *str;
196 char tmp[50];
197 int error = 0;
198
199 /*
200 * On entry into this function, the buffer is capable of holding the
201 * maximum key value (2048 bytes).
202 */
203
204 if (getifaddrs(&ifap)) {
205 strcpy(buffer, "getifaddrs failed\n");
206 return 1;
207 }
208
209 curp = ifap;
210 while (curp != NULL) {
211 if ((curp->ifa_addr != NULL) &&
212 (curp->ifa_addr->sa_family == family)) {
213 if (family == AF_INET) {
214 struct sockaddr_in *addr =
215 (struct sockaddr_in *) curp->ifa_addr;
216
217 str = inet_ntop(family, &addr->sin_addr,
218 tmp, 50);
219 if (str == NULL) {
220 strcpy(buffer, "inet_ntop failed\n");
221 error = 1;
222 goto getaddr_done;
223 }
224 if (offset == 0)
225 strcpy(buffer, tmp);
226 else
227 strcat(buffer, tmp);
228 strcat(buffer, ";");
229
230 offset += strlen(str) + 1;
231 if ((length - offset) < (ipv4_len + 1))
232 goto getaddr_done;
233
234 } else {
235
236 /*
237 * We only support AF_INET and AF_INET6
238 * and the list of addresses is separated by a ";".
239 */
240 struct sockaddr_in6 *addr =
241 (struct sockaddr_in6 *) curp->ifa_addr;
242
243 str = inet_ntop(family,
244 &addr->sin6_addr.s6_addr,
245 tmp, 50);
246 if (str == NULL) {
247 strcpy(buffer, "inet_ntop failed\n");
248 error = 1;
249 goto getaddr_done;
250 }
251 if (offset == 0)
252 strcpy(buffer, tmp);
253 else
254 strcat(buffer, tmp);
255 strcat(buffer, ";");
256 offset += strlen(str) + 1;
257 if ((length - offset) < (ipv6_len + 1))
258 goto getaddr_done;
259
260 }
261
262 }
263 curp = curp->ifa_next;
264 }
265
266getaddr_done:
267 freeifaddrs(ifap);
268 return error;
269}
270
271
272static int
273kvp_get_domain_name(char *buffer, int length)
274{
275 struct addrinfo hints, *info ;
276 int error = 0;
277
278 gethostname(buffer, length);
279 memset(&hints, 0, sizeof(hints));
280 hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
281 hints.ai_socktype = SOCK_STREAM;
282 hints.ai_flags = AI_CANONNAME;
283
284 error = getaddrinfo(buffer, NULL, &hints, &info);
285 if (error != 0) {
286 strcpy(buffer, "getaddrinfo failed\n");
287 return error;
288 }
289 strcpy(buffer, info->ai_canonname);
290 freeaddrinfo(info);
291 return error;
292}
293
294static int
295netlink_send(int fd, struct cn_msg *msg)
296{
297 struct nlmsghdr *nlh;
298 unsigned int size;
299 struct msghdr message;
300 char buffer[64];
301 struct iovec iov[2];
302
303 size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
304
305 nlh = (struct nlmsghdr *)buffer;
306 nlh->nlmsg_seq = 0;
307 nlh->nlmsg_pid = getpid();
308 nlh->nlmsg_type = NLMSG_DONE;
309 nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
310 nlh->nlmsg_flags = 0;
311
312 iov[0].iov_base = nlh;
313 iov[0].iov_len = sizeof(*nlh);
314
315 iov[1].iov_base = msg;
316 iov[1].iov_len = size;
317
318 memset(&message, 0, sizeof(message));
319 message.msg_name = &addr;
320 message.msg_namelen = sizeof(addr);
321 message.msg_iov = iov;
322 message.msg_iovlen = 2;
323
324 return sendmsg(fd, &message, 0);
325}
326
327int main(void)
328{
329 int fd, len, sock_opt;
330 int error;
331 struct cn_msg *message;
332 struct pollfd pfd;
333 struct nlmsghdr *incoming_msg;
334 struct cn_msg *incoming_cn_msg;
335 struct hv_ku_msg *hv_msg;
336 char *p;
337 char *key_value;
338 char *key_name;
339
340 daemon(1, 0);
341 openlog("KVP", 0, LOG_USER);
342 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
343 /*
344 * Retrieve OS release information.
345 */
346 kvp_get_os_info();
347
348 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
349 if (fd < 0) {
350 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
351 exit(-1);
352 }
353 addr.nl_family = AF_NETLINK;
354 addr.nl_pad = 0;
355 addr.nl_pid = 0;
356 addr.nl_groups = CN_KVP_IDX;
357
358
359 error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
360 if (error < 0) {
361 syslog(LOG_ERR, "bind failed; error:%d", error);
362 close(fd);
363 exit(-1);
364 }
365 sock_opt = addr.nl_groups;
366 setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
367 /*
368 * Register ourselves with the kernel.
369 */
370 message = (struct cn_msg *)kvp_send_buffer;
371 message->id.idx = CN_KVP_IDX;
372 message->id.val = CN_KVP_VAL;
373 message->seq = KVP_REGISTER;
374 message->ack = 0;
375 message->len = 0;
376
377 len = netlink_send(fd, message);
378 if (len < 0) {
379 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
380 close(fd);
381 exit(-1);
382 }
383
384 pfd.fd = fd;
385
386 while (1) {
387 pfd.events = POLLIN;
388 pfd.revents = 0;
389 poll(&pfd, 1, -1);
390
391 len = recv(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0);
392
393 if (len < 0) {
394 syslog(LOG_ERR, "recv failed; error:%d", len);
395 close(fd);
396 return -1;
397 }
398
399 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
400 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
401
402 switch (incoming_cn_msg->seq) {
403 case KVP_REGISTER:
404 /*
405 * Driver is registering with us; stash away the version
406 * information.
407 */
408 p = (char *)incoming_cn_msg->data;
409 lic_version = malloc(strlen(p) + 1);
410 if (lic_version) {
411 strcpy(lic_version, p);
412 syslog(LOG_INFO, "KVP LIC Version: %s",
413 lic_version);
414 } else {
415 syslog(LOG_ERR, "malloc failed");
416 }
417 continue;
418
419 case KVP_KERNEL_GET:
420 break;
421 default:
422 continue;
423 }
424
425 hv_msg = (struct hv_ku_msg *)incoming_cn_msg->data;
426 key_name = (char *)hv_msg->kvp_key;
427 key_value = (char *)hv_msg->kvp_value;
428
429 switch (hv_msg->kvp_index) {
430 case FullyQualifiedDomainName:
431 kvp_get_domain_name(key_value,
432 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
433 strcpy(key_name, "FullyQualifiedDomainName");
434 break;
435 case IntegrationServicesVersion:
436 strcpy(key_name, "IntegrationServicesVersion");
437 strcpy(key_value, lic_version);
438 break;
439 case NetworkAddressIPv4:
440 kvp_get_ip_address(AF_INET, key_value,
441 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
442 strcpy(key_name, "NetworkAddressIPv4");
443 break;
444 case NetworkAddressIPv6:
445 kvp_get_ip_address(AF_INET6, key_value,
446 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
447 strcpy(key_name, "NetworkAddressIPv6");
448 break;
449 case OSBuildNumber:
450 strcpy(key_value, os_build);
451 strcpy(key_name, "OSBuildNumber");
452 break;
453 case OSName:
454 strcpy(key_value, os_name);
455 strcpy(key_name, "OSName");
456 break;
457 case OSMajorVersion:
458 strcpy(key_value, os_major);
459 strcpy(key_name, "OSMajorVersion");
460 break;
461 case OSMinorVersion:
462 strcpy(key_value, os_minor);
463 strcpy(key_name, "OSMinorVersion");
464 break;
465 case OSVersion:
466 strcpy(key_value, os_build);
467 strcpy(key_name, "OSVersion");
468 break;
469 case ProcessorArchitecture:
470 strcpy(key_value, processor_arch);
471 strcpy(key_name, "ProcessorArchitecture");
472 break;
473 default:
474 strcpy(key_value, "Unknown Key");
475 /*
476 * We use a null key name to terminate enumeration.
477 */
478 strcpy(key_name, "");
479 break;
480 }
481 /*
482 * Send the value back to the kernel. The response is
483 * already in the receive buffer. Update the cn_msg header to
484 * reflect the key value that has been added to the message
485 */
486
487 incoming_cn_msg->id.idx = CN_KVP_IDX;
488 incoming_cn_msg->id.val = CN_KVP_VAL;
489 incoming_cn_msg->seq = KVP_USER_SET;
490 incoming_cn_msg->ack = 0;
491 incoming_cn_msg->len = sizeof(struct hv_ku_msg);
492
493 len = netlink_send(fd, incoming_cn_msg);
494 if (len < 0) {
495 syslog(LOG_ERR, "net_link send failed; error:%d", len);
496 exit(-1);
497 }
498 }
499
500}
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index 85c5f026930d..fe6762ed56bd 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -72,6 +72,19 @@ OPTIONS
72 CPUs are specified with -: 0-2. Default is to report samples on all 72 CPUs are specified with -: 0-2. Default is to report samples on all
73 CPUs. 73 CPUs.
74 74
75--asm-raw::
76 Show raw instruction encoding of assembly instructions.
77
78--source::
79 Interleave source code with assembly code. Enabled by default,
80 disable with --no-source.
81
82--symfs=<directory>::
83 Look for files with symbols relative to this directory.
84
85-M::
86--disassembler-style=:: Set disassembler style for objdump.
87
75SEE ALSO 88SEE ALSO
76-------- 89--------
77linkperf:perf-record[1], linkperf:perf-report[1] 90linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt
index 5eaac6f26d51..cc22325ffd1b 100644
--- a/tools/perf/Documentation/perf-buildid-list.txt
+++ b/tools/perf/Documentation/perf-buildid-list.txt
@@ -16,6 +16,9 @@ This command displays the buildids found in a perf.data file, so that other
16tools can be used to fetch packages with matching symbol tables for use by 16tools can be used to fetch packages with matching symbol tables for use by
17perf report. 17perf report.
18 18
19It can also be used to show the build id of the running kernel or in an ELF
20file using -i/--input.
21
19OPTIONS 22OPTIONS
20------- 23-------
21-H:: 24-H::
@@ -27,6 +30,9 @@ OPTIONS
27-f:: 30-f::
28--force:: 31--force::
29 Don't do ownership validation. 32 Don't do ownership validation.
33-k::
34--kernel::
35 Show running kernel build id.
30-v:: 36-v::
31--verbose:: 37--verbose::
32 Be more verbose. 38 Be more verbose.
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 04253c07d19a..212f24d672e1 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -134,6 +134,24 @@ OPTIONS
134 CPUs are specified with -: 0-2. Default is to report samples on all 134 CPUs are specified with -: 0-2. Default is to report samples on all
135 CPUs. 135 CPUs.
136 136
137-M::
138--disassembler-style=:: Set disassembler style for objdump.
139
140--source::
141 Interleave source code with assembly code. Enabled by default,
142 disable with --no-source.
143
144--asm-raw::
145 Show raw instruction encoding of assembly instructions.
146
147--show-total-period:: Show a column with the sum of periods.
148
149-I::
150--show-info::
151 Display extended information about the perf.data file. This adds
152 information which may be very large and thus may clutter the display.
153 It currently includes: cpu and numa topology of the host system.
154
137SEE ALSO 155SEE ALSO
138-------- 156--------
139linkperf:perf-stat[1] 157linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index 46822d5fde1c..5b212b57f70b 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -8,7 +8,7 @@ perf-sched - Tool to trace/measure scheduler properties (latencies)
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf sched' {record|latency|map|replay|trace} 11'perf sched' {record|latency|map|replay|script}
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -20,8 +20,8 @@ There are five variants of perf sched:
20 'perf sched latency' to report the per task scheduling latencies 20 'perf sched latency' to report the per task scheduling latencies
21 and other scheduling properties of the workload. 21 and other scheduling properties of the workload.
22 22
23 'perf sched trace' to see a detailed trace of the workload that 23 'perf sched script' to see a detailed trace of the workload that
24 was recorded. 24 was recorded (aliased to 'perf script' for now).
25 25
26 'perf sched replay' to simulate the workload that was recorded 26 'perf sched replay' to simulate the workload that was recorded
27 via perf sched record. (this is done by starting up mockup threads 27 via perf sched record. (this is done by starting up mockup threads
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index db017867d9e8..dec87ecb530e 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -188,6 +188,13 @@ OPTIONS
188 CPUs are specified with -: 0-2. Default is to report samples on all 188 CPUs are specified with -: 0-2. Default is to report samples on all
189 CPUs. 189 CPUs.
190 190
191-I::
192--show-info::
193 Display extended information about the perf.data file. This adds
194 information which may be very large and thus may clutter the display.
195 It currently includes: cpu and numa topology of the host system.
196 It can only be used with the perf script report mode.
197
191SEE ALSO 198SEE ALSO
192-------- 199--------
193linkperf:perf-record[1], linkperf:perf-script-perl[1], 200linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 918cc38ee6d1..8966b9ab2014 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -94,6 +94,22 @@ an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must ha
94corresponding events, i.e., they always refer to events defined earlier on the command 94corresponding events, i.e., they always refer to events defined earlier on the command
95line. 95line.
96 96
97-o file::
98--output file::
99Print the output into the designated file.
100
101--append::
102Append to the output file designated with the -o option. Ignored if -o is not specified.
103
104--log-fd::
105
106Log output to fd, instead of stderr. Complementary to --output, and mutually exclusive
107with it. --append may be used here. Examples:
108 3>results perf stat --log-fd 3 -- $cmd
109 3>>results perf stat --log-fd 3 --append -- $cmd
110
111
112
97EXAMPLES 113EXAMPLES
98-------- 114--------
99 115
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index f6eb1cdafb77..b1a5bbbfebef 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -106,6 +106,51 @@ Default is to monitor all CPUS.
106--zero:: 106--zero::
107 Zero history across display updates. 107 Zero history across display updates.
108 108
109-s::
110--sort::
111 Sort by key(s): pid, comm, dso, symbol, parent
112
113-n::
114--show-nr-samples::
115 Show a column with the number of samples.
116
117--show-total-period::
118 Show a column with the sum of periods.
119
120--dsos::
121 Only consider symbols in these dsos.
122
123--comms::
124 Only consider symbols in these comms.
125
126--symbols::
127 Only consider these symbols.
128
129-M::
130--disassembler-style=:: Set disassembler style for objdump.
131
132--source::
133 Interleave source code with assembly code. Enabled by default,
134 disable with --no-source.
135
136--asm-raw::
137 Show raw instruction encoding of assembly instructions.
138
139-G [type,min,order]::
140--call-graph::
141 Display call chains using type, min percent threshold and order.
142 type can be either:
143 - flat: single column, linear exposure of call chains.
144 - graph: use a graph tree, displaying absolute overhead rates.
145 - fractal: like graph, but displays relative rates. Each branch of
146 the tree is considered as a new profiled object.
147
148 order can be either:
149 - callee: callee based call graph.
150 - caller: inverted caller based call graph.
151
152 Default: fractal,0.5,callee.
153
109INTERACTIVE PROMPTING KEYS 154INTERACTIVE PROMPTING KEYS
110-------------------------- 155--------------------------
111 156
@@ -130,9 +175,6 @@ INTERACTIVE PROMPTING KEYS
130[S]:: 175[S]::
131 Stop annotation, return to full profile display. 176 Stop annotation, return to full profile display.
132 177
133[w]::
134 Toggle between weighted sum and individual count[E]r profile.
135
136[z]:: 178[z]::
137 Toggle event count zeroing across display updates. 179 Toggle event count zeroing across display updates.
138 180
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
new file mode 100644
index 000000000000..d1448668f4d4
--- /dev/null
+++ b/tools/perf/Documentation/perfconfig.example
@@ -0,0 +1,20 @@
1[colors]
2
3 # These were the old defaults
4 top = red, lightgray
5 medium = green, lightgray
6 normal = black, lightgray
7 selected = lightgray, magenta
8 code = blue, lightgray
9
10[tui]
11
12 # Defaults if linked with libslang
13 report = on
14 annotate = on
15 top = on
16
17[buildid]
18
19 # Default, disable using /dev/null
20 dir = /root/.debug
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 56d62d3fb167..b98e3075646b 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -30,6 +30,8 @@ endif
30# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. 30# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
31# 31#
32# Define NO_DWARF if you do not want debug-info analysis feature at all. 32# Define NO_DWARF if you do not want debug-info analysis feature at all.
33#
34# Define WERROR=0 to disable treating any warnings as errors.
33 35
34$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 36$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
35 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 37 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
@@ -63,6 +65,11 @@ ifeq ($(ARCH),x86_64)
63 endif 65 endif
64endif 66endif
65 67
68# Treat warnings as errors unless directed not to
69ifneq ($(WERROR),0)
70 CFLAGS_WERROR := -Werror
71endif
72
66# 73#
67# Include saner warnings here, which can catch bugs: 74# Include saner warnings here, which can catch bugs:
68# 75#
@@ -95,7 +102,7 @@ ifndef PERF_DEBUG
95 CFLAGS_OPTIMIZE = -O6 102 CFLAGS_OPTIMIZE = -O6
96endif 103endif
97 104
98CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 105CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
99EXTLIBS = -lpthread -lrt -lelf -lm 106EXTLIBS = -lpthread -lrt -lelf -lm
100ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 107ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
101ALL_LDFLAGS = $(LDFLAGS) 108ALL_LDFLAGS = $(LDFLAGS)
@@ -181,9 +188,9 @@ strip-libs = $(filter-out -l%,$(1))
181 188
182$(OUTPUT)python/perf.so: $(PYRF_OBJS) 189$(OUTPUT)python/perf.so: $(PYRF_OBJS)
183 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ 190 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
184 --quiet build_ext \ 191 --quiet build_ext; \
185 --build-lib='$(OUTPUT)python' \ 192 mkdir -p $(OUTPUT)python && \
186 --build-temp='$(OUTPUT)python/temp' 193 cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
187# 194#
188# No Perl scripts right now: 195# No Perl scripts right now:
189# 196#
@@ -459,13 +466,13 @@ else
459 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o 466 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
460 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o 467 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
461 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o 468 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
462 LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o
463 LIB_OBJS += $(OUTPUT)util/ui/helpline.o 469 LIB_OBJS += $(OUTPUT)util/ui/helpline.o
464 LIB_OBJS += $(OUTPUT)util/ui/progress.o 470 LIB_OBJS += $(OUTPUT)util/ui/progress.o
465 LIB_OBJS += $(OUTPUT)util/ui/util.o 471 LIB_OBJS += $(OUTPUT)util/ui/util.o
466 LIB_H += util/ui/browser.h 472 LIB_H += util/ui/browser.h
467 LIB_H += util/ui/browsers/map.h 473 LIB_H += util/ui/browsers/map.h
468 LIB_H += util/ui/helpline.h 474 LIB_H += util/ui/helpline.h
475 LIB_H += util/ui/keysyms.h
469 LIB_H += util/ui/libslang.h 476 LIB_H += util/ui/libslang.h
470 LIB_H += util/ui/progress.h 477 LIB_H += util/ui/progress.h
471 LIB_H += util/ui/util.h 478 LIB_H += util/ui/util.h
@@ -509,9 +516,13 @@ else
509 516
510 PYTHON_WORD := $(call shell-wordify,$(PYTHON)) 517 PYTHON_WORD := $(call shell-wordify,$(PYTHON))
511 518
512 python-clean := $(PYTHON_WORD) util/setup.py clean \ 519 # python extension build directories
513 --build-lib='$(OUTPUT)python' \ 520 PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
514 --build-temp='$(OUTPUT)python/temp' 521 PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
522 PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
523 export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
524
525 python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
515 526
516 ifdef NO_LIBPYTHON 527 ifdef NO_LIBPYTHON
517 $(call disable-python) 528 $(call disable-python)
@@ -718,9 +729,6 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
718$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 729$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
719 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 730 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
720 731
721$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
722 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
723
724$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 732$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
725 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 733 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
726 734
@@ -868,6 +876,9 @@ install: all
868 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' 876 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
869 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 877 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
870 878
879install-python_ext:
880 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
881
871install-doc: 882install-doc:
872 $(MAKE) -C Documentation install 883 $(MAKE) -C Documentation install
873 884
@@ -895,7 +906,7 @@ quick-install-html:
895### Cleaning rules 906### Cleaning rules
896 907
897clean: 908clean:
898 $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive} 909 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
899 $(RM) $(ALL_PROGRAMS) perf 910 $(RM) $(ALL_PROGRAMS) perf
900 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 911 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
901 $(MAKE) -C Documentation/ clean 912 $(MAKE) -C Documentation/ clean
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c
index fff6450c8c99..e8d5c551c69c 100644
--- a/tools/perf/arch/arm/util/dwarf-regs.c
+++ b/tools/perf/arch/arm/util/dwarf-regs.c
@@ -8,7 +8,10 @@
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 10
11#include <stdlib.h>
12#ifndef __UCLIBC__
11#include <libio.h> 13#include <libio.h>
14#endif
12#include <dwarf-regs.h> 15#include <dwarf-regs.h>
13 16
14struct pt_regs_dwarfnum { 17struct pt_regs_dwarfnum {
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 15130b50dfe3..744e629797be 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -2,3 +2,4 @@ ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
new file mode 100644
index 000000000000..eba80c292945
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -0,0 +1,36 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#include "../../util/header.h"
8
9#define __stringify_1(x) #x
10#define __stringify(x) __stringify_1(x)
11
12#define mfspr(rn) ({unsigned long rval; \
13 asm volatile("mfspr %0," __stringify(rn) \
14 : "=r" (rval)); rval; })
15
16#define SPRN_PVR 0x11F /* Processor Version Register */
17#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */
18#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */
19
20int
21get_cpuid(char *buffer, size_t sz)
22{
23 unsigned long pvr;
24 int nb;
25
26 pvr = mfspr(SPRN_PVR);
27
28 nb = snprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr));
29
30 /* look for end marker to ensure the entire data fit */
31 if (strchr(buffer, '$')) {
32 buffer[nb-1] = '\0';
33 return 0;
34 }
35 return -1;
36}
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 15130b50dfe3..744e629797be 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -2,3 +2,4 @@ ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
new file mode 100644
index 000000000000..f94006068d2b
--- /dev/null
+++ b/tools/perf/arch/x86/util/header.c
@@ -0,0 +1,59 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#include "../../util/header.h"
8
9static inline void
10cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
11 unsigned int *d)
12{
13 __asm__ __volatile__ (".byte 0x53\n\tcpuid\n\t"
14 "movl %%ebx, %%esi\n\t.byte 0x5b"
15 : "=a" (*a),
16 "=S" (*b),
17 "=c" (*c),
18 "=d" (*d)
19 : "a" (op));
20}
21
22int
23get_cpuid(char *buffer, size_t sz)
24{
25 unsigned int a, b, c, d, lvl;
26 int family = -1, model = -1, step = -1;
27 int nb;
28 char vendor[16];
29
30 cpuid(0, &lvl, &b, &c, &d);
31 strncpy(&vendor[0], (char *)(&b), 4);
32 strncpy(&vendor[4], (char *)(&d), 4);
33 strncpy(&vendor[8], (char *)(&c), 4);
34 vendor[12] = '\0';
35
36 if (lvl >= 1) {
37 cpuid(1, &a, &b, &c, &d);
38
39 family = (a >> 8) & 0xf; /* bits 11 - 8 */
40 model = (a >> 4) & 0xf; /* Bits 7 - 4 */
41 step = a & 0xf;
42
43 /* extended family */
44 if (family == 0xf)
45 family += (a >> 20) & 0xff;
46
47 /* extended model */
48 if (family >= 0x6)
49 model += ((a >> 16) & 0xf) << 4;
50 }
51 nb = snprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step);
52
53 /* look for end marker to ensure the entire data fit */
54 if (strchr(buffer, '$')) {
55 buffer[nb-1] = '\0';
56 return 0;
57 }
58 return -1;
59}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 555aefd7fe01..46b4c24f338e 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -114,10 +114,11 @@ static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
114 print_line, full_paths, 0, 0); 114 print_line, full_paths, 0, 0);
115} 115}
116 116
117static void hists__find_annotations(struct hists *self, int evidx) 117static void hists__find_annotations(struct hists *self, int evidx,
118 int nr_events)
118{ 119{
119 struct rb_node *nd = rb_first(&self->entries), *next; 120 struct rb_node *nd = rb_first(&self->entries), *next;
120 int key = KEY_RIGHT; 121 int key = K_RIGHT;
121 122
122 while (nd) { 123 while (nd) {
123 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 124 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
@@ -129,7 +130,7 @@ static void hists__find_annotations(struct hists *self, int evidx)
129 notes = symbol__annotation(he->ms.sym); 130 notes = symbol__annotation(he->ms.sym);
130 if (notes->src == NULL) { 131 if (notes->src == NULL) {
131find_next: 132find_next:
132 if (key == KEY_LEFT) 133 if (key == K_LEFT)
133 nd = rb_prev(nd); 134 nd = rb_prev(nd);
134 else 135 else
135 nd = rb_next(nd); 136 nd = rb_next(nd);
@@ -137,12 +138,13 @@ find_next:
137 } 138 }
138 139
139 if (use_browser > 0) { 140 if (use_browser > 0) {
140 key = hist_entry__tui_annotate(he, evidx); 141 key = hist_entry__tui_annotate(he, evidx, nr_events,
142 NULL, NULL, 0);
141 switch (key) { 143 switch (key) {
142 case KEY_RIGHT: 144 case K_RIGHT:
143 next = rb_next(nd); 145 next = rb_next(nd);
144 break; 146 break;
145 case KEY_LEFT: 147 case K_LEFT:
146 next = rb_prev(nd); 148 next = rb_prev(nd);
147 break; 149 break;
148 default: 150 default:
@@ -215,7 +217,8 @@ static int __cmd_annotate(void)
215 total_nr_samples += nr_samples; 217 total_nr_samples += nr_samples;
216 hists__collapse_resort(hists); 218 hists__collapse_resort(hists);
217 hists__output_resort(hists); 219 hists__output_resort(hists);
218 hists__find_annotations(hists, pos->idx); 220 hists__find_annotations(hists, pos->idx,
221 session->evlist->nr_entries);
219 } 222 }
220 } 223 }
221 224
@@ -267,6 +270,14 @@ static const struct option options[] = {
267 OPT_BOOLEAN('P', "full-paths", &full_paths, 270 OPT_BOOLEAN('P', "full-paths", &full_paths,
268 "Don't shorten the displayed pathnames"), 271 "Don't shorten the displayed pathnames"),
269 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 272 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
273 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
274 "Look for files with symbols relative to this directory"),
275 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
276 "Interleave source code with assembly code (default)"),
277 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
278 "Display raw encoding of assembly instructions (default)"),
279 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
280 "Specify disassembler style (e.g. -M intel for intel syntax)"),
270 OPT_END() 281 OPT_END()
271}; 282};
272 283
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 5af32ae9031e..cb690a65bf02 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -1,7 +1,8 @@
1/* 1/*
2 * builtin-buildid-list.c 2 * builtin-buildid-list.c
3 * 3 *
4 * Builtin buildid-list command: list buildids in perf.data 4 * Builtin buildid-list command: list buildids in perf.data, in the running
5 * kernel and in ELF files.
5 * 6 *
6 * Copyright (C) 2009, Red Hat Inc. 7 * Copyright (C) 2009, Red Hat Inc.
7 * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com> 8 * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com>
@@ -15,8 +16,11 @@
15#include "util/session.h" 16#include "util/session.h"
16#include "util/symbol.h" 17#include "util/symbol.h"
17 18
19#include <libelf.h>
20
18static char const *input_name = "perf.data"; 21static char const *input_name = "perf.data";
19static bool force; 22static bool force;
23static bool show_kernel;
20static bool with_hits; 24static bool with_hits;
21 25
22static const char * const buildid_list_usage[] = { 26static const char * const buildid_list_usage[] = {
@@ -29,12 +33,13 @@ static const struct option options[] = {
29 OPT_STRING('i', "input", &input_name, "file", 33 OPT_STRING('i', "input", &input_name, "file",
30 "input file name"), 34 "input file name"),
31 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 35 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
36 OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"),
32 OPT_INCR('v', "verbose", &verbose, 37 OPT_INCR('v', "verbose", &verbose,
33 "be more verbose"), 38 "be more verbose"),
34 OPT_END() 39 OPT_END()
35}; 40};
36 41
37static int __cmd_buildid_list(void) 42static int perf_session__list_build_ids(void)
38{ 43{
39 struct perf_session *session; 44 struct perf_session *session;
40 45
@@ -52,6 +57,49 @@ static int __cmd_buildid_list(void)
52 return 0; 57 return 0;
53} 58}
54 59
60static int sysfs__fprintf_build_id(FILE *fp)
61{
62 u8 kallsyms_build_id[BUILD_ID_SIZE];
63 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
64
65 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
66 sizeof(kallsyms_build_id)) != 0)
67 return -1;
68
69 build_id__sprintf(kallsyms_build_id, sizeof(kallsyms_build_id),
70 sbuild_id);
71 fprintf(fp, "%s\n", sbuild_id);
72 return 0;
73}
74
75static int filename__fprintf_build_id(const char *name, FILE *fp)
76{
77 u8 build_id[BUILD_ID_SIZE];
78 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
79
80 if (filename__read_build_id(name, build_id,
81 sizeof(build_id)) != sizeof(build_id))
82 return 0;
83
84 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
85 return fprintf(fp, "%s\n", sbuild_id);
86}
87
88static int __cmd_buildid_list(void)
89{
90 if (show_kernel)
91 return sysfs__fprintf_build_id(stdout);
92
93 elf_version(EV_CURRENT);
94 /*
95 * See if this is an ELF file first:
96 */
97 if (filename__fprintf_build_id(input_name, stdout))
98 return 0;
99
100 return perf_session__list_build_ids();
101}
102
55int cmd_buildid_list(int argc, const char **argv, const char *prefix __used) 103int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
56{ 104{
57 argc = parse_options(argc, argv, options, buildid_list_usage, 0); 105 argc = parse_options(argc, argv, options, buildid_list_usage, 0);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index e8219990f8b8..b39f3a1ee7dc 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -162,7 +162,7 @@ static int __cmd_diff(void)
162 162
163 hists__match(&session[0]->hists, &session[1]->hists); 163 hists__match(&session[0]->hists, &session[1]->hists);
164 hists__fprintf(&session[1]->hists, &session[0]->hists, 164 hists__fprintf(&session[1]->hists, &session[0]->hists,
165 show_displacement, stdout); 165 show_displacement, true, 0, 0, stdout);
166out_delete: 166out_delete:
167 for (i = 0; i < 2; ++i) 167 for (i = 0; i < 2; ++i)
168 perf_session__delete(session[i]); 168 perf_session__delete(session[i]);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 9ac05aafd9b2..899080ace267 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -942,10 +942,10 @@ static const char *record_args[] = {
942 "-f", 942 "-f",
943 "-m", "1024", 943 "-m", "1024",
944 "-c", "1", 944 "-c", "1",
945 "-e", "lock:lock_acquire:r", 945 "-e", "lock:lock_acquire",
946 "-e", "lock:lock_acquired:r", 946 "-e", "lock:lock_acquired",
947 "-e", "lock:lock_contended:r", 947 "-e", "lock:lock_contended",
948 "-e", "lock:lock_release:r", 948 "-e", "lock:lock_release",
949}; 949};
950 950
951static int __cmd_record(int argc, const char **argv) 951static int __cmd_record(int argc, const char **argv)
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 5f2a5c7046df..710ae3d0a489 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -134,10 +134,18 @@ static int opt_show_lines(const struct option *opt __used,
134{ 134{
135 int ret = 0; 135 int ret = 0;
136 136
137 if (str) 137 if (!str)
138 ret = parse_line_range_desc(str, &params.line_range); 138 return 0;
139 INIT_LIST_HEAD(&params.line_range.line_list); 139
140 if (params.show_lines) {
141 pr_warning("Warning: more than one --line options are"
142 " detected. Only the first one is valid.\n");
143 return 0;
144 }
145
140 params.show_lines = true; 146 params.show_lines = true;
147 ret = parse_line_range_desc(str, &params.line_range);
148 INIT_LIST_HEAD(&params.line_range.line_list);
141 149
142 return ret; 150 return ret;
143} 151}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 80dc5b790e47..f82480fa7f27 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -30,8 +30,6 @@
30#include <sched.h> 30#include <sched.h>
31#include <sys/mman.h> 31#include <sys/mman.h>
32 32
33#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
34
35enum write_mode_t { 33enum write_mode_t {
36 WRITE_FORCE, 34 WRITE_FORCE,
37 WRITE_APPEND 35 WRITE_APPEND
@@ -47,7 +45,7 @@ static int freq = 1000;
47static int output; 45static int output;
48static int pipe_output = 0; 46static int pipe_output = 0;
49static const char *output_name = NULL; 47static const char *output_name = NULL;
50static int group = 0; 48static bool group = false;
51static int realtime_prio = 0; 49static int realtime_prio = 0;
52static bool nodelay = false; 50static bool nodelay = false;
53static bool raw_samples = false; 51static bool raw_samples = false;
@@ -75,6 +73,7 @@ static off_t post_processing_offset;
75 73
76static struct perf_session *session; 74static struct perf_session *session;
77static const char *cpu_list; 75static const char *cpu_list;
76static const char *progname;
78 77
79static void advance_output(size_t size) 78static void advance_output(size_t size)
80{ 79{
@@ -139,17 +138,29 @@ static void mmap_read(struct perf_mmap *md)
139 138
140static volatile int done = 0; 139static volatile int done = 0;
141static volatile int signr = -1; 140static volatile int signr = -1;
141static volatile int child_finished = 0;
142 142
143static void sig_handler(int sig) 143static void sig_handler(int sig)
144{ 144{
145 if (sig == SIGCHLD)
146 child_finished = 1;
147
145 done = 1; 148 done = 1;
146 signr = sig; 149 signr = sig;
147} 150}
148 151
149static void sig_atexit(void) 152static void sig_atexit(void)
150{ 153{
151 if (child_pid > 0) 154 int status;
152 kill(child_pid, SIGTERM); 155
156 if (child_pid > 0) {
157 if (!child_finished)
158 kill(child_pid, SIGTERM);
159
160 wait(&status);
161 if (WIFSIGNALED(status))
162 psignal(WTERMSIG(status), progname);
163 }
153 164
154 if (signr == -1 || signr == SIGUSR1) 165 if (signr == -1 || signr == SIGUSR1)
155 return; 166 return;
@@ -163,6 +174,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
163 struct perf_event_attr *attr = &evsel->attr; 174 struct perf_event_attr *attr = &evsel->attr;
164 int track = !evsel->idx; /* only the first counter needs these */ 175 int track = !evsel->idx; /* only the first counter needs these */
165 176
177 attr->disabled = 1;
166 attr->inherit = !no_inherit; 178 attr->inherit = !no_inherit;
167 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 179 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
168 PERF_FORMAT_TOTAL_TIME_RUNNING | 180 PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -438,7 +450,6 @@ static void mmap_read_all(void)
438 450
439static int __cmd_record(int argc, const char **argv) 451static int __cmd_record(int argc, const char **argv)
440{ 452{
441 int i;
442 struct stat st; 453 struct stat st;
443 int flags; 454 int flags;
444 int err; 455 int err;
@@ -448,6 +459,8 @@ static int __cmd_record(int argc, const char **argv)
448 char buf; 459 char buf;
449 struct machine *machine; 460 struct machine *machine;
450 461
462 progname = argv[0];
463
451 page_size = sysconf(_SC_PAGE_SIZE); 464 page_size = sysconf(_SC_PAGE_SIZE);
452 465
453 atexit(sig_atexit); 466 atexit(sig_atexit);
@@ -516,6 +529,19 @@ static int __cmd_record(int argc, const char **argv)
516 if (have_tracepoints(&evsel_list->entries)) 529 if (have_tracepoints(&evsel_list->entries))
517 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 530 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
518 531
532 perf_header__set_feat(&session->header, HEADER_HOSTNAME);
533 perf_header__set_feat(&session->header, HEADER_OSRELEASE);
534 perf_header__set_feat(&session->header, HEADER_ARCH);
535 perf_header__set_feat(&session->header, HEADER_CPUDESC);
536 perf_header__set_feat(&session->header, HEADER_NRCPUS);
537 perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
538 perf_header__set_feat(&session->header, HEADER_CMDLINE);
539 perf_header__set_feat(&session->header, HEADER_VERSION);
540 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
541 perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
542 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
543 perf_header__set_feat(&session->header, HEADER_CPUID);
544
519 /* 512 kiB: default amount of unprivileged mlocked memory */ 545 /* 512 kiB: default amount of unprivileged mlocked memory */
520 if (mmap_pages == UINT_MAX) 546 if (mmap_pages == UINT_MAX)
521 mmap_pages = (512 * 1024) / page_size; 547 mmap_pages = (512 * 1024) / page_size;
@@ -674,6 +700,8 @@ static int __cmd_record(int argc, const char **argv)
674 } 700 }
675 } 701 }
676 702
703 perf_evlist__enable(evsel_list);
704
677 /* 705 /*
678 * Let the child rip 706 * Let the child rip
679 */ 707 */
@@ -682,7 +710,6 @@ static int __cmd_record(int argc, const char **argv)
682 710
683 for (;;) { 711 for (;;) {
684 int hits = samples; 712 int hits = samples;
685 int thread;
686 713
687 mmap_read_all(); 714 mmap_read_all();
688 715
@@ -693,19 +720,8 @@ static int __cmd_record(int argc, const char **argv)
693 waking++; 720 waking++;
694 } 721 }
695 722
696 if (done) { 723 if (done)
697 for (i = 0; i < evsel_list->cpus->nr; i++) { 724 perf_evlist__disable(evsel_list);
698 struct perf_evsel *pos;
699
700 list_for_each_entry(pos, &evsel_list->entries, node) {
701 for (thread = 0;
702 thread < evsel_list->threads->nr;
703 thread++)
704 ioctl(FD(pos, i, thread),
705 PERF_EVENT_IOC_DISABLE);
706 }
707 }
708 }
709 } 725 }
710 726
711 if (quiet || signr == SIGUSR1) 727 if (quiet || signr == SIGUSR1)
@@ -768,6 +784,8 @@ const struct option record_options[] = {
768 "child tasks do not inherit counters"), 784 "child tasks do not inherit counters"),
769 OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), 785 OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
770 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 786 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
787 OPT_BOOLEAN(0, "group", &group,
788 "put the counters into a counter group"),
771 OPT_BOOLEAN('g', "call-graph", &call_graph, 789 OPT_BOOLEAN('g', "call-graph", &call_graph,
772 "do call-graph (stack chain/backtrace) recording"), 790 "do call-graph (stack chain/backtrace) recording"),
773 OPT_INCR('v', "verbose", &verbose, 791 OPT_INCR('v', "verbose", &verbose,
@@ -795,6 +813,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
795 int err = -ENOMEM; 813 int err = -ENOMEM;
796 struct perf_evsel *pos; 814 struct perf_evsel *pos;
797 815
816 perf_header__set_cmdline(argc, argv);
817
798 evsel_list = perf_evlist__new(NULL, NULL); 818 evsel_list = perf_evlist__new(NULL, NULL);
799 if (evsel_list == NULL) 819 if (evsel_list == NULL)
800 return -ENOMEM; 820 return -ENOMEM;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index f854efda7686..4d7c8340c326 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -40,6 +40,7 @@ static char const *input_name = "perf.data";
40static bool force, use_tui, use_stdio; 40static bool force, use_tui, use_stdio;
41static bool hide_unresolved; 41static bool hide_unresolved;
42static bool dont_use_callchains; 42static bool dont_use_callchains;
43static bool show_full_info;
43 44
44static bool show_threads; 45static bool show_threads;
45static struct perf_read_values show_threads_values; 46static struct perf_read_values show_threads_values;
@@ -162,23 +163,22 @@ static int perf_session__setup_sample_type(struct perf_session *self)
162{ 163{
163 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { 164 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
164 if (sort__has_parent) { 165 if (sort__has_parent) {
165 fprintf(stderr, "selected --sort parent, but no" 166 ui__warning("Selected --sort parent, but no "
166 " callchain data. Did you call" 167 "callchain data. Did you call "
167 " perf record without -g?\n"); 168 "'perf record' without -g?\n");
168 return -EINVAL; 169 return -EINVAL;
169 } 170 }
170 if (symbol_conf.use_callchain) { 171 if (symbol_conf.use_callchain) {
171 fprintf(stderr, "selected -g but no callchain data." 172 ui__warning("Selected -g but no callchain data. Did "
172 " Did you call perf record without" 173 "you call 'perf record' without -g?\n");
173 " -g?\n");
174 return -1; 174 return -1;
175 } 175 }
176 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && 176 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
177 !symbol_conf.use_callchain) { 177 !symbol_conf.use_callchain) {
178 symbol_conf.use_callchain = true; 178 symbol_conf.use_callchain = true;
179 if (callchain_register_param(&callchain_param) < 0) { 179 if (callchain_register_param(&callchain_param) < 0) {
180 fprintf(stderr, "Can't register callchain" 180 ui__warning("Can't register callchain "
181 " params\n"); 181 "params.\n");
182 return -EINVAL; 182 return -EINVAL;
183 } 183 }
184 } 184 }
@@ -230,13 +230,10 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
230 230
231 list_for_each_entry(pos, &evlist->entries, node) { 231 list_for_each_entry(pos, &evlist->entries, node) {
232 struct hists *hists = &pos->hists; 232 struct hists *hists = &pos->hists;
233 const char *evname = NULL; 233 const char *evname = event_name(pos);
234
235 if (rb_first(&hists->entries) != rb_last(&hists->entries))
236 evname = event_name(pos);
237 234
238 hists__fprintf_nr_sample_events(hists, evname, stdout); 235 hists__fprintf_nr_sample_events(hists, evname, stdout);
239 hists__fprintf(hists, NULL, false, stdout); 236 hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
240 fprintf(stdout, "\n\n"); 237 fprintf(stdout, "\n\n");
241 } 238 }
242 239
@@ -277,6 +274,9 @@ static int __cmd_report(void)
277 goto out_delete; 274 goto out_delete;
278 } 275 }
279 276
277 if (use_browser <= 0)
278 perf_session__fprintf_info(session, stdout, show_full_info);
279
280 if (show_threads) 280 if (show_threads)
281 perf_read_values_init(&show_threads_values); 281 perf_read_values_init(&show_threads_values);
282 282
@@ -331,9 +331,10 @@ static int __cmd_report(void)
331 goto out_delete; 331 goto out_delete;
332 } 332 }
333 333
334 if (use_browser > 0) 334 if (use_browser > 0) {
335 perf_evlist__tui_browse_hists(session->evlist, help); 335 perf_evlist__tui_browse_hists(session->evlist, help,
336 else 336 NULL, NULL, 0);
337 } else
337 perf_evlist__tty_browse_hists(session->evlist, help); 338 perf_evlist__tty_browse_hists(session->evlist, help);
338 339
339out_delete: 340out_delete:
@@ -488,6 +489,16 @@ static const struct option options[] = {
488 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 489 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
489 "Look for files with symbols relative to this directory"), 490 "Look for files with symbols relative to this directory"),
490 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 491 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
492 OPT_BOOLEAN('I', "show-info", &show_full_info,
493 "Display extended information about perf.data file"),
494 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
495 "Interleave source code with assembly code (default)"),
496 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
497 "Display raw encoding of assembly instructions (default)"),
498 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
499 "Specify disassembler style (e.g. -M intel for intel syntax)"),
500 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
501 "Show a column with the sum of periods"),
491 OPT_END() 502 OPT_END()
492}; 503};
493 504
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index dcfe8873c9a1..5177964943e7 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1637,23 +1637,29 @@ static struct perf_event_ops event_ops = {
1637 .ordered_samples = true, 1637 .ordered_samples = true,
1638}; 1638};
1639 1639
1640static int read_events(void) 1640static void read_events(bool destroy, struct perf_session **psession)
1641{ 1641{
1642 int err = -EINVAL; 1642 int err = -EINVAL;
1643 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 1643 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
1644 0, false, &event_ops); 1644 0, false, &event_ops);
1645 if (session == NULL) 1645 if (session == NULL)
1646 return -ENOMEM; 1646 die("No Memory");
1647 1647
1648 if (perf_session__has_traces(session, "record -R")) { 1648 if (perf_session__has_traces(session, "record -R")) {
1649 err = perf_session__process_events(session, &event_ops); 1649 err = perf_session__process_events(session, &event_ops);
1650 if (err)
1651 die("Failed to process events, error %d", err);
1652
1650 nr_events = session->hists.stats.nr_events[0]; 1653 nr_events = session->hists.stats.nr_events[0];
1651 nr_lost_events = session->hists.stats.total_lost; 1654 nr_lost_events = session->hists.stats.total_lost;
1652 nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; 1655 nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
1653 } 1656 }
1654 1657
1655 perf_session__delete(session); 1658 if (destroy)
1656 return err; 1659 perf_session__delete(session);
1660
1661 if (psession)
1662 *psession = session;
1657} 1663}
1658 1664
1659static void print_bad_events(void) 1665static void print_bad_events(void)
@@ -1689,9 +1695,10 @@ static void print_bad_events(void)
1689static void __cmd_lat(void) 1695static void __cmd_lat(void)
1690{ 1696{
1691 struct rb_node *next; 1697 struct rb_node *next;
1698 struct perf_session *session;
1692 1699
1693 setup_pager(); 1700 setup_pager();
1694 read_events(); 1701 read_events(false, &session);
1695 sort_lat(); 1702 sort_lat();
1696 1703
1697 printf("\n ---------------------------------------------------------------------------------------------------------------\n"); 1704 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
@@ -1717,6 +1724,7 @@ static void __cmd_lat(void)
1717 print_bad_events(); 1724 print_bad_events();
1718 printf("\n"); 1725 printf("\n");
1719 1726
1727 perf_session__delete(session);
1720} 1728}
1721 1729
1722static struct trace_sched_handler map_ops = { 1730static struct trace_sched_handler map_ops = {
@@ -1731,7 +1739,7 @@ static void __cmd_map(void)
1731 max_cpu = sysconf(_SC_NPROCESSORS_CONF); 1739 max_cpu = sysconf(_SC_NPROCESSORS_CONF);
1732 1740
1733 setup_pager(); 1741 setup_pager();
1734 read_events(); 1742 read_events(true, NULL);
1735 print_bad_events(); 1743 print_bad_events();
1736} 1744}
1737 1745
@@ -1744,7 +1752,7 @@ static void __cmd_replay(void)
1744 1752
1745 test_calibrations(); 1753 test_calibrations();
1746 1754
1747 read_events(); 1755 read_events(true, NULL);
1748 1756
1749 printf("nr_run_events: %ld\n", nr_run_events); 1757 printf("nr_run_events: %ld\n", nr_run_events);
1750 printf("nr_sleep_events: %ld\n", nr_sleep_events); 1758 printf("nr_sleep_events: %ld\n", nr_sleep_events);
@@ -1769,7 +1777,7 @@ static void __cmd_replay(void)
1769 1777
1770 1778
1771static const char * const sched_usage[] = { 1779static const char * const sched_usage[] = {
1772 "perf sched [<options>] {record|latency|map|replay|trace}", 1780 "perf sched [<options>] {record|latency|map|replay|script}",
1773 NULL 1781 NULL
1774}; 1782};
1775 1783
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 09024ec2ab2e..2f62a2952269 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -22,6 +22,7 @@ static u64 last_timestamp;
22static u64 nr_unordered; 22static u64 nr_unordered;
23extern const struct option record_options[]; 23extern const struct option record_options[];
24static bool no_callchain; 24static bool no_callchain;
25static bool show_full_info;
25static const char *cpu_list; 26static const char *cpu_list;
26static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 27static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
27 28
@@ -1083,7 +1084,8 @@ static const struct option options[] = {
1083 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", 1084 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr",
1084 parse_output_fields), 1085 parse_output_fields),
1085 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 1086 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
1086 1087 OPT_BOOLEAN('I', "show-info", &show_full_info,
1088 "display extended information from perf.data file"),
1087 OPT_END() 1089 OPT_END()
1088}; 1090};
1089 1091
@@ -1268,6 +1270,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
1268 return -1; 1270 return -1;
1269 } 1271 }
1270 1272
1273 perf_session__fprintf_info(session, stdout, show_full_info);
1274
1271 if (!no_callchain) 1275 if (!no_callchain)
1272 symbol_conf.use_callchain = true; 1276 symbol_conf.use_callchain = true;
1273 else 1277 else
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 1ad04ce29c34..7ce65f52415e 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -193,6 +193,10 @@ static int big_num_opt = -1;
193static const char *cpu_list; 193static const char *cpu_list;
194static const char *csv_sep = NULL; 194static const char *csv_sep = NULL;
195static bool csv_output = false; 195static bool csv_output = false;
196static bool group = false;
197static const char *output_name = NULL;
198static FILE *output = NULL;
199static int output_fd;
196 200
197static volatile int done = 0; 201static volatile int done = 0;
198 202
@@ -250,8 +254,13 @@ static double avg_stats(struct stats *stats)
250 */ 254 */
251static double stddev_stats(struct stats *stats) 255static double stddev_stats(struct stats *stats)
252{ 256{
253 double variance = stats->M2 / (stats->n - 1); 257 double variance, variance_mean;
254 double variance_mean = variance / stats->n; 258
259 if (!stats->n)
260 return 0.0;
261
262 variance = stats->M2 / (stats->n - 1);
263 variance_mean = variance / stats->n;
255 264
256 return sqrt(variance_mean); 265 return sqrt(variance_mean);
257} 266}
@@ -280,14 +289,14 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
280 attr->inherit = !no_inherit; 289 attr->inherit = !no_inherit;
281 290
282 if (system_wide) 291 if (system_wide)
283 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false); 292 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group);
284 293
285 if (target_pid == -1 && target_tid == -1) { 294 if (target_pid == -1 && target_tid == -1) {
286 attr->disabled = 1; 295 attr->disabled = 1;
287 attr->enable_on_exec = 1; 296 attr->enable_on_exec = 1;
288 } 297 }
289 298
290 return perf_evsel__open_per_thread(evsel, evsel_list->threads, false); 299 return perf_evsel__open_per_thread(evsel, evsel_list->threads, group);
291} 300}
292 301
293/* 302/*
@@ -351,7 +360,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
351 update_stats(&ps->res_stats[i], count[i]); 360 update_stats(&ps->res_stats[i], count[i]);
352 361
353 if (verbose) { 362 if (verbose) {
354 fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", 363 fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
355 event_name(counter), count[0], count[1], count[2]); 364 event_name(counter), count[0], count[1], count[2]);
356 } 365 }
357 366
@@ -486,6 +495,8 @@ static int run_perf_stat(int argc __used, const char **argv)
486 if (forks) { 495 if (forks) {
487 close(go_pipe[1]); 496 close(go_pipe[1]);
488 wait(&status); 497 wait(&status);
498 if (WIFSIGNALED(status))
499 psignal(WTERMSIG(status), argv[0]);
489 } else { 500 } else {
490 while(!done) sleep(1); 501 while(!done) sleep(1);
491 } 502 }
@@ -518,9 +529,9 @@ static void print_noise_pct(double total, double avg)
518 pct = 100.0*total/avg; 529 pct = 100.0*total/avg;
519 530
520 if (csv_output) 531 if (csv_output)
521 fprintf(stderr, "%s%.2f%%", csv_sep, pct); 532 fprintf(output, "%s%.2f%%", csv_sep, pct);
522 else 533 else if (pct)
523 fprintf(stderr, " ( +-%6.2f%% )", pct); 534 fprintf(output, " ( +-%6.2f%% )", pct);
524} 535}
525 536
526static void print_noise(struct perf_evsel *evsel, double avg) 537static void print_noise(struct perf_evsel *evsel, double avg)
@@ -545,16 +556,17 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
545 csv_output ? 0 : -4, 556 csv_output ? 0 : -4,
546 evsel_list->cpus->map[cpu], csv_sep); 557 evsel_list->cpus->map[cpu], csv_sep);
547 558
548 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel)); 559 fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel));
549 560
550 if (evsel->cgrp) 561 if (evsel->cgrp)
551 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); 562 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
552 563
553 if (csv_output) 564 if (csv_output)
554 return; 565 return;
555 566
556 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 567 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
557 fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats)); 568 fprintf(output, " # %8.3f CPUs utilized ",
569 avg / avg_stats(&walltime_nsecs_stats));
558} 570}
559 571
560static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) 572static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -575,9 +587,9 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us
575 else if (ratio > 10.0) 587 else if (ratio > 10.0)
576 color = PERF_COLOR_YELLOW; 588 color = PERF_COLOR_YELLOW;
577 589
578 fprintf(stderr, " # "); 590 fprintf(output, " # ");
579 color_fprintf(stderr, color, "%6.2f%%", ratio); 591 color_fprintf(output, color, "%6.2f%%", ratio);
580 fprintf(stderr, " frontend cycles idle "); 592 fprintf(output, " frontend cycles idle ");
581} 593}
582 594
583static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg) 595static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -598,9 +610,9 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use
598 else if (ratio > 20.0) 610 else if (ratio > 20.0)
599 color = PERF_COLOR_YELLOW; 611 color = PERF_COLOR_YELLOW;
600 612
601 fprintf(stderr, " # "); 613 fprintf(output, " # ");
602 color_fprintf(stderr, color, "%6.2f%%", ratio); 614 color_fprintf(output, color, "%6.2f%%", ratio);
603 fprintf(stderr, " backend cycles idle "); 615 fprintf(output, " backend cycles idle ");
604} 616}
605 617
606static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) 618static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -621,9 +633,9 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double
621 else if (ratio > 5.0) 633 else if (ratio > 5.0)
622 color = PERF_COLOR_YELLOW; 634 color = PERF_COLOR_YELLOW;
623 635
624 fprintf(stderr, " # "); 636 fprintf(output, " # ");
625 color_fprintf(stderr, color, "%6.2f%%", ratio); 637 color_fprintf(output, color, "%6.2f%%", ratio);
626 fprintf(stderr, " of all branches "); 638 fprintf(output, " of all branches ");
627} 639}
628 640
629static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 641static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -644,9 +656,9 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou
644 else if (ratio > 5.0) 656 else if (ratio > 5.0)
645 color = PERF_COLOR_YELLOW; 657 color = PERF_COLOR_YELLOW;
646 658
647 fprintf(stderr, " # "); 659 fprintf(output, " # ");
648 color_fprintf(stderr, color, "%6.2f%%", ratio); 660 color_fprintf(output, color, "%6.2f%%", ratio);
649 fprintf(stderr, " of all L1-dcache hits "); 661 fprintf(output, " of all L1-dcache hits ");
650} 662}
651 663
652static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 664static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -667,9 +679,9 @@ static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, dou
667 else if (ratio > 5.0) 679 else if (ratio > 5.0)
668 color = PERF_COLOR_YELLOW; 680 color = PERF_COLOR_YELLOW;
669 681
670 fprintf(stderr, " # "); 682 fprintf(output, " # ");
671 color_fprintf(stderr, color, "%6.2f%%", ratio); 683 color_fprintf(output, color, "%6.2f%%", ratio);
672 fprintf(stderr, " of all L1-icache hits "); 684 fprintf(output, " of all L1-icache hits ");
673} 685}
674 686
675static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 687static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -690,9 +702,9 @@ static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
690 else if (ratio > 5.0) 702 else if (ratio > 5.0)
691 color = PERF_COLOR_YELLOW; 703 color = PERF_COLOR_YELLOW;
692 704
693 fprintf(stderr, " # "); 705 fprintf(output, " # ");
694 color_fprintf(stderr, color, "%6.2f%%", ratio); 706 color_fprintf(output, color, "%6.2f%%", ratio);
695 fprintf(stderr, " of all dTLB cache hits "); 707 fprintf(output, " of all dTLB cache hits ");
696} 708}
697 709
698static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 710static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -713,9 +725,9 @@ static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
713 else if (ratio > 5.0) 725 else if (ratio > 5.0)
714 color = PERF_COLOR_YELLOW; 726 color = PERF_COLOR_YELLOW;
715 727
716 fprintf(stderr, " # "); 728 fprintf(output, " # ");
717 color_fprintf(stderr, color, "%6.2f%%", ratio); 729 color_fprintf(output, color, "%6.2f%%", ratio);
718 fprintf(stderr, " of all iTLB cache hits "); 730 fprintf(output, " of all iTLB cache hits ");
719} 731}
720 732
721static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 733static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -736,9 +748,9 @@ static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, doub
736 else if (ratio > 5.0) 748 else if (ratio > 5.0)
737 color = PERF_COLOR_YELLOW; 749 color = PERF_COLOR_YELLOW;
738 750
739 fprintf(stderr, " # "); 751 fprintf(output, " # ");
740 color_fprintf(stderr, color, "%6.2f%%", ratio); 752 color_fprintf(output, color, "%6.2f%%", ratio);
741 fprintf(stderr, " of all LL-cache hits "); 753 fprintf(output, " of all LL-cache hits ");
742} 754}
743 755
744static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) 756static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
@@ -761,10 +773,10 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
761 else 773 else
762 cpu = 0; 774 cpu = 0;
763 775
764 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel)); 776 fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel));
765 777
766 if (evsel->cgrp) 778 if (evsel->cgrp)
767 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); 779 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
768 780
769 if (csv_output) 781 if (csv_output)
770 return; 782 return;
@@ -775,14 +787,14 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
775 if (total) 787 if (total)
776 ratio = avg / total; 788 ratio = avg / total;
777 789
778 fprintf(stderr, " # %5.2f insns per cycle ", ratio); 790 fprintf(output, " # %5.2f insns per cycle ", ratio);
779 791
780 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); 792 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
781 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); 793 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
782 794
783 if (total && avg) { 795 if (total && avg) {
784 ratio = total / avg; 796 ratio = total / avg;
785 fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio); 797 fprintf(output, "\n # %5.2f stalled cycles per insn", ratio);
786 } 798 }
787 799
788 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 800 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
@@ -830,7 +842,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
830 if (total) 842 if (total)
831 ratio = avg * 100 / total; 843 ratio = avg * 100 / total;
832 844
833 fprintf(stderr, " # %8.3f %% of all cache refs ", ratio); 845 fprintf(output, " # %8.3f %% of all cache refs ", ratio);
834 846
835 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { 847 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
836 print_stalled_cycles_frontend(cpu, evsel, avg); 848 print_stalled_cycles_frontend(cpu, evsel, avg);
@@ -842,16 +854,16 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
842 if (total) 854 if (total)
843 ratio = 1.0 * avg / total; 855 ratio = 1.0 * avg / total;
844 856
845 fprintf(stderr, " # %8.3f GHz ", ratio); 857 fprintf(output, " # %8.3f GHz ", ratio);
846 } else if (runtime_nsecs_stats[cpu].n != 0) { 858 } else if (runtime_nsecs_stats[cpu].n != 0) {
847 total = avg_stats(&runtime_nsecs_stats[cpu]); 859 total = avg_stats(&runtime_nsecs_stats[cpu]);
848 860
849 if (total) 861 if (total)
850 ratio = 1000.0 * avg / total; 862 ratio = 1000.0 * avg / total;
851 863
852 fprintf(stderr, " # %8.3f M/sec ", ratio); 864 fprintf(output, " # %8.3f M/sec ", ratio);
853 } else { 865 } else {
854 fprintf(stderr, " "); 866 fprintf(output, " ");
855 } 867 }
856} 868}
857 869
@@ -866,7 +878,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
866 int scaled = counter->counts->scaled; 878 int scaled = counter->counts->scaled;
867 879
868 if (scaled == -1) { 880 if (scaled == -1) {
869 fprintf(stderr, "%*s%s%*s", 881 fprintf(output, "%*s%s%*s",
870 csv_output ? 0 : 18, 882 csv_output ? 0 : 18,
871 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 883 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
872 csv_sep, 884 csv_sep,
@@ -874,9 +886,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
874 event_name(counter)); 886 event_name(counter));
875 887
876 if (counter->cgrp) 888 if (counter->cgrp)
877 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); 889 fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
878 890
879 fputc('\n', stderr); 891 fputc('\n', output);
880 return; 892 return;
881 } 893 }
882 894
@@ -888,7 +900,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
888 print_noise(counter, avg); 900 print_noise(counter, avg);
889 901
890 if (csv_output) { 902 if (csv_output) {
891 fputc('\n', stderr); 903 fputc('\n', output);
892 return; 904 return;
893 } 905 }
894 906
@@ -898,9 +910,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
898 avg_enabled = avg_stats(&ps->res_stats[1]); 910 avg_enabled = avg_stats(&ps->res_stats[1]);
899 avg_running = avg_stats(&ps->res_stats[2]); 911 avg_running = avg_stats(&ps->res_stats[2]);
900 912
901 fprintf(stderr, " [%5.2f%%]", 100 * avg_running / avg_enabled); 913 fprintf(output, " [%5.2f%%]", 100 * avg_running / avg_enabled);
902 } 914 }
903 fprintf(stderr, "\n"); 915 fprintf(output, "\n");
904} 916}
905 917
906/* 918/*
@@ -917,7 +929,7 @@ static void print_counter(struct perf_evsel *counter)
917 ena = counter->counts->cpu[cpu].ena; 929 ena = counter->counts->cpu[cpu].ena;
918 run = counter->counts->cpu[cpu].run; 930 run = counter->counts->cpu[cpu].run;
919 if (run == 0 || ena == 0) { 931 if (run == 0 || ena == 0) {
920 fprintf(stderr, "CPU%*d%s%*s%s%*s", 932 fprintf(output, "CPU%*d%s%*s%s%*s",
921 csv_output ? 0 : -4, 933 csv_output ? 0 : -4,
922 evsel_list->cpus->map[cpu], csv_sep, 934 evsel_list->cpus->map[cpu], csv_sep,
923 csv_output ? 0 : 18, 935 csv_output ? 0 : 18,
@@ -927,9 +939,10 @@ static void print_counter(struct perf_evsel *counter)
927 event_name(counter)); 939 event_name(counter));
928 940
929 if (counter->cgrp) 941 if (counter->cgrp)
930 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); 942 fprintf(output, "%s%s",
943 csv_sep, counter->cgrp->name);
931 944
932 fputc('\n', stderr); 945 fputc('\n', output);
933 continue; 946 continue;
934 } 947 }
935 948
@@ -942,9 +955,10 @@ static void print_counter(struct perf_evsel *counter)
942 print_noise(counter, 1.0); 955 print_noise(counter, 1.0);
943 956
944 if (run != ena) 957 if (run != ena)
945 fprintf(stderr, " (%.2f%%)", 100.0 * run / ena); 958 fprintf(output, " (%.2f%%)",
959 100.0 * run / ena);
946 } 960 }
947 fputc('\n', stderr); 961 fputc('\n', output);
948 } 962 }
949} 963}
950 964
@@ -956,21 +970,21 @@ static void print_stat(int argc, const char **argv)
956 fflush(stdout); 970 fflush(stdout);
957 971
958 if (!csv_output) { 972 if (!csv_output) {
959 fprintf(stderr, "\n"); 973 fprintf(output, "\n");
960 fprintf(stderr, " Performance counter stats for "); 974 fprintf(output, " Performance counter stats for ");
961 if(target_pid == -1 && target_tid == -1) { 975 if(target_pid == -1 && target_tid == -1) {
962 fprintf(stderr, "\'%s", argv[0]); 976 fprintf(output, "\'%s", argv[0]);
963 for (i = 1; i < argc; i++) 977 for (i = 1; i < argc; i++)
964 fprintf(stderr, " %s", argv[i]); 978 fprintf(output, " %s", argv[i]);
965 } else if (target_pid != -1) 979 } else if (target_pid != -1)
966 fprintf(stderr, "process id \'%d", target_pid); 980 fprintf(output, "process id \'%d", target_pid);
967 else 981 else
968 fprintf(stderr, "thread id \'%d", target_tid); 982 fprintf(output, "thread id \'%d", target_tid);
969 983
970 fprintf(stderr, "\'"); 984 fprintf(output, "\'");
971 if (run_count > 1) 985 if (run_count > 1)
972 fprintf(stderr, " (%d runs)", run_count); 986 fprintf(output, " (%d runs)", run_count);
973 fprintf(stderr, ":\n\n"); 987 fprintf(output, ":\n\n");
974 } 988 }
975 989
976 if (no_aggr) { 990 if (no_aggr) {
@@ -983,15 +997,15 @@ static void print_stat(int argc, const char **argv)
983 997
984 if (!csv_output) { 998 if (!csv_output) {
985 if (!null_run) 999 if (!null_run)
986 fprintf(stderr, "\n"); 1000 fprintf(output, "\n");
987 fprintf(stderr, " %17.9f seconds time elapsed", 1001 fprintf(output, " %17.9f seconds time elapsed",
988 avg_stats(&walltime_nsecs_stats)/1e9); 1002 avg_stats(&walltime_nsecs_stats)/1e9);
989 if (run_count > 1) { 1003 if (run_count > 1) {
990 fprintf(stderr, " "); 1004 fprintf(output, " ");
991 print_noise_pct(stddev_stats(&walltime_nsecs_stats), 1005 print_noise_pct(stddev_stats(&walltime_nsecs_stats),
992 avg_stats(&walltime_nsecs_stats)); 1006 avg_stats(&walltime_nsecs_stats));
993 } 1007 }
994 fprintf(stderr, "\n\n"); 1008 fprintf(output, "\n\n");
995 } 1009 }
996} 1010}
997 1011
@@ -1029,6 +1043,8 @@ static int stat__set_big_num(const struct option *opt __used,
1029 return 0; 1043 return 0;
1030} 1044}
1031 1045
1046static bool append_file;
1047
1032static const struct option options[] = { 1048static const struct option options[] = {
1033 OPT_CALLBACK('e', "event", &evsel_list, "event", 1049 OPT_CALLBACK('e', "event", &evsel_list, "event",
1034 "event selector. use 'perf list' to list available events", 1050 "event selector. use 'perf list' to list available events",
@@ -1043,6 +1059,8 @@ static const struct option options[] = {
1043 "stat events on existing thread id"), 1059 "stat events on existing thread id"),
1044 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1060 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1045 "system-wide collection from all CPUs"), 1061 "system-wide collection from all CPUs"),
1062 OPT_BOOLEAN('g', "group", &group,
1063 "put the counters into a counter group"),
1046 OPT_BOOLEAN('c', "scale", &scale, 1064 OPT_BOOLEAN('c', "scale", &scale,
1047 "scale/normalize counters"), 1065 "scale/normalize counters"),
1048 OPT_INCR('v', "verbose", &verbose, 1066 OPT_INCR('v', "verbose", &verbose,
@@ -1067,6 +1085,11 @@ static const struct option options[] = {
1067 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 1085 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
1068 "monitor event in cgroup name only", 1086 "monitor event in cgroup name only",
1069 parse_cgroups), 1087 parse_cgroups),
1088 OPT_STRING('o', "output", &output_name, "file",
1089 "output file name"),
1090 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
1091 OPT_INTEGER(0, "log-fd", &output_fd,
1092 "log output to fd, instead of stderr"),
1070 OPT_END() 1093 OPT_END()
1071}; 1094};
1072 1095
@@ -1138,6 +1161,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1138{ 1161{
1139 struct perf_evsel *pos; 1162 struct perf_evsel *pos;
1140 int status = -ENOMEM; 1163 int status = -ENOMEM;
1164 const char *mode;
1141 1165
1142 setlocale(LC_ALL, ""); 1166 setlocale(LC_ALL, "");
1143 1167
@@ -1148,16 +1172,46 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1148 argc = parse_options(argc, argv, options, stat_usage, 1172 argc = parse_options(argc, argv, options, stat_usage,
1149 PARSE_OPT_STOP_AT_NON_OPTION); 1173 PARSE_OPT_STOP_AT_NON_OPTION);
1150 1174
1151 if (csv_sep) 1175 output = stderr;
1176 if (output_name && strcmp(output_name, "-"))
1177 output = NULL;
1178
1179 if (output_name && output_fd) {
1180 fprintf(stderr, "cannot use both --output and --log-fd\n");
1181 usage_with_options(stat_usage, options);
1182 }
1183 if (!output) {
1184 struct timespec tm;
1185 mode = append_file ? "a" : "w";
1186
1187 output = fopen(output_name, mode);
1188 if (!output) {
1189 perror("failed to create output file");
1190 exit(-1);
1191 }
1192 clock_gettime(CLOCK_REALTIME, &tm);
1193 fprintf(output, "# started on %s\n", ctime(&tm.tv_sec));
1194 } else if (output_fd != 2) {
1195 mode = append_file ? "a" : "w";
1196 output = fdopen(output_fd, mode);
1197 if (!output) {
1198 perror("Failed opening logfd");
1199 return -errno;
1200 }
1201 }
1202
1203 if (csv_sep) {
1152 csv_output = true; 1204 csv_output = true;
1153 else 1205 if (!strcmp(csv_sep, "\\t"))
1206 csv_sep = "\t";
1207 } else
1154 csv_sep = DEFAULT_SEPARATOR; 1208 csv_sep = DEFAULT_SEPARATOR;
1155 1209
1156 /* 1210 /*
1157 * let the spreadsheet do the pretty-printing 1211 * let the spreadsheet do the pretty-printing
1158 */ 1212 */
1159 if (csv_output) { 1213 if (csv_output) {
1160 /* User explicitely passed -B? */ 1214 /* User explicitly passed -B? */
1161 if (big_num_opt == 1) { 1215 if (big_num_opt == 1) {
1162 fprintf(stderr, "-B option not supported with -x\n"); 1216 fprintf(stderr, "-B option not supported with -x\n");
1163 usage_with_options(stat_usage, options); 1217 usage_with_options(stat_usage, options);
@@ -1223,7 +1277,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1223 status = 0; 1277 status = 0;
1224 for (run_idx = 0; run_idx < run_count; run_idx++) { 1278 for (run_idx = 0; run_idx < run_count; run_idx++) {
1225 if (run_count != 1 && verbose) 1279 if (run_count != 1 && verbose)
1226 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); 1280 fprintf(output, "[ perf stat: executing run #%d ... ]\n",
1281 run_idx + 1);
1227 1282
1228 if (sync_run) 1283 if (sync_run)
1229 sync(); 1284 sync();
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 55f4c76f2821..efe696f936e2 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -561,7 +561,7 @@ static int test__basic_mmap(void)
561 } 561 }
562 562
563 err = perf_event__parse_sample(event, attr.sample_type, sample_size, 563 err = perf_event__parse_sample(event, attr.sample_type, sample_size,
564 false, &sample); 564 false, &sample, false);
565 if (err) { 565 if (err) {
566 pr_err("Can't parse sample, err = %d\n", err); 566 pr_err("Can't parse sample, err = %d\n", err);
567 goto out_munmap; 567 goto out_munmap;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index a43433f08300..7a871714d44e 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -5,6 +5,7 @@
5 * any workload, CPU or specific PID. 5 * any workload, CPU or specific PID.
6 * 6 *
7 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> 7 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
8 * 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
8 * 9 *
9 * Improvements and fixes by: 10 * Improvements and fixes by:
10 * 11 *
@@ -36,6 +37,7 @@
36#include "util/parse-events.h" 37#include "util/parse-events.h"
37#include "util/cpumap.h" 38#include "util/cpumap.h"
38#include "util/xyarray.h" 39#include "util/xyarray.h"
40#include "util/sort.h"
39 41
40#include "util/debug.h" 42#include "util/debug.h"
41 43
@@ -65,12 +67,8 @@
65static struct perf_top top = { 67static struct perf_top top = {
66 .count_filter = 5, 68 .count_filter = 5,
67 .delay_secs = 2, 69 .delay_secs = 2,
68 .display_weighted = -1,
69 .target_pid = -1, 70 .target_pid = -1,
70 .target_tid = -1, 71 .target_tid = -1,
71 .active_symbols = LIST_HEAD_INIT(top.active_symbols),
72 .active_symbols_lock = PTHREAD_MUTEX_INITIALIZER,
73 .active_symbols_cond = PTHREAD_COND_INITIALIZER,
74 .freq = 1000, /* 1 KHz */ 72 .freq = 1000, /* 1 KHz */
75}; 73};
76 74
@@ -78,6 +76,12 @@ static bool system_wide = false;
78 76
79static bool use_tui, use_stdio; 77static bool use_tui, use_stdio;
80 78
79static bool sort_has_symbols;
80
81static bool dont_use_callchains;
82static char callchain_default_opt[] = "fractal,0.5,callee";
83
84
81static int default_interval = 0; 85static int default_interval = 0;
82 86
83static bool kptr_restrict_warned; 87static bool kptr_restrict_warned;
@@ -85,7 +89,6 @@ static bool vmlinux_warned;
85static bool inherit = false; 89static bool inherit = false;
86static int realtime_prio = 0; 90static int realtime_prio = 0;
87static bool group = false; 91static bool group = false;
88static unsigned int page_size;
89static unsigned int mmap_pages = 128; 92static unsigned int mmap_pages = 128;
90 93
91static bool dump_symtab = false; 94static bool dump_symtab = false;
@@ -93,7 +96,6 @@ static bool dump_symtab = false;
93static struct winsize winsize; 96static struct winsize winsize;
94 97
95static const char *sym_filter = NULL; 98static const char *sym_filter = NULL;
96struct sym_entry *sym_filter_entry_sched = NULL;
97static int sym_pcnt_filter = 5; 99static int sym_pcnt_filter = 5;
98 100
99/* 101/*
@@ -136,18 +138,18 @@ static void sig_winch_handler(int sig __used)
136 update_print_entries(&winsize); 138 update_print_entries(&winsize);
137} 139}
138 140
139static int parse_source(struct sym_entry *syme) 141static int parse_source(struct hist_entry *he)
140{ 142{
141 struct symbol *sym; 143 struct symbol *sym;
142 struct annotation *notes; 144 struct annotation *notes;
143 struct map *map; 145 struct map *map;
144 int err = -1; 146 int err = -1;
145 147
146 if (!syme) 148 if (!he || !he->ms.sym)
147 return -1; 149 return -1;
148 150
149 sym = sym_entry__symbol(syme); 151 sym = he->ms.sym;
150 map = syme->map; 152 map = he->ms.map;
151 153
152 /* 154 /*
153 * We can't annotate with just /proc/kallsyms 155 * We can't annotate with just /proc/kallsyms
@@ -175,52 +177,62 @@ static int parse_source(struct sym_entry *syme)
175 return err; 177 return err;
176 } 178 }
177 179
178 err = symbol__annotate(sym, syme->map, 0); 180 err = symbol__annotate(sym, map, 0);
179 if (err == 0) { 181 if (err == 0) {
180out_assign: 182out_assign:
181 top.sym_filter_entry = syme; 183 top.sym_filter_entry = he;
182 } 184 }
183 185
184 pthread_mutex_unlock(&notes->lock); 186 pthread_mutex_unlock(&notes->lock);
185 return err; 187 return err;
186} 188}
187 189
188static void __zero_source_counters(struct sym_entry *syme) 190static void __zero_source_counters(struct hist_entry *he)
189{ 191{
190 struct symbol *sym = sym_entry__symbol(syme); 192 struct symbol *sym = he->ms.sym;
191 symbol__annotate_zero_histograms(sym); 193 symbol__annotate_zero_histograms(sym);
192} 194}
193 195
194static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) 196static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
195{ 197{
196 struct annotation *notes; 198 struct annotation *notes;
197 struct symbol *sym; 199 struct symbol *sym;
198 200
199 if (syme != top.sym_filter_entry) 201 if (he == NULL || he->ms.sym == NULL ||
202 (he != top.sym_filter_entry && use_browser != 1))
200 return; 203 return;
201 204
202 sym = sym_entry__symbol(syme); 205 sym = he->ms.sym;
203 notes = symbol__annotation(sym); 206 notes = symbol__annotation(sym);
204 207
205 if (pthread_mutex_trylock(&notes->lock)) 208 if (pthread_mutex_trylock(&notes->lock))
206 return; 209 return;
207 210
208 ip = syme->map->map_ip(syme->map, ip); 211 if (notes->src == NULL &&
209 symbol__inc_addr_samples(sym, syme->map, counter, ip); 212 symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
213 pthread_mutex_unlock(&notes->lock);
214 pr_err("Not enough memory for annotating '%s' symbol!\n",
215 sym->name);
216 sleep(1);
217 return;
218 }
219
220 ip = he->ms.map->map_ip(he->ms.map, ip);
221 symbol__inc_addr_samples(sym, he->ms.map, counter, ip);
210 222
211 pthread_mutex_unlock(&notes->lock); 223 pthread_mutex_unlock(&notes->lock);
212} 224}
213 225
214static void show_details(struct sym_entry *syme) 226static void show_details(struct hist_entry *he)
215{ 227{
216 struct annotation *notes; 228 struct annotation *notes;
217 struct symbol *symbol; 229 struct symbol *symbol;
218 int more; 230 int more;
219 231
220 if (!syme) 232 if (!he)
221 return; 233 return;
222 234
223 symbol = sym_entry__symbol(syme); 235 symbol = he->ms.sym;
224 notes = symbol__annotation(symbol); 236 notes = symbol__annotation(symbol);
225 237
226 pthread_mutex_lock(&notes->lock); 238 pthread_mutex_lock(&notes->lock);
@@ -231,7 +243,7 @@ static void show_details(struct sym_entry *syme)
231 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); 243 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name);
232 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 244 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
233 245
234 more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx, 246 more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx,
235 0, sym_pcnt_filter, top.print_entries, 4); 247 0, sym_pcnt_filter, top.print_entries, 4);
236 if (top.zero) 248 if (top.zero)
237 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); 249 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx);
@@ -245,21 +257,28 @@ out_unlock:
245 257
246static const char CONSOLE_CLEAR[] = ""; 258static const char CONSOLE_CLEAR[] = "";
247 259
248static void __list_insert_active_sym(struct sym_entry *syme) 260static struct hist_entry *
261 perf_session__add_hist_entry(struct perf_session *session,
262 struct addr_location *al,
263 struct perf_sample *sample,
264 struct perf_evsel *evsel)
249{ 265{
250 list_add(&syme->node, &top.active_symbols); 266 struct hist_entry *he;
267
268 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period);
269 if (he == NULL)
270 return NULL;
271
272 session->hists.stats.total_period += sample->period;
273 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
274 return he;
251} 275}
252 276
253static void print_sym_table(struct perf_session *session) 277static void print_sym_table(void)
254{ 278{
255 char bf[160]; 279 char bf[160];
256 int printed = 0; 280 int printed = 0;
257 struct rb_node *nd;
258 struct sym_entry *syme;
259 struct rb_root tmp = RB_ROOT;
260 const int win_width = winsize.ws_col - 1; 281 const int win_width = winsize.ws_col - 1;
261 int sym_width, dso_width, dso_short_width;
262 float sum_ksamples = perf_top__decay_samples(&top, &tmp);
263 282
264 puts(CONSOLE_CLEAR); 283 puts(CONSOLE_CLEAR);
265 284
@@ -270,10 +289,12 @@ static void print_sym_table(struct perf_session *session)
270 289
271 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 290 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
272 291
273 if (session->hists.stats.total_lost != 0) { 292 if (top.total_lost_warned != top.session->hists.stats.total_lost) {
293 top.total_lost_warned = top.session->hists.stats.total_lost;
274 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); 294 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
275 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", 295 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
276 session->hists.stats.total_lost); 296 top.total_lost_warned);
297 ++printed;
277 } 298 }
278 299
279 if (top.sym_filter_entry) { 300 if (top.sym_filter_entry) {
@@ -281,58 +302,15 @@ static void print_sym_table(struct perf_session *session)
281 return; 302 return;
282 } 303 }
283 304
284 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width, 305 hists__collapse_resort_threaded(&top.sym_evsel->hists);
285 &sym_width); 306 hists__output_resort_threaded(&top.sym_evsel->hists);
286 307 hists__decay_entries_threaded(&top.sym_evsel->hists,
287 if (sym_width + dso_width > winsize.ws_col - 29) { 308 top.hide_user_symbols,
288 dso_width = dso_short_width; 309 top.hide_kernel_symbols);
289 if (sym_width + dso_width > winsize.ws_col - 29) 310 hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3);
290 sym_width = winsize.ws_col - dso_width - 29;
291 }
292 putchar('\n'); 311 putchar('\n');
293 if (top.evlist->nr_entries == 1) 312 hists__fprintf(&top.sym_evsel->hists, NULL, false, false,
294 printf(" samples pcnt"); 313 winsize.ws_row - 4 - printed, win_width, stdout);
295 else
296 printf(" weight samples pcnt");
297
298 if (verbose)
299 printf(" RIP ");
300 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
301 printf(" %s _______ _____",
302 top.evlist->nr_entries == 1 ? " " : "______");
303 if (verbose)
304 printf(" ________________");
305 printf(" %-*.*s", sym_width, sym_width, graph_line);
306 printf(" %-*.*s", dso_width, dso_width, graph_line);
307 puts("\n");
308
309 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
310 struct symbol *sym;
311 double pcnt;
312
313 syme = rb_entry(nd, struct sym_entry, rb_node);
314 sym = sym_entry__symbol(syme);
315 if (++printed > top.print_entries ||
316 (int)syme->snap_count < top.count_filter)
317 continue;
318
319 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
320 sum_ksamples));
321
322 if (top.evlist->nr_entries == 1 || !top.display_weighted)
323 printf("%20.2f ", syme->weight);
324 else
325 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
326
327 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
328 if (verbose)
329 printf(" %016" PRIx64, sym->start);
330 printf(" %-*.*s", sym_width, sym_width, sym->name);
331 printf(" %-*.*s\n", dso_width, dso_width,
332 dso_width >= syme->map->dso->long_name_len ?
333 syme->map->dso->long_name :
334 syme->map->dso->short_name);
335 }
336} 314}
337 315
338static void prompt_integer(int *target, const char *msg) 316static void prompt_integer(int *target, const char *msg)
@@ -370,10 +348,11 @@ static void prompt_percent(int *target, const char *msg)
370 *target = tmp; 348 *target = tmp;
371} 349}
372 350
373static void prompt_symbol(struct sym_entry **target, const char *msg) 351static void prompt_symbol(struct hist_entry **target, const char *msg)
374{ 352{
375 char *buf = malloc(0), *p; 353 char *buf = malloc(0), *p;
376 struct sym_entry *syme = *target, *n, *found = NULL; 354 struct hist_entry *syme = *target, *n, *found = NULL;
355 struct rb_node *next;
377 size_t dummy = 0; 356 size_t dummy = 0;
378 357
379 /* zero counters of active symbol */ 358 /* zero counters of active symbol */
@@ -390,17 +369,14 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
390 if (p) 369 if (p)
391 *p = 0; 370 *p = 0;
392 371
393 pthread_mutex_lock(&top.active_symbols_lock); 372 next = rb_first(&top.sym_evsel->hists.entries);
394 syme = list_entry(top.active_symbols.next, struct sym_entry, node); 373 while (next) {
395 pthread_mutex_unlock(&top.active_symbols_lock); 374 n = rb_entry(next, struct hist_entry, rb_node);
396 375 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
397 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) { 376 found = n;
398 struct symbol *sym = sym_entry__symbol(syme);
399
400 if (!strcmp(buf, sym->name)) {
401 found = syme;
402 break; 377 break;
403 } 378 }
379 next = rb_next(&n->rb_node);
404 } 380 }
405 381
406 if (!found) { 382 if (!found) {
@@ -419,7 +395,7 @@ static void print_mapped_keys(void)
419 char *name = NULL; 395 char *name = NULL;
420 396
421 if (top.sym_filter_entry) { 397 if (top.sym_filter_entry) {
422 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); 398 struct symbol *sym = top.sym_filter_entry->ms.sym;
423 name = sym->name; 399 name = sym->name;
424 } 400 }
425 401
@@ -436,9 +412,6 @@ static void print_mapped_keys(void)
436 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 412 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
437 fprintf(stdout, "\t[S] stop annotation.\n"); 413 fprintf(stdout, "\t[S] stop annotation.\n");
438 414
439 if (top.evlist->nr_entries > 1)
440 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", top.display_weighted ? 1 : 0);
441
442 fprintf(stdout, 415 fprintf(stdout,
443 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 416 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
444 top.hide_kernel_symbols ? "yes" : "no"); 417 top.hide_kernel_symbols ? "yes" : "no");
@@ -465,7 +438,6 @@ static int key_mapped(int c)
465 case 'S': 438 case 'S':
466 return 1; 439 return 1;
467 case 'E': 440 case 'E':
468 case 'w':
469 return top.evlist->nr_entries > 1 ? 1 : 0; 441 return top.evlist->nr_entries > 1 ? 1 : 0;
470 default: 442 default:
471 break; 443 break;
@@ -474,7 +446,7 @@ static int key_mapped(int c)
474 return 0; 446 return 0;
475} 447}
476 448
477static void handle_keypress(struct perf_session *session, int c) 449static void handle_keypress(int c)
478{ 450{
479 if (!key_mapped(c)) { 451 if (!key_mapped(c)) {
480 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 452 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -550,7 +522,7 @@ static void handle_keypress(struct perf_session *session, int c)
550 case 'Q': 522 case 'Q':
551 printf("exiting.\n"); 523 printf("exiting.\n");
552 if (dump_symtab) 524 if (dump_symtab)
553 perf_session__fprintf_dsos(session, stderr); 525 perf_session__fprintf_dsos(top.session, stderr);
554 exit(0); 526 exit(0);
555 case 's': 527 case 's':
556 prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); 528 prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
@@ -559,7 +531,7 @@ static void handle_keypress(struct perf_session *session, int c)
559 if (!top.sym_filter_entry) 531 if (!top.sym_filter_entry)
560 break; 532 break;
561 else { 533 else {
562 struct sym_entry *syme = top.sym_filter_entry; 534 struct hist_entry *syme = top.sym_filter_entry;
563 535
564 top.sym_filter_entry = NULL; 536 top.sym_filter_entry = NULL;
565 __zero_source_counters(syme); 537 __zero_source_counters(syme);
@@ -568,9 +540,6 @@ static void handle_keypress(struct perf_session *session, int c)
568 case 'U': 540 case 'U':
569 top.hide_user_symbols = !top.hide_user_symbols; 541 top.hide_user_symbols = !top.hide_user_symbols;
570 break; 542 break;
571 case 'w':
572 top.display_weighted = ~top.display_weighted;
573 break;
574 case 'z': 543 case 'z':
575 top.zero = !top.zero; 544 top.zero = !top.zero;
576 break; 545 break;
@@ -579,19 +548,31 @@ static void handle_keypress(struct perf_session *session, int c)
579 } 548 }
580} 549}
581 550
551static void perf_top__sort_new_samples(void *arg)
552{
553 struct perf_top *t = arg;
554 perf_top__reset_sample_counters(t);
555
556 if (t->evlist->selected != NULL)
557 t->sym_evsel = t->evlist->selected;
558
559 hists__collapse_resort_threaded(&t->sym_evsel->hists);
560 hists__output_resort_threaded(&t->sym_evsel->hists);
561 hists__decay_entries_threaded(&t->sym_evsel->hists,
562 top.hide_user_symbols,
563 top.hide_kernel_symbols);
564 hists__output_recalc_col_len(&t->sym_evsel->hists, winsize.ws_row - 3);
565}
566
582static void *display_thread_tui(void *arg __used) 567static void *display_thread_tui(void *arg __used)
583{ 568{
584 int err = 0; 569 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
585 pthread_mutex_lock(&top.active_symbols_lock); 570
586 while (list_empty(&top.active_symbols)) { 571 perf_top__sort_new_samples(&top);
587 err = pthread_cond_wait(&top.active_symbols_cond, 572 perf_evlist__tui_browse_hists(top.evlist, help,
588 &top.active_symbols_lock); 573 perf_top__sort_new_samples,
589 if (err) 574 &top, top.delay_secs);
590 break; 575
591 }
592 pthread_mutex_unlock(&top.active_symbols_lock);
593 if (!err)
594 perf_top__tui_browser(&top);
595 exit_browser(0); 576 exit_browser(0);
596 exit(0); 577 exit(0);
597 return NULL; 578 return NULL;
@@ -602,7 +583,6 @@ static void *display_thread(void *arg __used)
602 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 583 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
603 struct termios tc, save; 584 struct termios tc, save;
604 int delay_msecs, c; 585 int delay_msecs, c;
605 struct perf_session *session = (struct perf_session *) arg;
606 586
607 tcgetattr(0, &save); 587 tcgetattr(0, &save);
608 tc = save; 588 tc = save;
@@ -610,20 +590,35 @@ static void *display_thread(void *arg __used)
610 tc.c_cc[VMIN] = 0; 590 tc.c_cc[VMIN] = 0;
611 tc.c_cc[VTIME] = 0; 591 tc.c_cc[VTIME] = 0;
612 592
593 pthread__unblock_sigwinch();
613repeat: 594repeat:
614 delay_msecs = top.delay_secs * 1000; 595 delay_msecs = top.delay_secs * 1000;
615 tcsetattr(0, TCSANOW, &tc); 596 tcsetattr(0, TCSANOW, &tc);
616 /* trash return*/ 597 /* trash return*/
617 getc(stdin); 598 getc(stdin);
618 599
619 do { 600 while (1) {
620 print_sym_table(session); 601 print_sym_table();
621 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 602 /*
622 603 * Either timeout expired or we got an EINTR due to SIGWINCH,
604 * refresh screen in both cases.
605 */
606 switch (poll(&stdin_poll, 1, delay_msecs)) {
607 case 0:
608 continue;
609 case -1:
610 if (errno == EINTR)
611 continue;
612 /* Fall trhu */
613 default:
614 goto process_hotkey;
615 }
616 }
617process_hotkey:
623 c = getc(stdin); 618 c = getc(stdin);
624 tcsetattr(0, TCSAFLUSH, &save); 619 tcsetattr(0, TCSAFLUSH, &save);
625 620
626 handle_keypress(session, c); 621 handle_keypress(c);
627 goto repeat; 622 goto repeat;
628 623
629 return NULL; 624 return NULL;
@@ -644,9 +639,8 @@ static const char *skip_symbols[] = {
644 NULL 639 NULL
645}; 640};
646 641
647static int symbol_filter(struct map *map, struct symbol *sym) 642static int symbol_filter(struct map *map __used, struct symbol *sym)
648{ 643{
649 struct sym_entry *syme;
650 const char *name = sym->name; 644 const char *name = sym->name;
651 int i; 645 int i;
652 646
@@ -666,16 +660,6 @@ static int symbol_filter(struct map *map, struct symbol *sym)
666 strstr(name, "_text_end")) 660 strstr(name, "_text_end"))
667 return 1; 661 return 1;
668 662
669 syme = symbol__priv(sym);
670 syme->map = map;
671 symbol__annotate_init(map, sym);
672
673 if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
674 /* schedule initial sym_filter_entry setup */
675 sym_filter_entry_sched = syme;
676 sym_filter = NULL;
677 }
678
679 for (i = 0; skip_symbols[i]; i++) { 663 for (i = 0; skip_symbols[i]; i++) {
680 if (!strcmp(skip_symbols[i], name)) { 664 if (!strcmp(skip_symbols[i], name)) {
681 sym->ignore = true; 665 sym->ignore = true;
@@ -690,10 +674,11 @@ static void perf_event__process_sample(const union perf_event *event,
690 struct perf_sample *sample, 674 struct perf_sample *sample,
691 struct perf_session *session) 675 struct perf_session *session)
692{ 676{
677 struct symbol *parent = NULL;
693 u64 ip = event->ip.ip; 678 u64 ip = event->ip.ip;
694 struct sym_entry *syme;
695 struct addr_location al; 679 struct addr_location al;
696 struct machine *machine; 680 struct machine *machine;
681 int err;
697 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 682 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
698 683
699 ++top.samples; 684 ++top.samples;
@@ -782,46 +767,41 @@ static void perf_event__process_sample(const union perf_event *event,
782 sleep(5); 767 sleep(5);
783 vmlinux_warned = true; 768 vmlinux_warned = true;
784 } 769 }
785
786 return;
787 }
788
789 /* let's see, whether we need to install initial sym_filter_entry */
790 if (sym_filter_entry_sched) {
791 top.sym_filter_entry = sym_filter_entry_sched;
792 sym_filter_entry_sched = NULL;
793 if (parse_source(top.sym_filter_entry) < 0) {
794 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
795
796 pr_err("Can't annotate %s", sym->name);
797 if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) {
798 pr_err(": No vmlinux file was found in the path:\n");
799 machine__fprintf_vmlinux_path(machine, stderr);
800 } else
801 pr_err(".\n");
802 exit(1);
803 }
804 } 770 }
805 771
806 syme = symbol__priv(al.sym); 772 if (al.sym == NULL || !al.sym->ignore) {
807 if (!al.sym->ignore) {
808 struct perf_evsel *evsel; 773 struct perf_evsel *evsel;
774 struct hist_entry *he;
809 775
810 evsel = perf_evlist__id2evsel(top.evlist, sample->id); 776 evsel = perf_evlist__id2evsel(top.evlist, sample->id);
811 assert(evsel != NULL); 777 assert(evsel != NULL);
812 syme->count[evsel->idx]++; 778
813 record_precise_ip(syme, evsel->idx, ip); 779 if ((sort__has_parent || symbol_conf.use_callchain) &&
814 pthread_mutex_lock(&top.active_symbols_lock); 780 sample->callchain) {
815 if (list_empty(&syme->node) || !syme->node.next) { 781 err = perf_session__resolve_callchain(session, al.thread,
816 static bool first = true; 782 sample->callchain, &parent);
817 __list_insert_active_sym(syme); 783 if (err)
818 if (first) { 784 return;
819 pthread_cond_broadcast(&top.active_symbols_cond);
820 first = false;
821 }
822 } 785 }
823 pthread_mutex_unlock(&top.active_symbols_lock); 786
787 he = perf_session__add_hist_entry(session, &al, sample, evsel);
788 if (he == NULL) {
789 pr_err("Problem incrementing symbol period, skipping event\n");
790 return;
791 }
792
793 if (symbol_conf.use_callchain) {
794 err = callchain_append(he->callchain, &session->callchain_cursor,
795 sample->period);
796 if (err)
797 return;
798 }
799
800 if (sort_has_symbols)
801 record_precise_ip(he, evsel->idx, ip);
824 } 802 }
803
804 return;
825} 805}
826 806
827static void perf_session__mmap_read_idx(struct perf_session *self, int idx) 807static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
@@ -872,7 +852,11 @@ static void start_counters(struct perf_evlist *evlist)
872 attr->read_format |= PERF_FORMAT_ID; 852 attr->read_format |= PERF_FORMAT_ID;
873 } 853 }
874 854
855 if (symbol_conf.use_callchain)
856 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
857
875 attr->mmap = 1; 858 attr->mmap = 1;
859 attr->comm = 1;
876 attr->inherit = inherit; 860 attr->inherit = inherit;
877try_again: 861try_again:
878 if (perf_evsel__open(counter, top.evlist->cpus, 862 if (perf_evsel__open(counter, top.evlist->cpus,
@@ -927,35 +911,56 @@ out_err:
927 exit(0); 911 exit(0);
928} 912}
929 913
914static int setup_sample_type(void)
915{
916 if (!sort_has_symbols) {
917 if (symbol_conf.use_callchain) {
918 ui__warning("Selected -g but \"sym\" not present in --sort/-s.");
919 return -EINVAL;
920 }
921 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
922 if (callchain_register_param(&callchain_param) < 0) {
923 ui__warning("Can't register callchain params.\n");
924 return -EINVAL;
925 }
926 }
927
928 return 0;
929}
930
930static int __cmd_top(void) 931static int __cmd_top(void)
931{ 932{
932 pthread_t thread; 933 pthread_t thread;
933 int ret __used; 934 int ret;
934 /* 935 /*
935 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 936 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
936 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 937 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
937 */ 938 */
938 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL); 939 top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
939 if (session == NULL) 940 if (top.session == NULL)
940 return -ENOMEM; 941 return -ENOMEM;
941 942
943 ret = setup_sample_type();
944 if (ret)
945 goto out_delete;
946
942 if (top.target_tid != -1) 947 if (top.target_tid != -1)
943 perf_event__synthesize_thread_map(top.evlist->threads, 948 perf_event__synthesize_thread_map(top.evlist->threads,
944 perf_event__process, session); 949 perf_event__process, top.session);
945 else 950 else
946 perf_event__synthesize_threads(perf_event__process, session); 951 perf_event__synthesize_threads(perf_event__process, top.session);
947 952
948 start_counters(top.evlist); 953 start_counters(top.evlist);
949 session->evlist = top.evlist; 954 top.session->evlist = top.evlist;
950 perf_session__update_sample_type(session); 955 perf_session__update_sample_type(top.session);
951 956
952 /* Wait for a minimal set of events before starting the snapshot */ 957 /* Wait for a minimal set of events before starting the snapshot */
953 poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 958 poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
954 959
955 perf_session__mmap_read(session); 960 perf_session__mmap_read(top.session);
956 961
957 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 962 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
958 display_thread), session)) { 963 display_thread), NULL)) {
959 printf("Could not create display thread.\n"); 964 printf("Could not create display thread.\n");
960 exit(-1); 965 exit(-1);
961 } 966 }
@@ -973,12 +978,96 @@ static int __cmd_top(void)
973 while (1) { 978 while (1) {
974 u64 hits = top.samples; 979 u64 hits = top.samples;
975 980
976 perf_session__mmap_read(session); 981 perf_session__mmap_read(top.session);
977 982
978 if (hits == top.samples) 983 if (hits == top.samples)
979 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 984 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
980 } 985 }
981 986
987out_delete:
988 perf_session__delete(top.session);
989 top.session = NULL;
990
991 return 0;
992}
993
994static int
995parse_callchain_opt(const struct option *opt __used, const char *arg,
996 int unset)
997{
998 char *tok, *tok2;
999 char *endptr;
1000
1001 /*
1002 * --no-call-graph
1003 */
1004 if (unset) {
1005 dont_use_callchains = true;
1006 return 0;
1007 }
1008
1009 symbol_conf.use_callchain = true;
1010
1011 if (!arg)
1012 return 0;
1013
1014 tok = strtok((char *)arg, ",");
1015 if (!tok)
1016 return -1;
1017
1018 /* get the output mode */
1019 if (!strncmp(tok, "graph", strlen(arg)))
1020 callchain_param.mode = CHAIN_GRAPH_ABS;
1021
1022 else if (!strncmp(tok, "flat", strlen(arg)))
1023 callchain_param.mode = CHAIN_FLAT;
1024
1025 else if (!strncmp(tok, "fractal", strlen(arg)))
1026 callchain_param.mode = CHAIN_GRAPH_REL;
1027
1028 else if (!strncmp(tok, "none", strlen(arg))) {
1029 callchain_param.mode = CHAIN_NONE;
1030 symbol_conf.use_callchain = false;
1031
1032 return 0;
1033 }
1034
1035 else
1036 return -1;
1037
1038 /* get the min percentage */
1039 tok = strtok(NULL, ",");
1040 if (!tok)
1041 goto setup;
1042
1043 callchain_param.min_percent = strtod(tok, &endptr);
1044 if (tok == endptr)
1045 return -1;
1046
1047 /* get the print limit */
1048 tok2 = strtok(NULL, ",");
1049 if (!tok2)
1050 goto setup;
1051
1052 if (tok2[0] != 'c') {
1053 callchain_param.print_limit = strtod(tok2, &endptr);
1054 tok2 = strtok(NULL, ",");
1055 if (!tok2)
1056 goto setup;
1057 }
1058
1059 /* get the call chain order */
1060 if (!strcmp(tok2, "caller"))
1061 callchain_param.order = ORDER_CALLER;
1062 else if (!strcmp(tok2, "callee"))
1063 callchain_param.order = ORDER_CALLEE;
1064 else
1065 return -1;
1066setup:
1067 if (callchain_register_param(&callchain_param) < 0) {
1068 fprintf(stderr, "Can't register callchain params\n");
1069 return -1;
1070 }
982 return 0; 1071 return 0;
983} 1072}
984 1073
@@ -1018,7 +1107,7 @@ static const struct option options[] = {
1018 "put the counters into a counter group"), 1107 "put the counters into a counter group"),
1019 OPT_BOOLEAN('i', "inherit", &inherit, 1108 OPT_BOOLEAN('i', "inherit", &inherit,
1020 "child tasks inherit counters"), 1109 "child tasks inherit counters"),
1021 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1110 OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name",
1022 "symbol to annotate"), 1111 "symbol to annotate"),
1023 OPT_BOOLEAN('z', "zero", &top.zero, 1112 OPT_BOOLEAN('z', "zero", &top.zero,
1024 "zero history across updates"), 1113 "zero history across updates"),
@@ -1032,6 +1121,28 @@ static const struct option options[] = {
1032 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 1121 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1033 OPT_INCR('v', "verbose", &verbose, 1122 OPT_INCR('v', "verbose", &verbose,
1034 "be more verbose (show counter open errors, etc)"), 1123 "be more verbose (show counter open errors, etc)"),
1124 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1125 "sort by key(s): pid, comm, dso, symbol, parent"),
1126 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1127 "Show a column with the number of samples"),
1128 OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order",
1129 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
1130 "Default: fractal,0.5,callee", &parse_callchain_opt,
1131 callchain_default_opt),
1132 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1133 "Show a column with the sum of periods"),
1134 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1135 "only consider symbols in these dsos"),
1136 OPT_STRING(0, "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1137 "only consider symbols in these comms"),
1138 OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1139 "only consider these symbols"),
1140 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
1141 "Interleave source code with assembly code (default)"),
1142 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
1143 "Display raw encoding of assembly instructions (default)"),
1144 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1145 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1035 OPT_END() 1146 OPT_END()
1036}; 1147};
1037 1148
@@ -1044,18 +1155,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1044 if (top.evlist == NULL) 1155 if (top.evlist == NULL)
1045 return -ENOMEM; 1156 return -ENOMEM;
1046 1157
1047 page_size = sysconf(_SC_PAGE_SIZE); 1158 symbol_conf.exclude_other = false;
1048 1159
1049 argc = parse_options(argc, argv, options, top_usage, 0); 1160 argc = parse_options(argc, argv, options, top_usage, 0);
1050 if (argc) 1161 if (argc)
1051 usage_with_options(top_usage, options); 1162 usage_with_options(top_usage, options);
1052 1163
1053 /* 1164 if (sort_order == default_sort_order)
1054 * XXX For now start disabled, only using TUI if explicitely asked for. 1165 sort_order = "dso,symbol";
1055 * Change that when handle_keys equivalent gets written, live annotation 1166
1056 * done, etc. 1167 setup_sorting(top_usage, options);
1057 */
1058 use_browser = 0;
1059 1168
1060 if (use_stdio) 1169 if (use_stdio)
1061 use_browser = 0; 1170 use_browser = 0;
@@ -1118,13 +1227,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1118 1227
1119 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 1228 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1120 1229
1121 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) + 1230 symbol_conf.priv_size = sizeof(struct annotation);
1122 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1123 1231
1124 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1232 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1125 if (symbol__init() < 0) 1233 if (symbol__init() < 0)
1126 return -1; 1234 return -1;
1127 1235
1236 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
1237 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1238 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1239
1240 /*
1241 * Avoid annotation data structures overhead when symbols aren't on the
1242 * sort list.
1243 */
1244 sort_has_symbols = sort_sym.list.next != NULL;
1245
1128 get_term_dimensions(&winsize); 1246 get_term_dimensions(&winsize);
1129 if (top.print_entries == 0) { 1247 if (top.print_entries == 0) {
1130 update_print_entries(&winsize); 1248 update_print_entries(&winsize);
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 4702e2443a8e..b382bd551aac 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -4,7 +4,6 @@
4#include "util/util.h" 4#include "util/util.h"
5#include "util/strbuf.h" 5#include "util/strbuf.h"
6 6
7extern const char perf_version_string[];
8extern const char perf_usage_string[]; 7extern const char perf_usage_string[];
9extern const char perf_more_info_string[]; 8extern const char perf_more_info_string[];
10 9
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index ec635b7cc8ea..73d0cac8b67e 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -427,6 +427,24 @@ static void get_debugfs_mntpt(void)
427 debugfs_mntpt[0] = '\0'; 427 debugfs_mntpt[0] = '\0';
428} 428}
429 429
430static void pthread__block_sigwinch(void)
431{
432 sigset_t set;
433
434 sigemptyset(&set);
435 sigaddset(&set, SIGWINCH);
436 pthread_sigmask(SIG_BLOCK, &set, NULL);
437}
438
439void pthread__unblock_sigwinch(void)
440{
441 sigset_t set;
442
443 sigemptyset(&set);
444 sigaddset(&set, SIGWINCH);
445 pthread_sigmask(SIG_UNBLOCK, &set, NULL);
446}
447
430int main(int argc, const char **argv) 448int main(int argc, const char **argv)
431{ 449{
432 const char *cmd; 450 const char *cmd;
@@ -480,6 +498,12 @@ int main(int argc, const char **argv)
480 * time. 498 * time.
481 */ 499 */
482 setup_path(); 500 setup_path();
501 /*
502 * Block SIGWINCH notifications so that the thread that wants it can
503 * unblock and get syscalls like select interrupted instead of waiting
504 * forever while the signal goes to some other non interested thread.
505 */
506 pthread__block_sigwinch();
483 507
484 while (1) { 508 while (1) {
485 static int done_help; 509 static int done_help;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index a5fc660c1f12..914c895510f7 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -9,18 +9,21 @@ void get_term_dimensions(struct winsize *ws);
9#include "../../arch/x86/include/asm/unistd.h" 9#include "../../arch/x86/include/asm/unistd.h"
10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") 10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
11#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 11#define cpu_relax() asm volatile("rep; nop" ::: "memory");
12#define CPUINFO_PROC "model name"
12#endif 13#endif
13 14
14#if defined(__x86_64__) 15#if defined(__x86_64__)
15#include "../../arch/x86/include/asm/unistd.h" 16#include "../../arch/x86/include/asm/unistd.h"
16#define rmb() asm volatile("lfence" ::: "memory") 17#define rmb() asm volatile("lfence" ::: "memory")
17#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 18#define cpu_relax() asm volatile("rep; nop" ::: "memory");
19#define CPUINFO_PROC "model name"
18#endif 20#endif
19 21
20#ifdef __powerpc__ 22#ifdef __powerpc__
21#include "../../arch/powerpc/include/asm/unistd.h" 23#include "../../arch/powerpc/include/asm/unistd.h"
22#define rmb() asm volatile ("sync" ::: "memory") 24#define rmb() asm volatile ("sync" ::: "memory")
23#define cpu_relax() asm volatile ("" ::: "memory"); 25#define cpu_relax() asm volatile ("" ::: "memory");
26#define CPUINFO_PROC "cpu"
24#endif 27#endif
25 28
26#ifdef __s390__ 29#ifdef __s390__
@@ -37,30 +40,35 @@ void get_term_dimensions(struct winsize *ws);
37# define rmb() asm volatile("" ::: "memory") 40# define rmb() asm volatile("" ::: "memory")
38#endif 41#endif
39#define cpu_relax() asm volatile("" ::: "memory") 42#define cpu_relax() asm volatile("" ::: "memory")
43#define CPUINFO_PROC "cpu type"
40#endif 44#endif
41 45
42#ifdef __hppa__ 46#ifdef __hppa__
43#include "../../arch/parisc/include/asm/unistd.h" 47#include "../../arch/parisc/include/asm/unistd.h"
44#define rmb() asm volatile("" ::: "memory") 48#define rmb() asm volatile("" ::: "memory")
45#define cpu_relax() asm volatile("" ::: "memory"); 49#define cpu_relax() asm volatile("" ::: "memory");
50#define CPUINFO_PROC "cpu"
46#endif 51#endif
47 52
48#ifdef __sparc__ 53#ifdef __sparc__
49#include "../../arch/sparc/include/asm/unistd.h" 54#include "../../arch/sparc/include/asm/unistd.h"
50#define rmb() asm volatile("":::"memory") 55#define rmb() asm volatile("":::"memory")
51#define cpu_relax() asm volatile("":::"memory") 56#define cpu_relax() asm volatile("":::"memory")
57#define CPUINFO_PROC "cpu"
52#endif 58#endif
53 59
54#ifdef __alpha__ 60#ifdef __alpha__
55#include "../../arch/alpha/include/asm/unistd.h" 61#include "../../arch/alpha/include/asm/unistd.h"
56#define rmb() asm volatile("mb" ::: "memory") 62#define rmb() asm volatile("mb" ::: "memory")
57#define cpu_relax() asm volatile("" ::: "memory") 63#define cpu_relax() asm volatile("" ::: "memory")
64#define CPUINFO_PROC "cpu model"
58#endif 65#endif
59 66
60#ifdef __ia64__ 67#ifdef __ia64__
61#include "../../arch/ia64/include/asm/unistd.h" 68#include "../../arch/ia64/include/asm/unistd.h"
62#define rmb() asm volatile ("mf" ::: "memory") 69#define rmb() asm volatile ("mf" ::: "memory")
63#define cpu_relax() asm volatile ("hint @pause" ::: "memory") 70#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
71#define CPUINFO_PROC "model name"
64#endif 72#endif
65 73
66#ifdef __arm__ 74#ifdef __arm__
@@ -71,6 +79,7 @@ void get_term_dimensions(struct winsize *ws);
71 */ 79 */
72#define rmb() ((void(*)(void))0xffff0fa0)() 80#define rmb() ((void(*)(void))0xffff0fa0)()
73#define cpu_relax() asm volatile("":::"memory") 81#define cpu_relax() asm volatile("":::"memory")
82#define CPUINFO_PROC "Processor"
74#endif 83#endif
75 84
76#ifdef __mips__ 85#ifdef __mips__
@@ -83,6 +92,7 @@ void get_term_dimensions(struct winsize *ws);
83 : /* no input */ \ 92 : /* no input */ \
84 : "memory") 93 : "memory")
85#define cpu_relax() asm volatile("" ::: "memory") 94#define cpu_relax() asm volatile("" ::: "memory")
95#define CPUINFO_PROC "cpu model"
86#endif 96#endif
87 97
88#include <time.h> 98#include <time.h>
@@ -171,5 +181,8 @@ struct ip_callchain {
171}; 181};
172 182
173extern bool perf_host, perf_guest; 183extern bool perf_host, perf_guest;
184extern const char perf_version_string[];
185
186void pthread__unblock_sigwinch(void);
174 187
175#endif 188#endif
diff --git a/tools/perf/scripts/python/bin/net_dropmonitor-record b/tools/perf/scripts/python/bin/net_dropmonitor-record
new file mode 100755
index 000000000000..423fb81dadae
--- /dev/null
+++ b/tools/perf/scripts/python/bin/net_dropmonitor-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e skb:kfree_skb $@
diff --git a/tools/perf/scripts/python/bin/net_dropmonitor-report b/tools/perf/scripts/python/bin/net_dropmonitor-report
new file mode 100755
index 000000000000..8d698f5a06aa
--- /dev/null
+++ b/tools/perf/scripts/python/bin/net_dropmonitor-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: display a table of dropped frames
3
4perf script -s "$PERF_EXEC_PATH"/scripts/python/net_dropmonitor.py $@
diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py
new file mode 100755
index 000000000000..a4ffc9500023
--- /dev/null
+++ b/tools/perf/scripts/python/net_dropmonitor.py
@@ -0,0 +1,72 @@
1# Monitor the system for dropped packets and proudce a report of drop locations and counts
2
3import os
4import sys
5
6sys.path.append(os.environ['PERF_EXEC_PATH'] + \
7 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
8
9from perf_trace_context import *
10from Core import *
11from Util import *
12
13drop_log = {}
14kallsyms = []
15
16def get_kallsyms_table():
17 global kallsyms
18 try:
19 f = open("/proc/kallsyms", "r")
20 linecount = 0
21 for line in f:
22 linecount = linecount+1
23 f.seek(0)
24 except:
25 return
26
27
28 j = 0
29 for line in f:
30 loc = int(line.split()[0], 16)
31 name = line.split()[2]
32 j = j +1
33 if ((j % 100) == 0):
34 print "\r" + str(j) + "/" + str(linecount),
35 kallsyms.append({ 'loc': loc, 'name' : name})
36
37 print "\r" + str(j) + "/" + str(linecount)
38 kallsyms.sort()
39 return
40
41def get_sym(sloc):
42 loc = int(sloc)
43 for i in kallsyms:
44 if (i['loc'] >= loc):
45 return (i['name'], i['loc']-loc)
46 return (None, 0)
47
48def print_drop_table():
49 print "%25s %25s %25s" % ("LOCATION", "OFFSET", "COUNT")
50 for i in drop_log.keys():
51 (sym, off) = get_sym(i)
52 if sym == None:
53 sym = i
54 print "%25s %25s %25s" % (sym, off, drop_log[i])
55
56
57def trace_begin():
58 print "Starting trace (Ctrl-C to dump results)"
59
60def trace_end():
61 print "Gathering kallsyms data"
62 get_kallsyms_table()
63 print_drop_table()
64
65# called from perf, when it finds a correspoinding event
66def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm,
67 skbaddr, protocol, location):
68 slocation = str(location)
69 try:
70 drop_log[slocation] = drop_log[slocation] + 1
71 except:
72 drop_log[slocation] = 1
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index e01af2b1a469..bc8f4773d4d8 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -16,6 +16,8 @@
16#include "annotate.h" 16#include "annotate.h"
17#include <pthread.h> 17#include <pthread.h>
18 18
19const char *disassembler_style;
20
19int symbol__annotate_init(struct map *map __used, struct symbol *sym) 21int symbol__annotate_init(struct map *map __used, struct symbol *sym)
20{ 22{
21 struct annotation *notes = symbol__annotation(sym); 23 struct annotation *notes = symbol__annotation(sym);
@@ -323,10 +325,15 @@ fallback:
323 dso, dso->long_name, sym, sym->name); 325 dso, dso->long_name, sym, sym->name);
324 326
325 snprintf(command, sizeof(command), 327 snprintf(command, sizeof(command),
326 "objdump --start-address=0x%016" PRIx64 328 "objdump %s%s --start-address=0x%016" PRIx64
327 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand", 329 " --stop-address=0x%016" PRIx64
330 " -d %s %s -C %s|grep -v %s|expand",
331 disassembler_style ? "-M " : "",
332 disassembler_style ? disassembler_style : "",
328 map__rip_2objdump(map, sym->start), 333 map__rip_2objdump(map, sym->start),
329 map__rip_2objdump(map, sym->end), 334 map__rip_2objdump(map, sym->end),
335 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
336 symbol_conf.annotate_src ? "-S" : "",
330 symfs_filename, filename); 337 symfs_filename, filename);
331 338
332 pr_debug("Executing: %s\n", command); 339 pr_debug("Executing: %s\n", command);
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index c2c286896801..d9072523d342 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -91,13 +91,18 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
91#ifdef NO_NEWT_SUPPORT 91#ifdef NO_NEWT_SUPPORT
92static inline int symbol__tui_annotate(struct symbol *sym __used, 92static inline int symbol__tui_annotate(struct symbol *sym __used,
93 struct map *map __used, 93 struct map *map __used,
94 int evidx __used, int refresh __used) 94 int evidx __used,
95 void(*timer)(void *arg) __used,
96 void *arg __used, int delay_secs __used)
95{ 97{
96 return 0; 98 return 0;
97} 99}
98#else 100#else
99int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 101int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
100 int refresh); 102 int nr_events, void(*timer)(void *arg), void *arg,
103 int delay_secs);
101#endif 104#endif
102 105
106extern const char *disassembler_style;
107
103#endif /* __PERF_ANNOTATE_H */ 108#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index e191eb9a667f..521c38a79190 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -200,7 +200,7 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
200 * Auto-detect: 200 * Auto-detect:
201 */ 201 */
202 if (perf_use_color_default < 0) { 202 if (perf_use_color_default < 0) {
203 if (isatty(1) || pager_in_use()) 203 if (isatty(fileno(fp)) || pager_in_use())
204 perf_use_color_default = 1; 204 perf_use_color_default = 1;
205 else 205 else
206 perf_use_color_default = 0; 206 perf_use_color_default = 0;
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index e02d78cae70f..80d9598db31a 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -341,7 +341,7 @@ const char *perf_config_dirname(const char *name, const char *value)
341 341
342static int perf_default_core_config(const char *var __used, const char *value __used) 342static int perf_default_core_config(const char *var __used, const char *value __used)
343{ 343{
344 /* Add other config variables here and to Documentation/config.txt. */ 344 /* Add other config variables here. */
345 return 0; 345 return 0;
346} 346}
347 347
@@ -350,7 +350,7 @@ int perf_default_config(const char *var, const char *value, void *dummy __used)
350 if (!prefixcmp(var, "core.")) 350 if (!prefixcmp(var, "core."))
351 return perf_default_core_config(var, value); 351 return perf_default_core_config(var, value);
352 352
353 /* Add other config variables here and to Documentation/config.txt. */ 353 /* Add other config variables here. */
354 return 0; 354 return 0;
355} 355}
356 356
@@ -399,7 +399,6 @@ static int perf_config_global(void)
399int perf_config(config_fn_t fn, void *data) 399int perf_config(config_fn_t fn, void *data)
400{ 400{
401 int ret = 0, found = 0; 401 int ret = 0, found = 0;
402 char *repo_config = NULL;
403 const char *home = NULL; 402 const char *home = NULL;
404 403
405 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 404 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
@@ -414,19 +413,32 @@ int perf_config(config_fn_t fn, void *data)
414 home = getenv("HOME"); 413 home = getenv("HOME");
415 if (perf_config_global() && home) { 414 if (perf_config_global() && home) {
416 char *user_config = strdup(mkpath("%s/.perfconfig", home)); 415 char *user_config = strdup(mkpath("%s/.perfconfig", home));
417 if (!access(user_config, R_OK)) { 416 struct stat st;
418 ret += perf_config_from_file(fn, user_config, data); 417
419 found += 1; 418 if (user_config == NULL) {
419 warning("Not enough memory to process %s/.perfconfig, "
420 "ignoring it.", home);
421 goto out;
420 } 422 }
421 free(user_config);
422 }
423 423
424 repo_config = perf_pathdup("config"); 424 if (stat(user_config, &st) < 0)
425 if (!access(repo_config, R_OK)) { 425 goto out_free;
426 ret += perf_config_from_file(fn, repo_config, data); 426
427 if (st.st_uid && (st.st_uid != geteuid())) {
428 warning("File %s not owned by current user or root, "
429 "ignoring it.", user_config);
430 goto out_free;
431 }
432
433 if (!st.st_size)
434 goto out_free;
435
436 ret += perf_config_from_file(fn, user_config, data);
427 found += 1; 437 found += 1;
438out_free:
439 free(user_config);
428 } 440 }
429 free(repo_config); 441out:
430 if (found == 0) 442 if (found == 0)
431 return -1; 443 return -1;
432 return ret; 444 return ret;
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index fddf40f30d3e..ee51e9b4dc09 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -96,6 +96,39 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr,
96 return *lineno ?: -ENOENT; 96 return *lineno ?: -ENOENT;
97} 97}
98 98
99static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data);
100
101/**
102 * cu_walk_functions_at - Walk on function DIEs at given address
103 * @cu_die: A CU DIE
104 * @addr: An address
105 * @callback: A callback which called with found DIEs
106 * @data: A user data
107 *
108 * Walk on function DIEs at given @addr in @cu_die. Passed DIEs
109 * should be subprogram or inlined-subroutines.
110 */
111int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
112 int (*callback)(Dwarf_Die *, void *), void *data)
113{
114 Dwarf_Die die_mem;
115 Dwarf_Die *sc_die;
116 int ret = -ENOENT;
117
118 /* Inlined function could be recursive. Trace it until fail */
119 for (sc_die = die_find_realfunc(cu_die, addr, &die_mem);
120 sc_die != NULL;
121 sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr,
122 &die_mem)) {
123 ret = callback(sc_die, data);
124 if (ret)
125 break;
126 }
127
128 return ret;
129
130}
131
99/** 132/**
100 * die_compare_name - Compare diename and tname 133 * die_compare_name - Compare diename and tname
101 * @dw_die: a DIE 134 * @dw_die: a DIE
@@ -198,6 +231,19 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
198 return 0; 231 return 0;
199} 232}
200 233
234/* Get attribute and translate it as a sdata */
235static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name,
236 Dwarf_Sword *result)
237{
238 Dwarf_Attribute attr;
239
240 if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
241 dwarf_formsdata(&attr, result) != 0)
242 return -ENOENT;
243
244 return 0;
245}
246
201/** 247/**
202 * die_is_signed_type - Check whether a type DIE is signed or not 248 * die_is_signed_type - Check whether a type DIE is signed or not
203 * @tp_die: a DIE of a type 249 * @tp_die: a DIE of a type
@@ -250,6 +296,50 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
250 return 0; 296 return 0;
251} 297}
252 298
299/* Get the call file index number in CU DIE */
300static int die_get_call_fileno(Dwarf_Die *in_die)
301{
302 Dwarf_Sword idx;
303
304 if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0)
305 return (int)idx;
306 else
307 return -ENOENT;
308}
309
310/* Get the declared file index number in CU DIE */
311static int die_get_decl_fileno(Dwarf_Die *pdie)
312{
313 Dwarf_Sword idx;
314
315 if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0)
316 return (int)idx;
317 else
318 return -ENOENT;
319}
320
321/**
322 * die_get_call_file - Get callsite file name of inlined function instance
323 * @in_die: a DIE of an inlined function instance
324 *
325 * Get call-site file name of @in_die. This means from which file the inline
326 * function is called.
327 */
328const char *die_get_call_file(Dwarf_Die *in_die)
329{
330 Dwarf_Die cu_die;
331 Dwarf_Files *files;
332 int idx;
333
334 idx = die_get_call_fileno(in_die);
335 if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) ||
336 dwarf_getsrcfiles(&cu_die, &files, NULL) != 0)
337 return NULL;
338
339 return dwarf_filesrc(files, idx, NULL, NULL);
340}
341
342
253/** 343/**
254 * die_find_child - Generic DIE search function in DIE tree 344 * die_find_child - Generic DIE search function in DIE tree
255 * @rt_die: a root DIE 345 * @rt_die: a root DIE
@@ -374,9 +464,78 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
374 return die_mem; 464 return die_mem;
375} 465}
376 466
467struct __instance_walk_param {
468 void *addr;
469 int (*callback)(Dwarf_Die *, void *);
470 void *data;
471 int retval;
472};
473
474static int __die_walk_instances_cb(Dwarf_Die *inst, void *data)
475{
476 struct __instance_walk_param *iwp = data;
477 Dwarf_Attribute attr_mem;
478 Dwarf_Die origin_mem;
479 Dwarf_Attribute *attr;
480 Dwarf_Die *origin;
481 int tmp;
482
483 attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem);
484 if (attr == NULL)
485 return DIE_FIND_CB_CONTINUE;
486
487 origin = dwarf_formref_die(attr, &origin_mem);
488 if (origin == NULL || origin->addr != iwp->addr)
489 return DIE_FIND_CB_CONTINUE;
490
491 /* Ignore redundant instances */
492 if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) {
493 dwarf_decl_line(origin, &tmp);
494 if (die_get_call_lineno(inst) == tmp) {
495 tmp = die_get_decl_fileno(origin);
496 if (die_get_call_fileno(inst) == tmp)
497 return DIE_FIND_CB_CONTINUE;
498 }
499 }
500
501 iwp->retval = iwp->callback(inst, iwp->data);
502
503 return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE;
504}
505
506/**
507 * die_walk_instances - Walk on instances of given DIE
508 * @or_die: an abstract original DIE
509 * @callback: a callback function which is called with instance DIE
510 * @data: user data
511 *
512 * Walk on the instances of give @in_die. @in_die must be an inlined function
513 * declartion. This returns the return value of @callback if it returns
514 * non-zero value, or -ENOENT if there is no instance.
515 */
516int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *),
517 void *data)
518{
519 Dwarf_Die cu_die;
520 Dwarf_Die die_mem;
521 struct __instance_walk_param iwp = {
522 .addr = or_die->addr,
523 .callback = callback,
524 .data = data,
525 .retval = -ENOENT,
526 };
527
528 if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL)
529 return -ENOENT;
530
531 die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem);
532
533 return iwp.retval;
534}
535
377/* Line walker internal parameters */ 536/* Line walker internal parameters */
378struct __line_walk_param { 537struct __line_walk_param {
379 const char *fname; 538 bool recursive;
380 line_walk_callback_t callback; 539 line_walk_callback_t callback;
381 void *data; 540 void *data;
382 int retval; 541 int retval;
@@ -385,39 +544,56 @@ struct __line_walk_param {
385static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) 544static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
386{ 545{
387 struct __line_walk_param *lw = data; 546 struct __line_walk_param *lw = data;
388 Dwarf_Addr addr; 547 Dwarf_Addr addr = 0;
548 const char *fname;
389 int lineno; 549 int lineno;
390 550
391 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { 551 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
552 fname = die_get_call_file(in_die);
392 lineno = die_get_call_lineno(in_die); 553 lineno = die_get_call_lineno(in_die);
393 if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { 554 if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
394 lw->retval = lw->callback(lw->fname, lineno, addr, 555 lw->retval = lw->callback(fname, lineno, addr, lw->data);
395 lw->data);
396 if (lw->retval != 0) 556 if (lw->retval != 0)
397 return DIE_FIND_CB_END; 557 return DIE_FIND_CB_END;
398 } 558 }
399 } 559 }
400 return DIE_FIND_CB_SIBLING; 560 if (!lw->recursive)
561 /* Don't need to search recursively */
562 return DIE_FIND_CB_SIBLING;
563
564 if (addr) {
565 fname = dwarf_decl_file(in_die);
566 if (fname && dwarf_decl_line(in_die, &lineno) == 0) {
567 lw->retval = lw->callback(fname, lineno, addr, lw->data);
568 if (lw->retval != 0)
569 return DIE_FIND_CB_END;
570 }
571 }
572
573 /* Continue to search nested inlined function call-sites */
574 return DIE_FIND_CB_CONTINUE;
401} 575}
402 576
403/* Walk on lines of blocks included in given DIE */ 577/* Walk on lines of blocks included in given DIE */
404static int __die_walk_funclines(Dwarf_Die *sp_die, 578static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive,
405 line_walk_callback_t callback, void *data) 579 line_walk_callback_t callback, void *data)
406{ 580{
407 struct __line_walk_param lw = { 581 struct __line_walk_param lw = {
582 .recursive = recursive,
408 .callback = callback, 583 .callback = callback,
409 .data = data, 584 .data = data,
410 .retval = 0, 585 .retval = 0,
411 }; 586 };
412 Dwarf_Die die_mem; 587 Dwarf_Die die_mem;
413 Dwarf_Addr addr; 588 Dwarf_Addr addr;
589 const char *fname;
414 int lineno; 590 int lineno;
415 591
416 /* Handle function declaration line */ 592 /* Handle function declaration line */
417 lw.fname = dwarf_decl_file(sp_die); 593 fname = dwarf_decl_file(sp_die);
418 if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && 594 if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
419 dwarf_entrypc(sp_die, &addr) == 0) { 595 dwarf_entrypc(sp_die, &addr) == 0) {
420 lw.retval = callback(lw.fname, lineno, addr, data); 596 lw.retval = callback(fname, lineno, addr, data);
421 if (lw.retval != 0) 597 if (lw.retval != 0)
422 goto done; 598 goto done;
423 } 599 }
@@ -430,7 +606,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
430{ 606{
431 struct __line_walk_param *lw = data; 607 struct __line_walk_param *lw = data;
432 608
433 lw->retval = __die_walk_funclines(sp_die, lw->callback, lw->data); 609 lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data);
434 if (lw->retval != 0) 610 if (lw->retval != 0)
435 return DWARF_CB_ABORT; 611 return DWARF_CB_ABORT;
436 612
@@ -439,7 +615,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
439 615
440/** 616/**
441 * die_walk_lines - Walk on lines inside given DIE 617 * die_walk_lines - Walk on lines inside given DIE
442 * @rt_die: a root DIE (CU or subprogram) 618 * @rt_die: a root DIE (CU, subprogram or inlined_subroutine)
443 * @callback: callback routine 619 * @callback: callback routine
444 * @data: user data 620 * @data: user data
445 * 621 *
@@ -460,12 +636,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
460 size_t nlines, i; 636 size_t nlines, i;
461 637
462 /* Get the CU die */ 638 /* Get the CU die */
463 if (dwarf_tag(rt_die) == DW_TAG_subprogram) 639 if (dwarf_tag(rt_die) != DW_TAG_compile_unit)
464 cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); 640 cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL);
465 else 641 else
466 cu_die = rt_die; 642 cu_die = rt_die;
467 if (!cu_die) { 643 if (!cu_die) {
468 pr_debug2("Failed to get CU from subprogram\n"); 644 pr_debug2("Failed to get CU from given DIE.\n");
469 return -EINVAL; 645 return -EINVAL;
470 } 646 }
471 647
@@ -509,7 +685,11 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
509 * subroutines. We have to check functions list or given function. 685 * subroutines. We have to check functions list or given function.
510 */ 686 */
511 if (rt_die != cu_die) 687 if (rt_die != cu_die)
512 ret = __die_walk_funclines(rt_die, callback, data); 688 /*
689 * Don't need walk functions recursively, because nested
690 * inlined functions don't have lines of the specified DIE.
691 */
692 ret = __die_walk_funclines(rt_die, false, callback, data);
513 else { 693 else {
514 struct __line_walk_param param = { 694 struct __line_walk_param param = {
515 .callback = callback, 695 .callback = callback,
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index bc3b21167e70..6ce1717784b7 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -34,12 +34,19 @@ extern const char *cu_get_comp_dir(Dwarf_Die *cu_die);
34extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, 34extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
35 const char **fname, int *lineno); 35 const char **fname, int *lineno);
36 36
37/* Walk on funcitons at given address */
38extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
39 int (*callback)(Dwarf_Die *, void *), void *data);
40
37/* Compare diename and tname */ 41/* Compare diename and tname */
38extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); 42extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
39 43
40/* Get callsite line number of inline-function instance */ 44/* Get callsite line number of inline-function instance */
41extern int die_get_call_lineno(Dwarf_Die *in_die); 45extern int die_get_call_lineno(Dwarf_Die *in_die);
42 46
47/* Get callsite file name of inlined function instance */
48extern const char *die_get_call_file(Dwarf_Die *in_die);
49
43/* Get type die */ 50/* Get type die */
44extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); 51extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
45 52
@@ -73,6 +80,10 @@ extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
73extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 80extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
74 Dwarf_Die *die_mem); 81 Dwarf_Die *die_mem);
75 82
83/* Walk on the instances of given DIE */
84extern int die_walk_instances(Dwarf_Die *in_die,
85 int (*callback)(Dwarf_Die *, void *), void *data);
86
76/* Walker on lines (Note: line number will not be sorted) */ 87/* Walker on lines (Note: line number will not be sorted) */
77typedef int (* line_walk_callback_t) (const char *fname, int lineno, 88typedef int (* line_walk_callback_t) (const char *fname, int lineno,
78 Dwarf_Addr addr, void *data); 89 Dwarf_Addr addr, void *data);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 3c1b8a632101..437f8ca679a0 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -169,12 +169,17 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
169 continue; 169 continue;
170 pbf += n + 3; 170 pbf += n + 3;
171 if (*pbf == 'x') { /* vm_exec */ 171 if (*pbf == 'x') { /* vm_exec */
172 char anonstr[] = "//anon\n";
172 char *execname = strchr(bf, '/'); 173 char *execname = strchr(bf, '/');
173 174
174 /* Catch VDSO */ 175 /* Catch VDSO */
175 if (execname == NULL) 176 if (execname == NULL)
176 execname = strstr(bf, "[vdso]"); 177 execname = strstr(bf, "[vdso]");
177 178
179 /* Catch anonymous mmaps */
180 if ((execname == NULL) && !strstr(bf, "["))
181 execname = anonstr;
182
178 if (execname == NULL) 183 if (execname == NULL)
179 continue; 184 continue;
180 185
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 1d7f66488a88..357a85b85248 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -186,6 +186,6 @@ const char *perf_event__name(unsigned int id);
186 186
187int perf_event__parse_sample(const union perf_event *event, u64 type, 187int perf_event__parse_sample(const union perf_event *event, u64 type,
188 int sample_size, bool sample_id_all, 188 int sample_size, bool sample_id_all,
189 struct perf_sample *sample); 189 struct perf_sample *sample, bool swapped);
190 190
191#endif /* __PERF_RECORD_H */ 191#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index b021ea9265c3..2f6bc89027da 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -85,10 +85,45 @@ int perf_evlist__add_default(struct perf_evlist *evlist)
85 struct perf_evsel *evsel = perf_evsel__new(&attr, 0); 85 struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
86 86
87 if (evsel == NULL) 87 if (evsel == NULL)
88 return -ENOMEM; 88 goto error;
89
90 /* use strdup() because free(evsel) assumes name is allocated */
91 evsel->name = strdup("cycles");
92 if (!evsel->name)
93 goto error_free;
89 94
90 perf_evlist__add(evlist, evsel); 95 perf_evlist__add(evlist, evsel);
91 return 0; 96 return 0;
97error_free:
98 perf_evsel__delete(evsel);
99error:
100 return -ENOMEM;
101}
102
103void perf_evlist__disable(struct perf_evlist *evlist)
104{
105 int cpu, thread;
106 struct perf_evsel *pos;
107
108 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
109 list_for_each_entry(pos, &evlist->entries, node) {
110 for (thread = 0; thread < evlist->threads->nr; thread++)
111 ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE);
112 }
113 }
114}
115
116void perf_evlist__enable(struct perf_evlist *evlist)
117{
118 int cpu, thread;
119 struct perf_evsel *pos;
120
121 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
122 list_for_each_entry(pos, &evlist->entries, node) {
123 for (thread = 0; thread < evlist->threads->nr; thread++)
124 ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE);
125 }
126 }
92} 127}
93 128
94int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 129int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
@@ -498,3 +533,9 @@ bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
498 first = list_entry(evlist->entries.next, struct perf_evsel, node); 533 first = list_entry(evlist->entries.next, struct perf_evsel, node);
499 return first->attr.sample_id_all; 534 return first->attr.sample_id_all;
500} 535}
536
537void perf_evlist__set_selected(struct perf_evlist *evlist,
538 struct perf_evsel *evsel)
539{
540 evlist->selected = evsel;
541}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index b2b862374f37..6be71fc57794 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -25,6 +25,7 @@ struct perf_evlist {
25 struct pollfd *pollfd; 25 struct pollfd *pollfd;
26 struct thread_map *threads; 26 struct thread_map *threads;
27 struct cpu_map *cpus; 27 struct cpu_map *cpus;
28 struct perf_evsel *selected;
28}; 29};
29 30
30struct perf_evsel; 31struct perf_evsel;
@@ -53,6 +54,12 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
53int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); 54int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
54void perf_evlist__munmap(struct perf_evlist *evlist); 55void perf_evlist__munmap(struct perf_evlist *evlist);
55 56
57void perf_evlist__disable(struct perf_evlist *evlist);
58void perf_evlist__enable(struct perf_evlist *evlist);
59
60void perf_evlist__set_selected(struct perf_evlist *evlist,
61 struct perf_evsel *evsel);
62
56static inline void perf_evlist__set_maps(struct perf_evlist *evlist, 63static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
57 struct cpu_map *cpus, 64 struct cpu_map *cpus,
58 struct thread_map *threads) 65 struct thread_map *threads)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index a03a36b7908a..b46f6e4bff3c 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -7,6 +7,8 @@
7 * Released under the GPL v2. (and only v2, not any later version) 7 * Released under the GPL v2. (and only v2, not any later version)
8 */ 8 */
9 9
10#include <byteswap.h>
11#include "asm/bug.h"
10#include "evsel.h" 12#include "evsel.h"
11#include "evlist.h" 13#include "evlist.h"
12#include "util.h" 14#include "util.h"
@@ -37,6 +39,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
37 evsel->idx = idx; 39 evsel->idx = idx;
38 evsel->attr = *attr; 40 evsel->attr = *attr;
39 INIT_LIST_HEAD(&evsel->node); 41 INIT_LIST_HEAD(&evsel->node);
42 hists__init(&evsel->hists);
40} 43}
41 44
42struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 45struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
@@ -342,10 +345,20 @@ static bool sample_overlap(const union perf_event *event,
342 345
343int perf_event__parse_sample(const union perf_event *event, u64 type, 346int perf_event__parse_sample(const union perf_event *event, u64 type,
344 int sample_size, bool sample_id_all, 347 int sample_size, bool sample_id_all,
345 struct perf_sample *data) 348 struct perf_sample *data, bool swapped)
346{ 349{
347 const u64 *array; 350 const u64 *array;
348 351
352 /*
353 * used for cross-endian analysis. See git commit 65014ab3
354 * for why this goofiness is needed.
355 */
356 union {
357 u64 val64;
358 u32 val32[2];
359 } u;
360
361
349 data->cpu = data->pid = data->tid = -1; 362 data->cpu = data->pid = data->tid = -1;
350 data->stream_id = data->id = data->time = -1ULL; 363 data->stream_id = data->id = data->time = -1ULL;
351 364
@@ -366,9 +379,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
366 } 379 }
367 380
368 if (type & PERF_SAMPLE_TID) { 381 if (type & PERF_SAMPLE_TID) {
369 u32 *p = (u32 *)array; 382 u.val64 = *array;
370 data->pid = p[0]; 383 if (swapped) {
371 data->tid = p[1]; 384 /* undo swap of u64, then swap on individual u32s */
385 u.val64 = bswap_64(u.val64);
386 u.val32[0] = bswap_32(u.val32[0]);
387 u.val32[1] = bswap_32(u.val32[1]);
388 }
389
390 data->pid = u.val32[0];
391 data->tid = u.val32[1];
372 array++; 392 array++;
373 } 393 }
374 394
@@ -395,8 +415,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
395 } 415 }
396 416
397 if (type & PERF_SAMPLE_CPU) { 417 if (type & PERF_SAMPLE_CPU) {
398 u32 *p = (u32 *)array; 418
399 data->cpu = *p; 419 u.val64 = *array;
420 if (swapped) {
421 /* undo swap of u64, then swap on individual u32s */
422 u.val64 = bswap_64(u.val64);
423 u.val32[0] = bswap_32(u.val32[0]);
424 }
425
426 data->cpu = u.val32[0];
400 array++; 427 array++;
401 } 428 }
402 429
@@ -423,18 +450,27 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
423 } 450 }
424 451
425 if (type & PERF_SAMPLE_RAW) { 452 if (type & PERF_SAMPLE_RAW) {
426 u32 *p = (u32 *)array; 453 const u64 *pdata;
454
455 u.val64 = *array;
456 if (WARN_ONCE(swapped,
457 "Endianness of raw data not corrected!\n")) {
458 /* undo swap of u64, then swap on individual u32s */
459 u.val64 = bswap_64(u.val64);
460 u.val32[0] = bswap_32(u.val32[0]);
461 u.val32[1] = bswap_32(u.val32[1]);
462 }
427 463
428 if (sample_overlap(event, array, sizeof(u32))) 464 if (sample_overlap(event, array, sizeof(u32)))
429 return -EFAULT; 465 return -EFAULT;
430 466
431 data->raw_size = *p; 467 data->raw_size = u.val32[0];
432 p++; 468 pdata = (void *) array + sizeof(u32);
433 469
434 if (sample_overlap(event, p, data->raw_size)) 470 if (sample_overlap(event, pdata, data->raw_size))
435 return -EFAULT; 471 return -EFAULT;
436 472
437 data->raw_data = p; 473 data->raw_data = (void *) pdata;
438 } 474 }
439 475
440 return 0; 476 return 0;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index cb2959a3fb43..76c0b2c49eb8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -7,6 +7,7 @@
7#include <stdlib.h> 7#include <stdlib.h>
8#include <linux/list.h> 8#include <linux/list.h>
9#include <linux/kernel.h> 9#include <linux/kernel.h>
10#include <sys/utsname.h>
10 11
11#include "evlist.h" 12#include "evlist.h"
12#include "evsel.h" 13#include "evsel.h"
@@ -17,12 +18,19 @@
17#include "session.h" 18#include "session.h"
18#include "symbol.h" 19#include "symbol.h"
19#include "debug.h" 20#include "debug.h"
21#include "cpumap.h"
20 22
21static bool no_buildid_cache = false; 23static bool no_buildid_cache = false;
22 24
23static int event_count; 25static int event_count;
24static struct perf_trace_event_type *events; 26static struct perf_trace_event_type *events;
25 27
28static u32 header_argc;
29static const char **header_argv;
30
31static int dsos__write_buildid_table(struct perf_header *header, int fd);
32static int perf_session__cache_build_ids(struct perf_session *session);
33
26int perf_header__push_event(u64 id, const char *name) 34int perf_header__push_event(u64 id, const char *name)
27{ 35{
28 if (strlen(name) > MAX_EVENT_NAME) 36 if (strlen(name) > MAX_EVENT_NAME)
@@ -110,6 +118,1020 @@ static int write_padded(int fd, const void *bf, size_t count,
110 return err; 118 return err;
111} 119}
112 120
121static int do_write_string(int fd, const char *str)
122{
123 u32 len, olen;
124 int ret;
125
126 olen = strlen(str) + 1;
127 len = ALIGN(olen, NAME_ALIGN);
128
129 /* write len, incl. \0 */
130 ret = do_write(fd, &len, sizeof(len));
131 if (ret < 0)
132 return ret;
133
134 return write_padded(fd, str, olen, len);
135}
136
137static char *do_read_string(int fd, struct perf_header *ph)
138{
139 ssize_t sz, ret;
140 u32 len;
141 char *buf;
142
143 sz = read(fd, &len, sizeof(len));
144 if (sz < (ssize_t)sizeof(len))
145 return NULL;
146
147 if (ph->needs_swap)
148 len = bswap_32(len);
149
150 buf = malloc(len);
151 if (!buf)
152 return NULL;
153
154 ret = read(fd, buf, len);
155 if (ret == (ssize_t)len) {
156 /*
157 * strings are padded by zeroes
158 * thus the actual strlen of buf
159 * may be less than len
160 */
161 return buf;
162 }
163
164 free(buf);
165 return NULL;
166}
167
168int
169perf_header__set_cmdline(int argc, const char **argv)
170{
171 int i;
172
173 header_argc = (u32)argc;
174
175 /* do not include NULL termination */
176 header_argv = calloc(argc, sizeof(char *));
177 if (!header_argv)
178 return -ENOMEM;
179
180 /*
181 * must copy argv contents because it gets moved
182 * around during option parsing
183 */
184 for (i = 0; i < argc ; i++)
185 header_argv[i] = argv[i];
186
187 return 0;
188}
189
190static int write_trace_info(int fd, struct perf_header *h __used,
191 struct perf_evlist *evlist)
192{
193 return read_tracing_data(fd, &evlist->entries);
194}
195
196
197static int write_build_id(int fd, struct perf_header *h,
198 struct perf_evlist *evlist __used)
199{
200 struct perf_session *session;
201 int err;
202
203 session = container_of(h, struct perf_session, header);
204
205 err = dsos__write_buildid_table(h, fd);
206 if (err < 0) {
207 pr_debug("failed to write buildid table\n");
208 return err;
209 }
210 if (!no_buildid_cache)
211 perf_session__cache_build_ids(session);
212
213 return 0;
214}
215
216static int write_hostname(int fd, struct perf_header *h __used,
217 struct perf_evlist *evlist __used)
218{
219 struct utsname uts;
220 int ret;
221
222 ret = uname(&uts);
223 if (ret < 0)
224 return -1;
225
226 return do_write_string(fd, uts.nodename);
227}
228
229static int write_osrelease(int fd, struct perf_header *h __used,
230 struct perf_evlist *evlist __used)
231{
232 struct utsname uts;
233 int ret;
234
235 ret = uname(&uts);
236 if (ret < 0)
237 return -1;
238
239 return do_write_string(fd, uts.release);
240}
241
242static int write_arch(int fd, struct perf_header *h __used,
243 struct perf_evlist *evlist __used)
244{
245 struct utsname uts;
246 int ret;
247
248 ret = uname(&uts);
249 if (ret < 0)
250 return -1;
251
252 return do_write_string(fd, uts.machine);
253}
254
255static int write_version(int fd, struct perf_header *h __used,
256 struct perf_evlist *evlist __used)
257{
258 return do_write_string(fd, perf_version_string);
259}
260
261static int write_cpudesc(int fd, struct perf_header *h __used,
262 struct perf_evlist *evlist __used)
263{
264#ifndef CPUINFO_PROC
265#define CPUINFO_PROC NULL
266#endif
267 FILE *file;
268 char *buf = NULL;
269 char *s, *p;
270 const char *search = CPUINFO_PROC;
271 size_t len = 0;
272 int ret = -1;
273
274 if (!search)
275 return -1;
276
277 file = fopen("/proc/cpuinfo", "r");
278 if (!file)
279 return -1;
280
281 while (getline(&buf, &len, file) > 0) {
282 ret = strncmp(buf, search, strlen(search));
283 if (!ret)
284 break;
285 }
286
287 if (ret)
288 goto done;
289
290 s = buf;
291
292 p = strchr(buf, ':');
293 if (p && *(p+1) == ' ' && *(p+2))
294 s = p + 2;
295 p = strchr(s, '\n');
296 if (p)
297 *p = '\0';
298
299 /* squash extra space characters (branding string) */
300 p = s;
301 while (*p) {
302 if (isspace(*p)) {
303 char *r = p + 1;
304 char *q = r;
305 *p = ' ';
306 while (*q && isspace(*q))
307 q++;
308 if (q != (p+1))
309 while ((*r++ = *q++));
310 }
311 p++;
312 }
313 ret = do_write_string(fd, s);
314done:
315 free(buf);
316 fclose(file);
317 return ret;
318}
319
320static int write_nrcpus(int fd, struct perf_header *h __used,
321 struct perf_evlist *evlist __used)
322{
323 long nr;
324 u32 nrc, nra;
325 int ret;
326
327 nr = sysconf(_SC_NPROCESSORS_CONF);
328 if (nr < 0)
329 return -1;
330
331 nrc = (u32)(nr & UINT_MAX);
332
333 nr = sysconf(_SC_NPROCESSORS_ONLN);
334 if (nr < 0)
335 return -1;
336
337 nra = (u32)(nr & UINT_MAX);
338
339 ret = do_write(fd, &nrc, sizeof(nrc));
340 if (ret < 0)
341 return ret;
342
343 return do_write(fd, &nra, sizeof(nra));
344}
345
346static int write_event_desc(int fd, struct perf_header *h __used,
347 struct perf_evlist *evlist)
348{
349 struct perf_evsel *attr;
350 u32 nre = 0, nri, sz;
351 int ret;
352
353 list_for_each_entry(attr, &evlist->entries, node)
354 nre++;
355
356 /*
357 * write number of events
358 */
359 ret = do_write(fd, &nre, sizeof(nre));
360 if (ret < 0)
361 return ret;
362
363 /*
364 * size of perf_event_attr struct
365 */
366 sz = (u32)sizeof(attr->attr);
367 ret = do_write(fd, &sz, sizeof(sz));
368 if (ret < 0)
369 return ret;
370
371 list_for_each_entry(attr, &evlist->entries, node) {
372
373 ret = do_write(fd, &attr->attr, sz);
374 if (ret < 0)
375 return ret;
376 /*
377 * write number of unique id per event
378 * there is one id per instance of an event
379 *
380 * copy into an nri to be independent of the
381 * type of ids,
382 */
383 nri = attr->ids;
384 ret = do_write(fd, &nri, sizeof(nri));
385 if (ret < 0)
386 return ret;
387
388 /*
389 * write event string as passed on cmdline
390 */
391 ret = do_write_string(fd, attr->name);
392 if (ret < 0)
393 return ret;
394 /*
395 * write unique ids for this event
396 */
397 ret = do_write(fd, attr->id, attr->ids * sizeof(u64));
398 if (ret < 0)
399 return ret;
400 }
401 return 0;
402}
403
404static int write_cmdline(int fd, struct perf_header *h __used,
405 struct perf_evlist *evlist __used)
406{
407 char buf[MAXPATHLEN];
408 char proc[32];
409 u32 i, n;
410 int ret;
411
412 /*
413 * actual atual path to perf binary
414 */
415 sprintf(proc, "/proc/%d/exe", getpid());
416 ret = readlink(proc, buf, sizeof(buf));
417 if (ret <= 0)
418 return -1;
419
420 /* readlink() does not add null termination */
421 buf[ret] = '\0';
422
423 /* account for binary path */
424 n = header_argc + 1;
425
426 ret = do_write(fd, &n, sizeof(n));
427 if (ret < 0)
428 return ret;
429
430 ret = do_write_string(fd, buf);
431 if (ret < 0)
432 return ret;
433
434 for (i = 0 ; i < header_argc; i++) {
435 ret = do_write_string(fd, header_argv[i]);
436 if (ret < 0)
437 return ret;
438 }
439 return 0;
440}
441
442#define CORE_SIB_FMT \
443 "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list"
444#define THRD_SIB_FMT \
445 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list"
446
447struct cpu_topo {
448 u32 core_sib;
449 u32 thread_sib;
450 char **core_siblings;
451 char **thread_siblings;
452};
453
454static int build_cpu_topo(struct cpu_topo *tp, int cpu)
455{
456 FILE *fp;
457 char filename[MAXPATHLEN];
458 char *buf = NULL, *p;
459 size_t len = 0;
460 u32 i = 0;
461 int ret = -1;
462
463 sprintf(filename, CORE_SIB_FMT, cpu);
464 fp = fopen(filename, "r");
465 if (!fp)
466 return -1;
467
468 if (getline(&buf, &len, fp) <= 0)
469 goto done;
470
471 fclose(fp);
472
473 p = strchr(buf, '\n');
474 if (p)
475 *p = '\0';
476
477 for (i = 0; i < tp->core_sib; i++) {
478 if (!strcmp(buf, tp->core_siblings[i]))
479 break;
480 }
481 if (i == tp->core_sib) {
482 tp->core_siblings[i] = buf;
483 tp->core_sib++;
484 buf = NULL;
485 len = 0;
486 }
487
488 sprintf(filename, THRD_SIB_FMT, cpu);
489 fp = fopen(filename, "r");
490 if (!fp)
491 goto done;
492
493 if (getline(&buf, &len, fp) <= 0)
494 goto done;
495
496 p = strchr(buf, '\n');
497 if (p)
498 *p = '\0';
499
500 for (i = 0; i < tp->thread_sib; i++) {
501 if (!strcmp(buf, tp->thread_siblings[i]))
502 break;
503 }
504 if (i == tp->thread_sib) {
505 tp->thread_siblings[i] = buf;
506 tp->thread_sib++;
507 buf = NULL;
508 }
509 ret = 0;
510done:
511 if(fp)
512 fclose(fp);
513 free(buf);
514 return ret;
515}
516
517static void free_cpu_topo(struct cpu_topo *tp)
518{
519 u32 i;
520
521 if (!tp)
522 return;
523
524 for (i = 0 ; i < tp->core_sib; i++)
525 free(tp->core_siblings[i]);
526
527 for (i = 0 ; i < tp->thread_sib; i++)
528 free(tp->thread_siblings[i]);
529
530 free(tp);
531}
532
533static struct cpu_topo *build_cpu_topology(void)
534{
535 struct cpu_topo *tp;
536 void *addr;
537 u32 nr, i;
538 size_t sz;
539 long ncpus;
540 int ret = -1;
541
542 ncpus = sysconf(_SC_NPROCESSORS_CONF);
543 if (ncpus < 0)
544 return NULL;
545
546 nr = (u32)(ncpus & UINT_MAX);
547
548 sz = nr * sizeof(char *);
549
550 addr = calloc(1, sizeof(*tp) + 2 * sz);
551 if (!addr)
552 return NULL;
553
554 tp = addr;
555
556 addr += sizeof(*tp);
557 tp->core_siblings = addr;
558 addr += sz;
559 tp->thread_siblings = addr;
560
561 for (i = 0; i < nr; i++) {
562 ret = build_cpu_topo(tp, i);
563 if (ret < 0)
564 break;
565 }
566 if (ret) {
567 free_cpu_topo(tp);
568 tp = NULL;
569 }
570 return tp;
571}
572
573static int write_cpu_topology(int fd, struct perf_header *h __used,
574 struct perf_evlist *evlist __used)
575{
576 struct cpu_topo *tp;
577 u32 i;
578 int ret;
579
580 tp = build_cpu_topology();
581 if (!tp)
582 return -1;
583
584 ret = do_write(fd, &tp->core_sib, sizeof(tp->core_sib));
585 if (ret < 0)
586 goto done;
587
588 for (i = 0; i < tp->core_sib; i++) {
589 ret = do_write_string(fd, tp->core_siblings[i]);
590 if (ret < 0)
591 goto done;
592 }
593 ret = do_write(fd, &tp->thread_sib, sizeof(tp->thread_sib));
594 if (ret < 0)
595 goto done;
596
597 for (i = 0; i < tp->thread_sib; i++) {
598 ret = do_write_string(fd, tp->thread_siblings[i]);
599 if (ret < 0)
600 break;
601 }
602done:
603 free_cpu_topo(tp);
604 return ret;
605}
606
607
608
609static int write_total_mem(int fd, struct perf_header *h __used,
610 struct perf_evlist *evlist __used)
611{
612 char *buf = NULL;
613 FILE *fp;
614 size_t len = 0;
615 int ret = -1, n;
616 uint64_t mem;
617
618 fp = fopen("/proc/meminfo", "r");
619 if (!fp)
620 return -1;
621
622 while (getline(&buf, &len, fp) > 0) {
623 ret = strncmp(buf, "MemTotal:", 9);
624 if (!ret)
625 break;
626 }
627 if (!ret) {
628 n = sscanf(buf, "%*s %"PRIu64, &mem);
629 if (n == 1)
630 ret = do_write(fd, &mem, sizeof(mem));
631 }
632 free(buf);
633 fclose(fp);
634 return ret;
635}
636
637static int write_topo_node(int fd, int node)
638{
639 char str[MAXPATHLEN];
640 char field[32];
641 char *buf = NULL, *p;
642 size_t len = 0;
643 FILE *fp;
644 u64 mem_total, mem_free, mem;
645 int ret = -1;
646
647 sprintf(str, "/sys/devices/system/node/node%d/meminfo", node);
648 fp = fopen(str, "r");
649 if (!fp)
650 return -1;
651
652 while (getline(&buf, &len, fp) > 0) {
653 /* skip over invalid lines */
654 if (!strchr(buf, ':'))
655 continue;
656 if (sscanf(buf, "%*s %*d %s %"PRIu64, field, &mem) != 2)
657 goto done;
658 if (!strcmp(field, "MemTotal:"))
659 mem_total = mem;
660 if (!strcmp(field, "MemFree:"))
661 mem_free = mem;
662 }
663
664 fclose(fp);
665
666 ret = do_write(fd, &mem_total, sizeof(u64));
667 if (ret)
668 goto done;
669
670 ret = do_write(fd, &mem_free, sizeof(u64));
671 if (ret)
672 goto done;
673
674 ret = -1;
675 sprintf(str, "/sys/devices/system/node/node%d/cpulist", node);
676
677 fp = fopen(str, "r");
678 if (!fp)
679 goto done;
680
681 if (getline(&buf, &len, fp) <= 0)
682 goto done;
683
684 p = strchr(buf, '\n');
685 if (p)
686 *p = '\0';
687
688 ret = do_write_string(fd, buf);
689done:
690 free(buf);
691 fclose(fp);
692 return ret;
693}
694
695static int write_numa_topology(int fd, struct perf_header *h __used,
696 struct perf_evlist *evlist __used)
697{
698 char *buf = NULL;
699 size_t len = 0;
700 FILE *fp;
701 struct cpu_map *node_map = NULL;
702 char *c;
703 u32 nr, i, j;
704 int ret = -1;
705
706 fp = fopen("/sys/devices/system/node/online", "r");
707 if (!fp)
708 return -1;
709
710 if (getline(&buf, &len, fp) <= 0)
711 goto done;
712
713 c = strchr(buf, '\n');
714 if (c)
715 *c = '\0';
716
717 node_map = cpu_map__new(buf);
718 if (!node_map)
719 goto done;
720
721 nr = (u32)node_map->nr;
722
723 ret = do_write(fd, &nr, sizeof(nr));
724 if (ret < 0)
725 goto done;
726
727 for (i = 0; i < nr; i++) {
728 j = (u32)node_map->map[i];
729 ret = do_write(fd, &j, sizeof(j));
730 if (ret < 0)
731 break;
732
733 ret = write_topo_node(fd, i);
734 if (ret < 0)
735 break;
736 }
737done:
738 free(buf);
739 fclose(fp);
740 free(node_map);
741 return ret;
742}
743
744/*
745 * default get_cpuid(): nothing gets recorded
746 * actual implementation must be in arch/$(ARCH)/util/header.c
747 */
748int __attribute__((weak)) get_cpuid(char *buffer __used, size_t sz __used)
749{
750 return -1;
751}
752
753static int write_cpuid(int fd, struct perf_header *h __used,
754 struct perf_evlist *evlist __used)
755{
756 char buffer[64];
757 int ret;
758
759 ret = get_cpuid(buffer, sizeof(buffer));
760 if (!ret)
761 goto write_it;
762
763 return -1;
764write_it:
765 return do_write_string(fd, buffer);
766}
767
768static void print_hostname(struct perf_header *ph, int fd, FILE *fp)
769{
770 char *str = do_read_string(fd, ph);
771 fprintf(fp, "# hostname : %s\n", str);
772 free(str);
773}
774
775static void print_osrelease(struct perf_header *ph, int fd, FILE *fp)
776{
777 char *str = do_read_string(fd, ph);
778 fprintf(fp, "# os release : %s\n", str);
779 free(str);
780}
781
782static void print_arch(struct perf_header *ph, int fd, FILE *fp)
783{
784 char *str = do_read_string(fd, ph);
785 fprintf(fp, "# arch : %s\n", str);
786 free(str);
787}
788
789static void print_cpudesc(struct perf_header *ph, int fd, FILE *fp)
790{
791 char *str = do_read_string(fd, ph);
792 fprintf(fp, "# cpudesc : %s\n", str);
793 free(str);
794}
795
796static void print_nrcpus(struct perf_header *ph, int fd, FILE *fp)
797{
798 ssize_t ret;
799 u32 nr;
800
801 ret = read(fd, &nr, sizeof(nr));
802 if (ret != (ssize_t)sizeof(nr))
803 nr = -1; /* interpreted as error */
804
805 if (ph->needs_swap)
806 nr = bswap_32(nr);
807
808 fprintf(fp, "# nrcpus online : %u\n", nr);
809
810 ret = read(fd, &nr, sizeof(nr));
811 if (ret != (ssize_t)sizeof(nr))
812 nr = -1; /* interpreted as error */
813
814 if (ph->needs_swap)
815 nr = bswap_32(nr);
816
817 fprintf(fp, "# nrcpus avail : %u\n", nr);
818}
819
820static void print_version(struct perf_header *ph, int fd, FILE *fp)
821{
822 char *str = do_read_string(fd, ph);
823 fprintf(fp, "# perf version : %s\n", str);
824 free(str);
825}
826
827static void print_cmdline(struct perf_header *ph, int fd, FILE *fp)
828{
829 ssize_t ret;
830 char *str;
831 u32 nr, i;
832
833 ret = read(fd, &nr, sizeof(nr));
834 if (ret != (ssize_t)sizeof(nr))
835 return;
836
837 if (ph->needs_swap)
838 nr = bswap_32(nr);
839
840 fprintf(fp, "# cmdline : ");
841
842 for (i = 0; i < nr; i++) {
843 str = do_read_string(fd, ph);
844 fprintf(fp, "%s ", str);
845 free(str);
846 }
847 fputc('\n', fp);
848}
849
850static void print_cpu_topology(struct perf_header *ph, int fd, FILE *fp)
851{
852 ssize_t ret;
853 u32 nr, i;
854 char *str;
855
856 ret = read(fd, &nr, sizeof(nr));
857 if (ret != (ssize_t)sizeof(nr))
858 return;
859
860 if (ph->needs_swap)
861 nr = bswap_32(nr);
862
863 for (i = 0; i < nr; i++) {
864 str = do_read_string(fd, ph);
865 fprintf(fp, "# sibling cores : %s\n", str);
866 free(str);
867 }
868
869 ret = read(fd, &nr, sizeof(nr));
870 if (ret != (ssize_t)sizeof(nr))
871 return;
872
873 if (ph->needs_swap)
874 nr = bswap_32(nr);
875
876 for (i = 0; i < nr; i++) {
877 str = do_read_string(fd, ph);
878 fprintf(fp, "# sibling threads : %s\n", str);
879 free(str);
880 }
881}
882
883static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
884{
885 struct perf_event_attr attr;
886 uint64_t id;
887 void *buf = NULL;
888 char *str;
889 u32 nre, sz, nr, i, j, msz;
890 int ret;
891
892 /* number of events */
893 ret = read(fd, &nre, sizeof(nre));
894 if (ret != (ssize_t)sizeof(nre))
895 goto error;
896
897 if (ph->needs_swap)
898 nre = bswap_32(nre);
899
900 ret = read(fd, &sz, sizeof(sz));
901 if (ret != (ssize_t)sizeof(sz))
902 goto error;
903
904 if (ph->needs_swap)
905 sz = bswap_32(sz);
906
907 /*
908 * ensure it is at least to our ABI rev
909 */
910 if (sz < (u32)sizeof(attr))
911 goto error;
912
913 memset(&attr, 0, sizeof(attr));
914
915 /* read entire region to sync up to next field */
916 buf = malloc(sz);
917 if (!buf)
918 goto error;
919
920 msz = sizeof(attr);
921 if (sz < msz)
922 msz = sz;
923
924 for (i = 0 ; i < nre; i++) {
925
926 ret = read(fd, buf, sz);
927 if (ret != (ssize_t)sz)
928 goto error;
929
930 if (ph->needs_swap)
931 perf_event__attr_swap(buf);
932
933 memcpy(&attr, buf, msz);
934
935 ret = read(fd, &nr, sizeof(nr));
936 if (ret != (ssize_t)sizeof(nr))
937 goto error;
938
939 if (ph->needs_swap)
940 nr = bswap_32(nr);
941
942 str = do_read_string(fd, ph);
943 fprintf(fp, "# event : name = %s, ", str);
944 free(str);
945
946 fprintf(fp, "type = %d, config = 0x%"PRIx64
947 ", config1 = 0x%"PRIx64", config2 = 0x%"PRIx64,
948 attr.type,
949 (u64)attr.config,
950 (u64)attr.config1,
951 (u64)attr.config2);
952
953 fprintf(fp, ", excl_usr = %d, excl_kern = %d",
954 attr.exclude_user,
955 attr.exclude_kernel);
956
957 if (nr)
958 fprintf(fp, ", id = {");
959
960 for (j = 0 ; j < nr; j++) {
961 ret = read(fd, &id, sizeof(id));
962 if (ret != (ssize_t)sizeof(id))
963 goto error;
964
965 if (ph->needs_swap)
966 id = bswap_64(id);
967
968 if (j)
969 fputc(',', fp);
970
971 fprintf(fp, " %"PRIu64, id);
972 }
973 if (nr && j == nr)
974 fprintf(fp, " }");
975 fputc('\n', fp);
976 }
977 free(buf);
978 return;
979error:
980 fprintf(fp, "# event desc: not available or unable to read\n");
981}
982
983static void print_total_mem(struct perf_header *h __used, int fd, FILE *fp)
984{
985 uint64_t mem;
986 ssize_t ret;
987
988 ret = read(fd, &mem, sizeof(mem));
989 if (ret != sizeof(mem))
990 goto error;
991
992 if (h->needs_swap)
993 mem = bswap_64(mem);
994
995 fprintf(fp, "# total memory : %"PRIu64" kB\n", mem);
996 return;
997error:
998 fprintf(fp, "# total memory : unknown\n");
999}
1000
1001static void print_numa_topology(struct perf_header *h __used, int fd, FILE *fp)
1002{
1003 ssize_t ret;
1004 u32 nr, c, i;
1005 char *str;
1006 uint64_t mem_total, mem_free;
1007
1008 /* nr nodes */
1009 ret = read(fd, &nr, sizeof(nr));
1010 if (ret != (ssize_t)sizeof(nr))
1011 goto error;
1012
1013 if (h->needs_swap)
1014 nr = bswap_32(nr);
1015
1016 for (i = 0; i < nr; i++) {
1017
1018 /* node number */
1019 ret = read(fd, &c, sizeof(c));
1020 if (ret != (ssize_t)sizeof(c))
1021 goto error;
1022
1023 if (h->needs_swap)
1024 c = bswap_32(c);
1025
1026 ret = read(fd, &mem_total, sizeof(u64));
1027 if (ret != sizeof(u64))
1028 goto error;
1029
1030 ret = read(fd, &mem_free, sizeof(u64));
1031 if (ret != sizeof(u64))
1032 goto error;
1033
1034 if (h->needs_swap) {
1035 mem_total = bswap_64(mem_total);
1036 mem_free = bswap_64(mem_free);
1037 }
1038
1039 fprintf(fp, "# node%u meminfo : total = %"PRIu64" kB,"
1040 " free = %"PRIu64" kB\n",
1041 c,
1042 mem_total,
1043 mem_free);
1044
1045 str = do_read_string(fd, h);
1046 fprintf(fp, "# node%u cpu list : %s\n", c, str);
1047 free(str);
1048 }
1049 return;
1050error:
1051 fprintf(fp, "# numa topology : not available\n");
1052}
1053
1054static void print_cpuid(struct perf_header *ph, int fd, FILE *fp)
1055{
1056 char *str = do_read_string(fd, ph);
1057 fprintf(fp, "# cpuid : %s\n", str);
1058 free(str);
1059}
1060
1061struct feature_ops {
1062 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1063 void (*print)(struct perf_header *h, int fd, FILE *fp);
1064 const char *name;
1065 bool full_only;
1066};
1067
1068#define FEAT_OPA(n, w, p) \
1069 [n] = { .name = #n, .write = w, .print = p }
1070#define FEAT_OPF(n, w, p) \
1071 [n] = { .name = #n, .write = w, .print = p, .full_only = true }
1072
1073static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1074 FEAT_OPA(HEADER_TRACE_INFO, write_trace_info, NULL),
1075 FEAT_OPA(HEADER_BUILD_ID, write_build_id, NULL),
1076 FEAT_OPA(HEADER_HOSTNAME, write_hostname, print_hostname),
1077 FEAT_OPA(HEADER_OSRELEASE, write_osrelease, print_osrelease),
1078 FEAT_OPA(HEADER_VERSION, write_version, print_version),
1079 FEAT_OPA(HEADER_ARCH, write_arch, print_arch),
1080 FEAT_OPA(HEADER_NRCPUS, write_nrcpus, print_nrcpus),
1081 FEAT_OPA(HEADER_CPUDESC, write_cpudesc, print_cpudesc),
1082 FEAT_OPA(HEADER_CPUID, write_cpuid, print_cpuid),
1083 FEAT_OPA(HEADER_TOTAL_MEM, write_total_mem, print_total_mem),
1084 FEAT_OPA(HEADER_EVENT_DESC, write_event_desc, print_event_desc),
1085 FEAT_OPA(HEADER_CMDLINE, write_cmdline, print_cmdline),
1086 FEAT_OPF(HEADER_CPU_TOPOLOGY, write_cpu_topology, print_cpu_topology),
1087 FEAT_OPF(HEADER_NUMA_TOPOLOGY, write_numa_topology, print_numa_topology),
1088};
1089
1090struct header_print_data {
1091 FILE *fp;
1092 bool full; /* extended list of headers */
1093};
1094
1095static int perf_file_section__fprintf_info(struct perf_file_section *section,
1096 struct perf_header *ph,
1097 int feat, int fd, void *data)
1098{
1099 struct header_print_data *hd = data;
1100
1101 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
1102 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
1103 "%d, continuing...\n", section->offset, feat);
1104 return 0;
1105 }
1106 if (feat < HEADER_TRACE_INFO || feat >= HEADER_LAST_FEATURE) {
1107 pr_warning("unknown feature %d\n", feat);
1108 return -1;
1109 }
1110 if (!feat_ops[feat].print)
1111 return 0;
1112
1113 if (!feat_ops[feat].full_only || hd->full)
1114 feat_ops[feat].print(ph, fd, hd->fp);
1115 else
1116 fprintf(hd->fp, "# %s info available, use -I to display\n",
1117 feat_ops[feat].name);
1118
1119 return 0;
1120}
1121
1122int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
1123{
1124 struct header_print_data hd;
1125 struct perf_header *header = &session->header;
1126 int fd = session->fd;
1127 hd.fp = fp;
1128 hd.full = full;
1129
1130 perf_header__process_sections(header, fd, &hd,
1131 perf_file_section__fprintf_info);
1132 return 0;
1133}
1134
113#define dsos__for_each_with_build_id(pos, head) \ 1135#define dsos__for_each_with_build_id(pos, head) \
114 list_for_each_entry(pos, head, node) \ 1136 list_for_each_entry(pos, head, node) \
115 if (!pos->has_build_id) \ 1137 if (!pos->has_build_id) \
@@ -189,8 +1211,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
189 const char *name, bool is_kallsyms) 1211 const char *name, bool is_kallsyms)
190{ 1212{
191 const size_t size = PATH_MAX; 1213 const size_t size = PATH_MAX;
192 char *realname, *filename = malloc(size), 1214 char *realname, *filename = zalloc(size),
193 *linkname = malloc(size), *targetname; 1215 *linkname = zalloc(size), *targetname;
194 int len, err = -1; 1216 int len, err = -1;
195 1217
196 if (is_kallsyms) { 1218 if (is_kallsyms) {
@@ -254,8 +1276,8 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
254int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) 1276int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
255{ 1277{
256 const size_t size = PATH_MAX; 1278 const size_t size = PATH_MAX;
257 char *filename = malloc(size), 1279 char *filename = zalloc(size),
258 *linkname = malloc(size); 1280 *linkname = zalloc(size);
259 int err = -1; 1281 int err = -1;
260 1282
261 if (filename == NULL || linkname == NULL) 1283 if (filename == NULL || linkname == NULL)
@@ -267,7 +1289,7 @@ int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
267 if (access(linkname, F_OK)) 1289 if (access(linkname, F_OK))
268 goto out_free; 1290 goto out_free;
269 1291
270 if (readlink(linkname, filename, size) < 0) 1292 if (readlink(linkname, filename, size - 1) < 0)
271 goto out_free; 1293 goto out_free;
272 1294
273 if (unlink(linkname)) 1295 if (unlink(linkname))
@@ -356,15 +1378,41 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with
356 return ret; 1378 return ret;
357} 1379}
358 1380
1381static int do_write_feat(int fd, struct perf_header *h, int type,
1382 struct perf_file_section **p,
1383 struct perf_evlist *evlist)
1384{
1385 int err;
1386 int ret = 0;
1387
1388 if (perf_header__has_feat(h, type)) {
1389
1390 (*p)->offset = lseek(fd, 0, SEEK_CUR);
1391
1392 err = feat_ops[type].write(fd, h, evlist);
1393 if (err < 0) {
1394 pr_debug("failed to write feature %d\n", type);
1395
1396 /* undo anything written */
1397 lseek(fd, (*p)->offset, SEEK_SET);
1398
1399 return -1;
1400 }
1401 (*p)->size = lseek(fd, 0, SEEK_CUR) - (*p)->offset;
1402 (*p)++;
1403 }
1404 return ret;
1405}
1406
359static int perf_header__adds_write(struct perf_header *header, 1407static int perf_header__adds_write(struct perf_header *header,
360 struct perf_evlist *evlist, int fd) 1408 struct perf_evlist *evlist, int fd)
361{ 1409{
362 int nr_sections; 1410 int nr_sections;
363 struct perf_session *session; 1411 struct perf_session *session;
364 struct perf_file_section *feat_sec; 1412 struct perf_file_section *feat_sec, *p;
365 int sec_size; 1413 int sec_size;
366 u64 sec_start; 1414 u64 sec_start;
367 int idx = 0, err; 1415 int err;
368 1416
369 session = container_of(header, struct perf_session, header); 1417 session = container_of(header, struct perf_session, header);
370 1418
@@ -376,7 +1424,7 @@ static int perf_header__adds_write(struct perf_header *header,
376 if (!nr_sections) 1424 if (!nr_sections)
377 return 0; 1425 return 0;
378 1426
379 feat_sec = calloc(sizeof(*feat_sec), nr_sections); 1427 feat_sec = p = calloc(sizeof(*feat_sec), nr_sections);
380 if (feat_sec == NULL) 1428 if (feat_sec == NULL)
381 return -ENOMEM; 1429 return -ENOMEM;
382 1430
@@ -385,36 +1433,69 @@ static int perf_header__adds_write(struct perf_header *header,
385 sec_start = header->data_offset + header->data_size; 1433 sec_start = header->data_offset + header->data_size;
386 lseek(fd, sec_start + sec_size, SEEK_SET); 1434 lseek(fd, sec_start + sec_size, SEEK_SET);
387 1435
388 if (perf_header__has_feat(header, HEADER_TRACE_INFO)) { 1436 err = do_write_feat(fd, header, HEADER_TRACE_INFO, &p, evlist);
389 struct perf_file_section *trace_sec; 1437 if (err)
390 1438 goto out_free;
391 trace_sec = &feat_sec[idx++];
392 1439
393 /* Write trace info */ 1440 err = do_write_feat(fd, header, HEADER_BUILD_ID, &p, evlist);
394 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 1441 if (err) {
395 read_tracing_data(fd, &evlist->entries); 1442 perf_header__clear_feat(header, HEADER_BUILD_ID);
396 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 1443 goto out_free;
397 } 1444 }
398 1445
399 if (perf_header__has_feat(header, HEADER_BUILD_ID)) { 1446 err = do_write_feat(fd, header, HEADER_HOSTNAME, &p, evlist);
400 struct perf_file_section *buildid_sec; 1447 if (err)
1448 perf_header__clear_feat(header, HEADER_HOSTNAME);
401 1449
402 buildid_sec = &feat_sec[idx++]; 1450 err = do_write_feat(fd, header, HEADER_OSRELEASE, &p, evlist);
1451 if (err)
1452 perf_header__clear_feat(header, HEADER_OSRELEASE);
403 1453
404 /* Write build-ids */ 1454 err = do_write_feat(fd, header, HEADER_VERSION, &p, evlist);
405 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 1455 if (err)
406 err = dsos__write_buildid_table(header, fd); 1456 perf_header__clear_feat(header, HEADER_VERSION);
407 if (err < 0) { 1457
408 pr_debug("failed to write buildid table\n"); 1458 err = do_write_feat(fd, header, HEADER_ARCH, &p, evlist);
409 goto out_free; 1459 if (err)
410 } 1460 perf_header__clear_feat(header, HEADER_ARCH);
411 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - 1461
412 buildid_sec->offset; 1462 err = do_write_feat(fd, header, HEADER_NRCPUS, &p, evlist);
413 if (!no_buildid_cache) 1463 if (err)
414 perf_session__cache_build_ids(session); 1464 perf_header__clear_feat(header, HEADER_NRCPUS);
415 } 1465
1466 err = do_write_feat(fd, header, HEADER_CPUDESC, &p, evlist);
1467 if (err)
1468 perf_header__clear_feat(header, HEADER_CPUDESC);
1469
1470 err = do_write_feat(fd, header, HEADER_CPUID, &p, evlist);
1471 if (err)
1472 perf_header__clear_feat(header, HEADER_CPUID);
1473
1474 err = do_write_feat(fd, header, HEADER_TOTAL_MEM, &p, evlist);
1475 if (err)
1476 perf_header__clear_feat(header, HEADER_TOTAL_MEM);
1477
1478 err = do_write_feat(fd, header, HEADER_CMDLINE, &p, evlist);
1479 if (err)
1480 perf_header__clear_feat(header, HEADER_CMDLINE);
1481
1482 err = do_write_feat(fd, header, HEADER_EVENT_DESC, &p, evlist);
1483 if (err)
1484 perf_header__clear_feat(header, HEADER_EVENT_DESC);
1485
1486 err = do_write_feat(fd, header, HEADER_CPU_TOPOLOGY, &p, evlist);
1487 if (err)
1488 perf_header__clear_feat(header, HEADER_CPU_TOPOLOGY);
1489
1490 err = do_write_feat(fd, header, HEADER_NUMA_TOPOLOGY, &p, evlist);
1491 if (err)
1492 perf_header__clear_feat(header, HEADER_NUMA_TOPOLOGY);
416 1493
417 lseek(fd, sec_start, SEEK_SET); 1494 lseek(fd, sec_start, SEEK_SET);
1495 /*
1496 * may write more than needed due to dropped feature, but
1497 * this is okay, reader will skip the mising entries
1498 */
418 err = do_write(fd, feat_sec, sec_size); 1499 err = do_write(fd, feat_sec, sec_size);
419 if (err < 0) 1500 if (err < 0)
420 pr_debug("failed to write feature section\n"); 1501 pr_debug("failed to write feature section\n");
@@ -554,9 +1635,10 @@ static int perf_header__getbuffer64(struct perf_header *header,
554} 1635}
555 1636
556int perf_header__process_sections(struct perf_header *header, int fd, 1637int perf_header__process_sections(struct perf_header *header, int fd,
1638 void *data,
557 int (*process)(struct perf_file_section *section, 1639 int (*process)(struct perf_file_section *section,
558 struct perf_header *ph, 1640 struct perf_header *ph,
559 int feat, int fd)) 1641 int feat, int fd, void *data))
560{ 1642{
561 struct perf_file_section *feat_sec; 1643 struct perf_file_section *feat_sec;
562 int nr_sections; 1644 int nr_sections;
@@ -584,7 +1666,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
584 if (perf_header__has_feat(header, feat)) { 1666 if (perf_header__has_feat(header, feat)) {
585 struct perf_file_section *sec = &feat_sec[idx++]; 1667 struct perf_file_section *sec = &feat_sec[idx++];
586 1668
587 err = process(sec, header, feat, fd); 1669 err = process(sec, header, feat, fd, data);
588 if (err < 0) 1670 if (err < 0)
589 break; 1671 break;
590 } 1672 }
@@ -621,21 +1703,41 @@ int perf_file_header__read(struct perf_file_header *header,
621 bitmap_zero(header->adds_features, HEADER_FEAT_BITS); 1703 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
622 else 1704 else
623 return -1; 1705 return -1;
1706 } else if (ph->needs_swap) {
1707 unsigned int i;
1708 /*
1709 * feature bitmap is declared as an array of unsigned longs --
1710 * not good since its size can differ between the host that
1711 * generated the data file and the host analyzing the file.
1712 *
1713 * We need to handle endianness, but we don't know the size of
1714 * the unsigned long where the file was generated. Take a best
1715 * guess at determining it: try 64-bit swap first (ie., file
1716 * created on a 64-bit host), and check if the hostname feature
1717 * bit is set (this feature bit is forced on as of fbe96f2).
1718 * If the bit is not, undo the 64-bit swap and try a 32-bit
1719 * swap. If the hostname bit is still not set (e.g., older data
1720 * file), punt and fallback to the original behavior --
1721 * clearing all feature bits and setting buildid.
1722 */
1723 for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i)
1724 header->adds_features[i] = bswap_64(header->adds_features[i]);
1725
1726 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
1727 for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) {
1728 header->adds_features[i] = bswap_64(header->adds_features[i]);
1729 header->adds_features[i] = bswap_32(header->adds_features[i]);
1730 }
1731 }
1732
1733 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
1734 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
1735 set_bit(HEADER_BUILD_ID, header->adds_features);
1736 }
624 } 1737 }
625 1738
626 memcpy(&ph->adds_features, &header->adds_features, 1739 memcpy(&ph->adds_features, &header->adds_features,
627 sizeof(ph->adds_features)); 1740 sizeof(ph->adds_features));
628 /*
629 * FIXME: hack that assumes that if we need swap the perf.data file
630 * may be coming from an arch with a different word-size, ergo different
631 * DEFINE_BITMAP format, investigate more later, but for now its mostly
632 * safe to assume that we have a build-id section. Trace files probably
633 * have several other issues in this realm anyway...
634 */
635 if (ph->needs_swap) {
636 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
637 perf_header__set_feat(ph, HEADER_BUILD_ID);
638 }
639 1741
640 ph->event_offset = header->event_types.offset; 1742 ph->event_offset = header->event_types.offset;
641 ph->event_size = header->event_types.size; 1743 ph->event_size = header->event_types.size;
@@ -726,7 +1828,16 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
726 return -1; 1828 return -1;
727 1829
728 bev.header = old_bev.header; 1830 bev.header = old_bev.header;
729 bev.pid = 0; 1831
1832 /*
1833 * As the pid is the missing value, we need to fill
1834 * it properly. The header.misc value give us nice hint.
1835 */
1836 bev.pid = HOST_KERNEL_ID;
1837 if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
1838 bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
1839 bev.pid = DEFAULT_GUEST_KERNEL_ID;
1840
730 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); 1841 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
731 __event_process_build_id(&bev, filename, session); 1842 __event_process_build_id(&bev, filename, session);
732 1843
@@ -787,7 +1898,7 @@ out:
787 1898
788static int perf_file_section__process(struct perf_file_section *section, 1899static int perf_file_section__process(struct perf_file_section *section,
789 struct perf_header *ph, 1900 struct perf_header *ph,
790 int feat, int fd) 1901 int feat, int fd, void *data __used)
791{ 1902{
792 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { 1903 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
793 pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 1904 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
@@ -804,6 +1915,21 @@ static int perf_file_section__process(struct perf_file_section *section,
804 if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) 1915 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
805 pr_debug("Failed to read buildids, continuing...\n"); 1916 pr_debug("Failed to read buildids, continuing...\n");
806 break; 1917 break;
1918
1919 case HEADER_HOSTNAME:
1920 case HEADER_OSRELEASE:
1921 case HEADER_VERSION:
1922 case HEADER_ARCH:
1923 case HEADER_NRCPUS:
1924 case HEADER_CPUDESC:
1925 case HEADER_CPUID:
1926 case HEADER_TOTAL_MEM:
1927 case HEADER_CMDLINE:
1928 case HEADER_EVENT_DESC:
1929 case HEADER_CPU_TOPOLOGY:
1930 case HEADER_NUMA_TOPOLOGY:
1931 break;
1932
807 default: 1933 default:
808 pr_debug("unknown feature %d, continuing...\n", feat); 1934 pr_debug("unknown feature %d, continuing...\n", feat);
809 } 1935 }
@@ -926,7 +2052,8 @@ int perf_session__read_header(struct perf_session *session, int fd)
926 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 2052 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
927 } 2053 }
928 2054
929 perf_header__process_sections(header, fd, perf_file_section__process); 2055 perf_header__process_sections(header, fd, NULL,
2056 perf_file_section__process);
930 2057
931 lseek(fd, header->data_offset, SEEK_SET); 2058 lseek(fd, header->data_offset, SEEK_SET);
932 2059
@@ -1091,15 +2218,29 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1091 struct perf_session *session __unused) 2218 struct perf_session *session __unused)
1092{ 2219{
1093 union perf_event ev; 2220 union perf_event ev;
2221 struct tracing_data *tdata;
1094 ssize_t size = 0, aligned_size = 0, padding; 2222 ssize_t size = 0, aligned_size = 0, padding;
1095 int err __used = 0; 2223 int err __used = 0;
1096 2224
2225 /*
2226 * We are going to store the size of the data followed
2227 * by the data contents. Since the fd descriptor is a pipe,
2228 * we cannot seek back to store the size of the data once
2229 * we know it. Instead we:
2230 *
2231 * - write the tracing data to the temp file
2232 * - get/write the data size to pipe
2233 * - write the tracing data from the temp file
2234 * to the pipe
2235 */
2236 tdata = tracing_data_get(&evlist->entries, fd, true);
2237 if (!tdata)
2238 return -1;
2239
1097 memset(&ev, 0, sizeof(ev)); 2240 memset(&ev, 0, sizeof(ev));
1098 2241
1099 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 2242 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1100 size = read_tracing_data_size(fd, &evlist->entries); 2243 size = tdata->size;
1101 if (size <= 0)
1102 return size;
1103 aligned_size = ALIGN(size, sizeof(u64)); 2244 aligned_size = ALIGN(size, sizeof(u64));
1104 padding = aligned_size - size; 2245 padding = aligned_size - size;
1105 ev.tracing_data.header.size = sizeof(ev.tracing_data); 2246 ev.tracing_data.header.size = sizeof(ev.tracing_data);
@@ -1107,7 +2248,12 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1107 2248
1108 process(&ev, NULL, session); 2249 process(&ev, NULL, session);
1109 2250
1110 err = read_tracing_data(fd, &evlist->entries); 2251 /*
2252 * The put function will copy all the tracing data
2253 * stored in temp file to the pipe.
2254 */
2255 tracing_data_put(tdata);
2256
1111 write_padded(fd, NULL, 0, padding); 2257 write_padded(fd, NULL, 0, padding);
1112 2258
1113 return aligned_size; 2259 return aligned_size;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 1886256768a1..3d5a742f4a2a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -12,6 +12,20 @@
12enum { 12enum {
13 HEADER_TRACE_INFO = 1, 13 HEADER_TRACE_INFO = 1,
14 HEADER_BUILD_ID, 14 HEADER_BUILD_ID,
15
16 HEADER_HOSTNAME,
17 HEADER_OSRELEASE,
18 HEADER_VERSION,
19 HEADER_ARCH,
20 HEADER_NRCPUS,
21 HEADER_CPUDESC,
22 HEADER_CPUID,
23 HEADER_TOTAL_MEM,
24 HEADER_CMDLINE,
25 HEADER_EVENT_DESC,
26 HEADER_CPU_TOPOLOGY,
27 HEADER_NUMA_TOPOLOGY,
28
15 HEADER_LAST_FEATURE, 29 HEADER_LAST_FEATURE,
16}; 30};
17 31
@@ -68,10 +82,15 @@ void perf_header__set_feat(struct perf_header *header, int feat);
68void perf_header__clear_feat(struct perf_header *header, int feat); 82void perf_header__clear_feat(struct perf_header *header, int feat);
69bool perf_header__has_feat(const struct perf_header *header, int feat); 83bool perf_header__has_feat(const struct perf_header *header, int feat);
70 84
85int perf_header__set_cmdline(int argc, const char **argv);
86
71int perf_header__process_sections(struct perf_header *header, int fd, 87int perf_header__process_sections(struct perf_header *header, int fd,
88 void *data,
72 int (*process)(struct perf_file_section *section, 89 int (*process)(struct perf_file_section *section,
73 struct perf_header *ph, 90 struct perf_header *ph,
74 int feat, int fd)); 91 int feat, int fd, void *data));
92
93int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
75 94
76int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, 95int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
77 const char *name, bool is_kallsyms); 96 const char *name, bool is_kallsyms);
@@ -104,4 +123,10 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
104 struct perf_session *session); 123 struct perf_session *session);
105int perf_event__process_build_id(union perf_event *event, 124int perf_event__process_build_id(union perf_event *event,
106 struct perf_session *session); 125 struct perf_session *session);
126
127/*
128 * arch specific callback
129 */
130int get_cpuid(char *buffer, size_t sz);
131
107#endif /* __PERF_HEADER_H */ 132#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 677e1da6bb3e..f6a993963a1e 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -6,6 +6,11 @@
6#include "sort.h" 6#include "sort.h"
7#include <math.h> 7#include <math.h>
8 8
9static bool hists__filter_entry_by_dso(struct hists *hists,
10 struct hist_entry *he);
11static bool hists__filter_entry_by_thread(struct hists *hists,
12 struct hist_entry *he);
13
9enum hist_filter { 14enum hist_filter {
10 HIST_FILTER__DSO, 15 HIST_FILTER__DSO,
11 HIST_FILTER__THREAD, 16 HIST_FILTER__THREAD,
@@ -18,56 +23,56 @@ struct callchain_param callchain_param = {
18 .order = ORDER_CALLEE 23 .order = ORDER_CALLEE
19}; 24};
20 25
21u16 hists__col_len(struct hists *self, enum hist_column col) 26u16 hists__col_len(struct hists *hists, enum hist_column col)
22{ 27{
23 return self->col_len[col]; 28 return hists->col_len[col];
24} 29}
25 30
26void hists__set_col_len(struct hists *self, enum hist_column col, u16 len) 31void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
27{ 32{
28 self->col_len[col] = len; 33 hists->col_len[col] = len;
29} 34}
30 35
31bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len) 36bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
32{ 37{
33 if (len > hists__col_len(self, col)) { 38 if (len > hists__col_len(hists, col)) {
34 hists__set_col_len(self, col, len); 39 hists__set_col_len(hists, col, len);
35 return true; 40 return true;
36 } 41 }
37 return false; 42 return false;
38} 43}
39 44
40static void hists__reset_col_len(struct hists *self) 45static void hists__reset_col_len(struct hists *hists)
41{ 46{
42 enum hist_column col; 47 enum hist_column col;
43 48
44 for (col = 0; col < HISTC_NR_COLS; ++col) 49 for (col = 0; col < HISTC_NR_COLS; ++col)
45 hists__set_col_len(self, col, 0); 50 hists__set_col_len(hists, col, 0);
46} 51}
47 52
48static void hists__calc_col_len(struct hists *self, struct hist_entry *h) 53static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
49{ 54{
50 u16 len; 55 u16 len;
51 56
52 if (h->ms.sym) 57 if (h->ms.sym)
53 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen); 58 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen);
54 else { 59 else {
55 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 60 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
56 61
57 if (hists__col_len(self, HISTC_DSO) < unresolved_col_width && 62 if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
58 !symbol_conf.col_width_list_str && !symbol_conf.field_sep && 63 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
59 !symbol_conf.dso_list) 64 !symbol_conf.dso_list)
60 hists__set_col_len(self, HISTC_DSO, 65 hists__set_col_len(hists, HISTC_DSO,
61 unresolved_col_width); 66 unresolved_col_width);
62 } 67 }
63 68
64 len = thread__comm_len(h->thread); 69 len = thread__comm_len(h->thread);
65 if (hists__new_col_len(self, HISTC_COMM, len)) 70 if (hists__new_col_len(hists, HISTC_COMM, len))
66 hists__set_col_len(self, HISTC_THREAD, len + 6); 71 hists__set_col_len(hists, HISTC_THREAD, len + 6);
67 72
68 if (h->ms.map) { 73 if (h->ms.map) {
69 len = dso__name_len(h->ms.map->dso); 74 len = dso__name_len(h->ms.map->dso);
70 hists__new_col_len(self, HISTC_DSO, len); 75 hists__new_col_len(hists, HISTC_DSO, len);
71 } 76 }
72} 77}
73 78
@@ -92,6 +97,67 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self,
92 } 97 }
93} 98}
94 99
100static void hist_entry__decay(struct hist_entry *he)
101{
102 he->period = (he->period * 7) / 8;
103 he->nr_events = (he->nr_events * 7) / 8;
104}
105
106static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
107{
108 u64 prev_period = he->period;
109
110 if (prev_period == 0)
111 return true;
112
113 hist_entry__decay(he);
114
115 if (!he->filtered)
116 hists->stats.total_period -= prev_period - he->period;
117
118 return he->period == 0;
119}
120
121static void __hists__decay_entries(struct hists *hists, bool zap_user,
122 bool zap_kernel, bool threaded)
123{
124 struct rb_node *next = rb_first(&hists->entries);
125 struct hist_entry *n;
126
127 while (next) {
128 n = rb_entry(next, struct hist_entry, rb_node);
129 next = rb_next(&n->rb_node);
130 /*
131 * We may be annotating this, for instance, so keep it here in
132 * case some it gets new samples, we'll eventually free it when
133 * the user stops browsing and it agains gets fully decayed.
134 */
135 if (((zap_user && n->level == '.') ||
136 (zap_kernel && n->level != '.') ||
137 hists__decay_entry(hists, n)) &&
138 !n->used) {
139 rb_erase(&n->rb_node, &hists->entries);
140
141 if (sort__need_collapse || threaded)
142 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
143
144 hist_entry__free(n);
145 --hists->nr_entries;
146 }
147 }
148}
149
150void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
151{
152 return __hists__decay_entries(hists, zap_user, zap_kernel, false);
153}
154
155void hists__decay_entries_threaded(struct hists *hists,
156 bool zap_user, bool zap_kernel)
157{
158 return __hists__decay_entries(hists, zap_user, zap_kernel, true);
159}
160
95/* 161/*
96 * histogram, sorted on item, collects periods 162 * histogram, sorted on item, collects periods
97 */ 163 */
@@ -113,11 +179,12 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
113 return self; 179 return self;
114} 180}
115 181
116static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h) 182static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
117{ 183{
118 if (!h->filtered) { 184 if (!h->filtered) {
119 hists__calc_col_len(self, h); 185 hists__calc_col_len(hists, h);
120 ++self->nr_entries; 186 ++hists->nr_entries;
187 hists->stats.total_period += h->period;
121 } 188 }
122} 189}
123 190
@@ -128,11 +195,11 @@ static u8 symbol__parent_filter(const struct symbol *parent)
128 return 0; 195 return 0;
129} 196}
130 197
131struct hist_entry *__hists__add_entry(struct hists *self, 198struct hist_entry *__hists__add_entry(struct hists *hists,
132 struct addr_location *al, 199 struct addr_location *al,
133 struct symbol *sym_parent, u64 period) 200 struct symbol *sym_parent, u64 period)
134{ 201{
135 struct rb_node **p = &self->entries.rb_node; 202 struct rb_node **p;
136 struct rb_node *parent = NULL; 203 struct rb_node *parent = NULL;
137 struct hist_entry *he; 204 struct hist_entry *he;
138 struct hist_entry entry = { 205 struct hist_entry entry = {
@@ -150,9 +217,13 @@ struct hist_entry *__hists__add_entry(struct hists *self,
150 }; 217 };
151 int cmp; 218 int cmp;
152 219
220 pthread_mutex_lock(&hists->lock);
221
222 p = &hists->entries_in->rb_node;
223
153 while (*p != NULL) { 224 while (*p != NULL) {
154 parent = *p; 225 parent = *p;
155 he = rb_entry(parent, struct hist_entry, rb_node); 226 he = rb_entry(parent, struct hist_entry, rb_node_in);
156 227
157 cmp = hist_entry__cmp(&entry, he); 228 cmp = hist_entry__cmp(&entry, he);
158 229
@@ -170,12 +241,14 @@ struct hist_entry *__hists__add_entry(struct hists *self,
170 241
171 he = hist_entry__new(&entry); 242 he = hist_entry__new(&entry);
172 if (!he) 243 if (!he)
173 return NULL; 244 goto out_unlock;
174 rb_link_node(&he->rb_node, parent, p); 245
175 rb_insert_color(&he->rb_node, &self->entries); 246 rb_link_node(&he->rb_node_in, parent, p);
176 hists__inc_nr_entries(self, he); 247 rb_insert_color(&he->rb_node_in, hists->entries_in);
177out: 248out:
178 hist_entry__add_cpumode_period(he, al->cpumode, period); 249 hist_entry__add_cpumode_period(he, al->cpumode, period);
250out_unlock:
251 pthread_mutex_unlock(&hists->lock);
179 return he; 252 return he;
180} 253}
181 254
@@ -222,7 +295,7 @@ void hist_entry__free(struct hist_entry *he)
222 * collapse the histogram 295 * collapse the histogram
223 */ 296 */
224 297
225static bool hists__collapse_insert_entry(struct hists *self, 298static bool hists__collapse_insert_entry(struct hists *hists,
226 struct rb_root *root, 299 struct rb_root *root,
227 struct hist_entry *he) 300 struct hist_entry *he)
228{ 301{
@@ -233,15 +306,16 @@ static bool hists__collapse_insert_entry(struct hists *self,
233 306
234 while (*p != NULL) { 307 while (*p != NULL) {
235 parent = *p; 308 parent = *p;
236 iter = rb_entry(parent, struct hist_entry, rb_node); 309 iter = rb_entry(parent, struct hist_entry, rb_node_in);
237 310
238 cmp = hist_entry__collapse(iter, he); 311 cmp = hist_entry__collapse(iter, he);
239 312
240 if (!cmp) { 313 if (!cmp) {
241 iter->period += he->period; 314 iter->period += he->period;
315 iter->nr_events += he->nr_events;
242 if (symbol_conf.use_callchain) { 316 if (symbol_conf.use_callchain) {
243 callchain_cursor_reset(&self->callchain_cursor); 317 callchain_cursor_reset(&hists->callchain_cursor);
244 callchain_merge(&self->callchain_cursor, iter->callchain, 318 callchain_merge(&hists->callchain_cursor, iter->callchain,
245 he->callchain); 319 he->callchain);
246 } 320 }
247 hist_entry__free(he); 321 hist_entry__free(he);
@@ -254,35 +328,70 @@ static bool hists__collapse_insert_entry(struct hists *self,
254 p = &(*p)->rb_right; 328 p = &(*p)->rb_right;
255 } 329 }
256 330
257 rb_link_node(&he->rb_node, parent, p); 331 rb_link_node(&he->rb_node_in, parent, p);
258 rb_insert_color(&he->rb_node, root); 332 rb_insert_color(&he->rb_node_in, root);
259 return true; 333 return true;
260} 334}
261 335
262void hists__collapse_resort(struct hists *self) 336static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
337{
338 struct rb_root *root;
339
340 pthread_mutex_lock(&hists->lock);
341
342 root = hists->entries_in;
343 if (++hists->entries_in > &hists->entries_in_array[1])
344 hists->entries_in = &hists->entries_in_array[0];
345
346 pthread_mutex_unlock(&hists->lock);
347
348 return root;
349}
350
351static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
352{
353 hists__filter_entry_by_dso(hists, he);
354 hists__filter_entry_by_thread(hists, he);
355}
356
357static void __hists__collapse_resort(struct hists *hists, bool threaded)
263{ 358{
264 struct rb_root tmp; 359 struct rb_root *root;
265 struct rb_node *next; 360 struct rb_node *next;
266 struct hist_entry *n; 361 struct hist_entry *n;
267 362
268 if (!sort__need_collapse) 363 if (!sort__need_collapse && !threaded)
269 return; 364 return;
270 365
271 tmp = RB_ROOT; 366 root = hists__get_rotate_entries_in(hists);
272 next = rb_first(&self->entries); 367 next = rb_first(root);
273 self->nr_entries = 0; 368 hists->stats.total_period = 0;
274 hists__reset_col_len(self);
275 369
276 while (next) { 370 while (next) {
277 n = rb_entry(next, struct hist_entry, rb_node); 371 n = rb_entry(next, struct hist_entry, rb_node_in);
278 next = rb_next(&n->rb_node); 372 next = rb_next(&n->rb_node_in);
279 373
280 rb_erase(&n->rb_node, &self->entries); 374 rb_erase(&n->rb_node_in, root);
281 if (hists__collapse_insert_entry(self, &tmp, n)) 375 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) {
282 hists__inc_nr_entries(self, n); 376 /*
377 * If it wasn't combined with one of the entries already
378 * collapsed, we need to apply the filters that may have
379 * been set by, say, the hist_browser.
380 */
381 hists__apply_filters(hists, n);
382 hists__inc_nr_entries(hists, n);
383 }
283 } 384 }
385}
284 386
285 self->entries = tmp; 387void hists__collapse_resort(struct hists *hists)
388{
389 return __hists__collapse_resort(hists, false);
390}
391
392void hists__collapse_resort_threaded(struct hists *hists)
393{
394 return __hists__collapse_resort(hists, true);
286} 395}
287 396
288/* 397/*
@@ -315,31 +424,43 @@ static void __hists__insert_output_entry(struct rb_root *entries,
315 rb_insert_color(&he->rb_node, entries); 424 rb_insert_color(&he->rb_node, entries);
316} 425}
317 426
318void hists__output_resort(struct hists *self) 427static void __hists__output_resort(struct hists *hists, bool threaded)
319{ 428{
320 struct rb_root tmp; 429 struct rb_root *root;
321 struct rb_node *next; 430 struct rb_node *next;
322 struct hist_entry *n; 431 struct hist_entry *n;
323 u64 min_callchain_hits; 432 u64 min_callchain_hits;
324 433
325 min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100); 434 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
435
436 if (sort__need_collapse || threaded)
437 root = &hists->entries_collapsed;
438 else
439 root = hists->entries_in;
326 440
327 tmp = RB_ROOT; 441 next = rb_first(root);
328 next = rb_first(&self->entries); 442 hists->entries = RB_ROOT;
329 443
330 self->nr_entries = 0; 444 hists->nr_entries = 0;
331 hists__reset_col_len(self); 445 hists__reset_col_len(hists);
332 446
333 while (next) { 447 while (next) {
334 n = rb_entry(next, struct hist_entry, rb_node); 448 n = rb_entry(next, struct hist_entry, rb_node_in);
335 next = rb_next(&n->rb_node); 449 next = rb_next(&n->rb_node_in);
336 450
337 rb_erase(&n->rb_node, &self->entries); 451 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
338 __hists__insert_output_entry(&tmp, n, min_callchain_hits); 452 hists__inc_nr_entries(hists, n);
339 hists__inc_nr_entries(self, n);
340 } 453 }
454}
341 455
342 self->entries = tmp; 456void hists__output_resort(struct hists *hists)
457{
458 return __hists__output_resort(hists, false);
459}
460
461void hists__output_resort_threaded(struct hists *hists)
462{
463 return __hists__output_resort(hists, true);
343} 464}
344 465
345static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 466static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -594,12 +715,27 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
594 return ret; 715 return ret;
595} 716}
596 717
597int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, 718void hists__output_recalc_col_len(struct hists *hists, int max_rows)
598 struct hists *hists, struct hists *pair_hists, 719{
599 bool show_displacement, long displacement, 720 struct rb_node *next = rb_first(&hists->entries);
600 bool color, u64 session_total) 721 struct hist_entry *n;
722 int row = 0;
723
724 hists__reset_col_len(hists);
725
726 while (next && row++ < max_rows) {
727 n = rb_entry(next, struct hist_entry, rb_node);
728 if (!n->filtered)
729 hists__calc_col_len(hists, n);
730 next = rb_next(&n->rb_node);
731 }
732}
733
734static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s,
735 size_t size, struct hists *pair_hists,
736 bool show_displacement, long displacement,
737 bool color, u64 session_total)
601{ 738{
602 struct sort_entry *se;
603 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; 739 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
604 u64 nr_events; 740 u64 nr_events;
605 const char *sep = symbol_conf.field_sep; 741 const char *sep = symbol_conf.field_sep;
@@ -664,6 +800,13 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
664 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events); 800 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
665 } 801 }
666 802
803 if (symbol_conf.show_total_period) {
804 if (sep)
805 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
806 else
807 ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
808 }
809
667 if (pair_hists) { 810 if (pair_hists) {
668 char bf[32]; 811 char bf[32];
669 double old_percent = 0, new_percent = 0, diff; 812 double old_percent = 0, new_percent = 0, diff;
@@ -698,26 +841,42 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
698 } 841 }
699 } 842 }
700 843
844 return ret;
845}
846
847int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
848 struct hists *hists)
849{
850 const char *sep = symbol_conf.field_sep;
851 struct sort_entry *se;
852 int ret = 0;
853
701 list_for_each_entry(se, &hist_entry__sort_list, list) { 854 list_for_each_entry(se, &hist_entry__sort_list, list) {
702 if (se->elide) 855 if (se->elide)
703 continue; 856 continue;
704 857
705 ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); 858 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
706 ret += se->se_snprintf(self, s + ret, size - ret, 859 ret += se->se_snprintf(he, s + ret, size - ret,
707 hists__col_len(hists, se->se_width_idx)); 860 hists__col_len(hists, se->se_width_idx));
708 } 861 }
709 862
710 return ret; 863 return ret;
711} 864}
712 865
713int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, 866int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
714 struct hists *pair_hists, bool show_displacement, 867 struct hists *pair_hists, bool show_displacement,
715 long displacement, FILE *fp, u64 session_total) 868 long displacement, FILE *fp, u64 session_total)
716{ 869{
717 char bf[512]; 870 char bf[512];
718 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists, 871 int ret;
719 show_displacement, displacement, 872
720 true, session_total); 873 if (size == 0 || size > sizeof(bf))
874 size = sizeof(bf);
875
876 ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists,
877 show_displacement, displacement,
878 true, session_total);
879 hist_entry__snprintf(he, bf + ret, size - ret, hists);
721 return fprintf(fp, "%s\n", bf); 880 return fprintf(fp, "%s\n", bf);
722} 881}
723 882
@@ -738,8 +897,9 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
738 left_margin); 897 left_margin);
739} 898}
740 899
741size_t hists__fprintf(struct hists *self, struct hists *pair, 900size_t hists__fprintf(struct hists *hists, struct hists *pair,
742 bool show_displacement, FILE *fp) 901 bool show_displacement, bool show_header, int max_rows,
902 int max_cols, FILE *fp)
743{ 903{
744 struct sort_entry *se; 904 struct sort_entry *se;
745 struct rb_node *nd; 905 struct rb_node *nd;
@@ -749,9 +909,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
749 unsigned int width; 909 unsigned int width;
750 const char *sep = symbol_conf.field_sep; 910 const char *sep = symbol_conf.field_sep;
751 const char *col_width = symbol_conf.col_width_list_str; 911 const char *col_width = symbol_conf.col_width_list_str;
912 int nr_rows = 0;
752 913
753 init_rem_hits(); 914 init_rem_hits();
754 915
916 if (!show_header)
917 goto print_entries;
918
755 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); 919 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
756 920
757 if (symbol_conf.show_nr_samples) { 921 if (symbol_conf.show_nr_samples) {
@@ -761,6 +925,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
761 fputs(" Samples ", fp); 925 fputs(" Samples ", fp);
762 } 926 }
763 927
928 if (symbol_conf.show_total_period) {
929 if (sep)
930 ret += fprintf(fp, "%cPeriod", *sep);
931 else
932 ret += fprintf(fp, " Period ");
933 }
934
764 if (symbol_conf.show_cpu_utilization) { 935 if (symbol_conf.show_cpu_utilization) {
765 if (sep) { 936 if (sep) {
766 ret += fprintf(fp, "%csys", *sep); 937 ret += fprintf(fp, "%csys", *sep);
@@ -803,18 +974,21 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
803 width = strlen(se->se_header); 974 width = strlen(se->se_header);
804 if (symbol_conf.col_width_list_str) { 975 if (symbol_conf.col_width_list_str) {
805 if (col_width) { 976 if (col_width) {
806 hists__set_col_len(self, se->se_width_idx, 977 hists__set_col_len(hists, se->se_width_idx,
807 atoi(col_width)); 978 atoi(col_width));
808 col_width = strchr(col_width, ','); 979 col_width = strchr(col_width, ',');
809 if (col_width) 980 if (col_width)
810 ++col_width; 981 ++col_width;
811 } 982 }
812 } 983 }
813 if (!hists__new_col_len(self, se->se_width_idx, width)) 984 if (!hists__new_col_len(hists, se->se_width_idx, width))
814 width = hists__col_len(self, se->se_width_idx); 985 width = hists__col_len(hists, se->se_width_idx);
815 fprintf(fp, " %*s", width, se->se_header); 986 fprintf(fp, " %*s", width, se->se_header);
816 } 987 }
988
817 fprintf(fp, "\n"); 989 fprintf(fp, "\n");
990 if (max_rows && ++nr_rows >= max_rows)
991 goto out;
818 992
819 if (sep) 993 if (sep)
820 goto print_entries; 994 goto print_entries;
@@ -822,6 +996,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
822 fprintf(fp, "# ........"); 996 fprintf(fp, "# ........");
823 if (symbol_conf.show_nr_samples) 997 if (symbol_conf.show_nr_samples)
824 fprintf(fp, " .........."); 998 fprintf(fp, " ..........");
999 if (symbol_conf.show_total_period)
1000 fprintf(fp, " ............");
825 if (pair) { 1001 if (pair) {
826 fprintf(fp, " .........."); 1002 fprintf(fp, " ..........");
827 if (show_displacement) 1003 if (show_displacement)
@@ -834,17 +1010,23 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
834 continue; 1010 continue;
835 1011
836 fprintf(fp, " "); 1012 fprintf(fp, " ");
837 width = hists__col_len(self, se->se_width_idx); 1013 width = hists__col_len(hists, se->se_width_idx);
838 if (width == 0) 1014 if (width == 0)
839 width = strlen(se->se_header); 1015 width = strlen(se->se_header);
840 for (i = 0; i < width; i++) 1016 for (i = 0; i < width; i++)
841 fprintf(fp, "."); 1017 fprintf(fp, ".");
842 } 1018 }
843 1019
844 fprintf(fp, "\n#\n"); 1020 fprintf(fp, "\n");
1021 if (max_rows && ++nr_rows >= max_rows)
1022 goto out;
1023
1024 fprintf(fp, "#\n");
1025 if (max_rows && ++nr_rows >= max_rows)
1026 goto out;
845 1027
846print_entries: 1028print_entries:
847 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1029 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
848 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1030 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
849 1031
850 if (h->filtered) 1032 if (h->filtered)
@@ -858,19 +1040,22 @@ print_entries:
858 displacement = 0; 1040 displacement = 0;
859 ++position; 1041 ++position;
860 } 1042 }
861 ret += hist_entry__fprintf(h, self, pair, show_displacement, 1043 ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
862 displacement, fp, self->stats.total_period); 1044 displacement, fp, hists->stats.total_period);
863 1045
864 if (symbol_conf.use_callchain) 1046 if (symbol_conf.use_callchain)
865 ret += hist_entry__fprintf_callchain(h, self, fp, 1047 ret += hist_entry__fprintf_callchain(h, hists, fp,
866 self->stats.total_period); 1048 hists->stats.total_period);
1049 if (max_rows && ++nr_rows >= max_rows)
1050 goto out;
1051
867 if (h->ms.map == NULL && verbose > 1) { 1052 if (h->ms.map == NULL && verbose > 1) {
868 __map_groups__fprintf_maps(&h->thread->mg, 1053 __map_groups__fprintf_maps(&h->thread->mg,
869 MAP__FUNCTION, verbose, fp); 1054 MAP__FUNCTION, verbose, fp);
870 fprintf(fp, "%.10s end\n", graph_dotted_line); 1055 fprintf(fp, "%.10s end\n", graph_dotted_line);
871 } 1056 }
872 } 1057 }
873 1058out:
874 free(rem_sq_bracket); 1059 free(rem_sq_bracket);
875 1060
876 return ret; 1061 return ret;
@@ -879,7 +1064,7 @@ print_entries:
879/* 1064/*
880 * See hists__fprintf to match the column widths 1065 * See hists__fprintf to match the column widths
881 */ 1066 */
882unsigned int hists__sort_list_width(struct hists *self) 1067unsigned int hists__sort_list_width(struct hists *hists)
883{ 1068{
884 struct sort_entry *se; 1069 struct sort_entry *se;
885 int ret = 9; /* total % */ 1070 int ret = 9; /* total % */
@@ -896,9 +1081,12 @@ unsigned int hists__sort_list_width(struct hists *self)
896 if (symbol_conf.show_nr_samples) 1081 if (symbol_conf.show_nr_samples)
897 ret += 11; 1082 ret += 11;
898 1083
1084 if (symbol_conf.show_total_period)
1085 ret += 13;
1086
899 list_for_each_entry(se, &hist_entry__sort_list, list) 1087 list_for_each_entry(se, &hist_entry__sort_list, list)
900 if (!se->elide) 1088 if (!se->elide)
901 ret += 2 + hists__col_len(self, se->se_width_idx); 1089 ret += 2 + hists__col_len(hists, se->se_width_idx);
902 1090
903 if (verbose) /* Addr + origin */ 1091 if (verbose) /* Addr + origin */
904 ret += 3 + BITS_PER_LONG / 4; 1092 ret += 3 + BITS_PER_LONG / 4;
@@ -906,63 +1094,84 @@ unsigned int hists__sort_list_width(struct hists *self)
906 return ret; 1094 return ret;
907} 1095}
908 1096
909static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h, 1097static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
910 enum hist_filter filter) 1098 enum hist_filter filter)
911{ 1099{
912 h->filtered &= ~(1 << filter); 1100 h->filtered &= ~(1 << filter);
913 if (h->filtered) 1101 if (h->filtered)
914 return; 1102 return;
915 1103
916 ++self->nr_entries; 1104 ++hists->nr_entries;
917 if (h->ms.unfolded) 1105 if (h->ms.unfolded)
918 self->nr_entries += h->nr_rows; 1106 hists->nr_entries += h->nr_rows;
919 h->row_offset = 0; 1107 h->row_offset = 0;
920 self->stats.total_period += h->period; 1108 hists->stats.total_period += h->period;
921 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; 1109 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
922 1110
923 hists__calc_col_len(self, h); 1111 hists__calc_col_len(hists, h);
924} 1112}
925 1113
926void hists__filter_by_dso(struct hists *self, const struct dso *dso) 1114
1115static bool hists__filter_entry_by_dso(struct hists *hists,
1116 struct hist_entry *he)
1117{
1118 if (hists->dso_filter != NULL &&
1119 (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) {
1120 he->filtered |= (1 << HIST_FILTER__DSO);
1121 return true;
1122 }
1123
1124 return false;
1125}
1126
1127void hists__filter_by_dso(struct hists *hists)
927{ 1128{
928 struct rb_node *nd; 1129 struct rb_node *nd;
929 1130
930 self->nr_entries = self->stats.total_period = 0; 1131 hists->nr_entries = hists->stats.total_period = 0;
931 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1132 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
932 hists__reset_col_len(self); 1133 hists__reset_col_len(hists);
933 1134
934 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1135 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
935 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1136 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
936 1137
937 if (symbol_conf.exclude_other && !h->parent) 1138 if (symbol_conf.exclude_other && !h->parent)
938 continue; 1139 continue;
939 1140
940 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) { 1141 if (hists__filter_entry_by_dso(hists, h))
941 h->filtered |= (1 << HIST_FILTER__DSO);
942 continue; 1142 continue;
943 }
944 1143
945 hists__remove_entry_filter(self, h, HIST_FILTER__DSO); 1144 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
946 } 1145 }
947} 1146}
948 1147
949void hists__filter_by_thread(struct hists *self, const struct thread *thread) 1148static bool hists__filter_entry_by_thread(struct hists *hists,
1149 struct hist_entry *he)
1150{
1151 if (hists->thread_filter != NULL &&
1152 he->thread != hists->thread_filter) {
1153 he->filtered |= (1 << HIST_FILTER__THREAD);
1154 return true;
1155 }
1156
1157 return false;
1158}
1159
1160void hists__filter_by_thread(struct hists *hists)
950{ 1161{
951 struct rb_node *nd; 1162 struct rb_node *nd;
952 1163
953 self->nr_entries = self->stats.total_period = 0; 1164 hists->nr_entries = hists->stats.total_period = 0;
954 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1165 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
955 hists__reset_col_len(self); 1166 hists__reset_col_len(hists);
956 1167
957 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1168 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
958 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1169 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
959 1170
960 if (thread != NULL && h->thread != thread) { 1171 if (hists__filter_entry_by_thread(hists, h))
961 h->filtered |= (1 << HIST_FILTER__THREAD);
962 continue; 1172 continue;
963 }
964 1173
965 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD); 1174 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
966 } 1175 }
967} 1176}
968 1177
@@ -976,13 +1185,13 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
976 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 1185 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
977} 1186}
978 1187
979void hists__inc_nr_events(struct hists *self, u32 type) 1188void hists__inc_nr_events(struct hists *hists, u32 type)
980{ 1189{
981 ++self->stats.nr_events[0]; 1190 ++hists->stats.nr_events[0];
982 ++self->stats.nr_events[type]; 1191 ++hists->stats.nr_events[type];
983} 1192}
984 1193
985size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) 1194size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
986{ 1195{
987 int i; 1196 int i;
988 size_t ret = 0; 1197 size_t ret = 0;
@@ -990,7 +1199,7 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
990 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 1199 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
991 const char *name; 1200 const char *name;
992 1201
993 if (self->stats.nr_events[i] == 0) 1202 if (hists->stats.nr_events[i] == 0)
994 continue; 1203 continue;
995 1204
996 name = perf_event__name(i); 1205 name = perf_event__name(i);
@@ -998,8 +1207,18 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
998 continue; 1207 continue;
999 1208
1000 ret += fprintf(fp, "%16s events: %10d\n", name, 1209 ret += fprintf(fp, "%16s events: %10d\n", name,
1001 self->stats.nr_events[i]); 1210 hists->stats.nr_events[i]);
1002 } 1211 }
1003 1212
1004 return ret; 1213 return ret;
1005} 1214}
1215
1216void hists__init(struct hists *hists)
1217{
1218 memset(hists, 0, sizeof(*hists));
1219 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1220 hists->entries_in = &hists->entries_in_array[0];
1221 hists->entries_collapsed = RB_ROOT;
1222 hists->entries = RB_ROOT;
1223 pthread_mutex_init(&hists->lock, NULL);
1224}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 3beb97c4d822..ff93ddc91c5c 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -2,6 +2,7 @@
2#define __PERF_HIST_H 2#define __PERF_HIST_H
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <pthread.h>
5#include "callchain.h" 6#include "callchain.h"
6 7
7extern struct callchain_param callchain_param; 8extern struct callchain_param callchain_param;
@@ -42,9 +43,18 @@ enum hist_column {
42 HISTC_NR_COLS, /* Last entry */ 43 HISTC_NR_COLS, /* Last entry */
43}; 44};
44 45
46struct thread;
47struct dso;
48
45struct hists { 49struct hists {
50 struct rb_root entries_in_array[2];
51 struct rb_root *entries_in;
46 struct rb_root entries; 52 struct rb_root entries;
53 struct rb_root entries_collapsed;
47 u64 nr_entries; 54 u64 nr_entries;
55 const struct thread *thread_filter;
56 const struct dso *dso_filter;
57 pthread_mutex_t lock;
48 struct events_stats stats; 58 struct events_stats stats;
49 u64 event_stream; 59 u64 event_stream;
50 u16 col_len[HISTC_NR_COLS]; 60 u16 col_len[HISTC_NR_COLS];
@@ -52,34 +62,42 @@ struct hists {
52 struct callchain_cursor callchain_cursor; 62 struct callchain_cursor callchain_cursor;
53}; 63};
54 64
65void hists__init(struct hists *hists);
66
55struct hist_entry *__hists__add_entry(struct hists *self, 67struct hist_entry *__hists__add_entry(struct hists *self,
56 struct addr_location *al, 68 struct addr_location *al,
57 struct symbol *parent, u64 period); 69 struct symbol *parent, u64 period);
58extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 70extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
59extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 71extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
60int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, 72int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
61 struct hists *pair_hists, bool show_displacement, 73 struct hists *pair_hists, bool show_displacement,
62 long displacement, FILE *fp, u64 total); 74 long displacement, FILE *fp, u64 session_total);
63int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, 75int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
64 struct hists *hists, struct hists *pair_hists, 76 struct hists *hists);
65 bool show_displacement, long displacement,
66 bool color, u64 total);
67void hist_entry__free(struct hist_entry *); 77void hist_entry__free(struct hist_entry *);
68 78
69void hists__output_resort(struct hists *self); 79void hists__output_resort(struct hists *self);
80void hists__output_resort_threaded(struct hists *hists);
70void hists__collapse_resort(struct hists *self); 81void hists__collapse_resort(struct hists *self);
82void hists__collapse_resort_threaded(struct hists *hists);
83
84void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
85void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
86 bool zap_kernel);
87void hists__output_recalc_col_len(struct hists *hists, int max_rows);
71 88
72void hists__inc_nr_events(struct hists *self, u32 type); 89void hists__inc_nr_events(struct hists *self, u32 type);
73size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 90size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
74 91
75size_t hists__fprintf(struct hists *self, struct hists *pair, 92size_t hists__fprintf(struct hists *self, struct hists *pair,
76 bool show_displacement, FILE *fp); 93 bool show_displacement, bool show_header,
94 int max_rows, int max_cols, FILE *fp);
77 95
78int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); 96int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
79int hist_entry__annotate(struct hist_entry *self, size_t privsize); 97int hist_entry__annotate(struct hist_entry *self, size_t privsize);
80 98
81void hists__filter_by_dso(struct hists *self, const struct dso *dso); 99void hists__filter_by_dso(struct hists *hists);
82void hists__filter_by_thread(struct hists *self, const struct thread *thread); 100void hists__filter_by_thread(struct hists *hists);
83 101
84u16 hists__col_len(struct hists *self, enum hist_column col); 102u16 hists__col_len(struct hists *self, enum hist_column col);
85void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 103void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
@@ -90,26 +108,33 @@ struct perf_evlist;
90#ifdef NO_NEWT_SUPPORT 108#ifdef NO_NEWT_SUPPORT
91static inline 109static inline
92int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, 110int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
93 const char *help __used) 111 const char *help __used,
112 void(*timer)(void *arg) __used,
113 void *arg __used,
114 int refresh __used)
94{ 115{
95 return 0; 116 return 0;
96} 117}
97 118
98static inline int hist_entry__tui_annotate(struct hist_entry *self __used, 119static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
99 int evidx __used) 120 int evidx __used,
121 int nr_events __used,
122 void(*timer)(void *arg) __used,
123 void *arg __used,
124 int delay_secs __used)
100{ 125{
101 return 0; 126 return 0;
102} 127}
103#define KEY_LEFT -1 128#define K_LEFT -1
104#define KEY_RIGHT -2 129#define K_RIGHT -2
105#else 130#else
106#include <newt.h> 131#include "ui/keysyms.h"
107int hist_entry__tui_annotate(struct hist_entry *self, int evidx); 132int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
108 133 void(*timer)(void *arg), void *arg, int delay_secs);
109#define KEY_LEFT NEWT_KEY_LEFT
110#define KEY_RIGHT NEWT_KEY_RIGHT
111 134
112int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help); 135int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
136 void(*timer)(void *arg), void *arg,
137 int refresh);
113#endif 138#endif
114 139
115unsigned int hists__sort_list_width(struct hists *self); 140unsigned int hists__sort_list_width(struct hists *self);
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
index 791f9dd27ebf..547628e97f3d 100644
--- a/tools/perf/util/include/linux/compiler.h
+++ b/tools/perf/util/include/linux/compiler.h
@@ -5,7 +5,9 @@
5#define __always_inline inline 5#define __always_inline inline
6#endif 6#endif
7#define __user 7#define __user
8#ifndef __attribute_const__
8#define __attribute_const__ 9#define __attribute_const__
10#endif
9 11
10#define __used __attribute__((__unused__)) 12#define __used __attribute__((__unused__))
11 13
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index a16ecab5229d..78284b13e808 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -18,6 +18,13 @@ static inline int is_anon_memory(const char *filename)
18 return strcmp(filename, "//anon") == 0; 18 return strcmp(filename, "//anon") == 0;
19} 19}
20 20
21static inline int is_no_dso_memory(const char *filename)
22{
23 return !strcmp(filename, "[stack]") ||
24 !strcmp(filename, "[vdso]") ||
25 !strcmp(filename, "[heap]");
26}
27
21void map__init(struct map *self, enum map_type type, 28void map__init(struct map *self, enum map_type type,
22 u64 start, u64 end, u64 pgoff, struct dso *dso) 29 u64 start, u64 end, u64 pgoff, struct dso *dso)
23{ 30{
@@ -42,9 +49,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
42 if (self != NULL) { 49 if (self != NULL) {
43 char newfilename[PATH_MAX]; 50 char newfilename[PATH_MAX];
44 struct dso *dso; 51 struct dso *dso;
45 int anon; 52 int anon, no_dso;
46 53
47 anon = is_anon_memory(filename); 54 anon = is_anon_memory(filename);
55 no_dso = is_no_dso_memory(filename);
48 56
49 if (anon) { 57 if (anon) {
50 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 58 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
@@ -57,12 +65,16 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
57 65
58 map__init(self, type, start, start + len, pgoff, dso); 66 map__init(self, type, start, start + len, pgoff, dso);
59 67
60 if (anon) { 68 if (anon || no_dso) {
61set_identity:
62 self->map_ip = self->unmap_ip = identity__map_ip; 69 self->map_ip = self->unmap_ip = identity__map_ip;
63 } else if (strcmp(filename, "[vdso]") == 0) { 70
64 dso__set_loaded(dso, self->type); 71 /*
65 goto set_identity; 72 * Set memory without DSO as loaded. All map__find_*
73 * functions still return NULL, and we avoid the
74 * unnecessary map__load warning.
75 */
76 if (no_dso)
77 dso__set_loaded(dso, self->type);
66 } 78 }
67 } 79 }
68 return self; 80 return self;
@@ -127,8 +139,8 @@ int map__load(struct map *self, symbol_filter_t filter)
127 139
128 if (len > sizeof(DSO__DELETED) && 140 if (len > sizeof(DSO__DELETED) &&
129 strcmp(name + real_len + 1, DSO__DELETED) == 0) { 141 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
130 pr_warning("%.*s was updated, restart the long " 142 pr_warning("%.*s was updated (is prelink enabled?). "
131 "running apps that use it!\n", 143 "Restart the long running apps that use it!\n",
132 (int)real_len, name); 144 (int)real_len, name);
133 } else { 145 } else {
134 pr_warning("no symbols found in %s, maybe install " 146 pr_warning("no symbols found in %s, maybe install "
@@ -220,55 +232,55 @@ u64 map__objdump_2ip(struct map *map, u64 addr)
220 return ip; 232 return ip;
221} 233}
222 234
223void map_groups__init(struct map_groups *self) 235void map_groups__init(struct map_groups *mg)
224{ 236{
225 int i; 237 int i;
226 for (i = 0; i < MAP__NR_TYPES; ++i) { 238 for (i = 0; i < MAP__NR_TYPES; ++i) {
227 self->maps[i] = RB_ROOT; 239 mg->maps[i] = RB_ROOT;
228 INIT_LIST_HEAD(&self->removed_maps[i]); 240 INIT_LIST_HEAD(&mg->removed_maps[i]);
229 } 241 }
230 self->machine = NULL; 242 mg->machine = NULL;
231} 243}
232 244
233static void maps__delete(struct rb_root *self) 245static void maps__delete(struct rb_root *maps)
234{ 246{
235 struct rb_node *next = rb_first(self); 247 struct rb_node *next = rb_first(maps);
236 248
237 while (next) { 249 while (next) {
238 struct map *pos = rb_entry(next, struct map, rb_node); 250 struct map *pos = rb_entry(next, struct map, rb_node);
239 251
240 next = rb_next(&pos->rb_node); 252 next = rb_next(&pos->rb_node);
241 rb_erase(&pos->rb_node, self); 253 rb_erase(&pos->rb_node, maps);
242 map__delete(pos); 254 map__delete(pos);
243 } 255 }
244} 256}
245 257
246static void maps__delete_removed(struct list_head *self) 258static void maps__delete_removed(struct list_head *maps)
247{ 259{
248 struct map *pos, *n; 260 struct map *pos, *n;
249 261
250 list_for_each_entry_safe(pos, n, self, node) { 262 list_for_each_entry_safe(pos, n, maps, node) {
251 list_del(&pos->node); 263 list_del(&pos->node);
252 map__delete(pos); 264 map__delete(pos);
253 } 265 }
254} 266}
255 267
256void map_groups__exit(struct map_groups *self) 268void map_groups__exit(struct map_groups *mg)
257{ 269{
258 int i; 270 int i;
259 271
260 for (i = 0; i < MAP__NR_TYPES; ++i) { 272 for (i = 0; i < MAP__NR_TYPES; ++i) {
261 maps__delete(&self->maps[i]); 273 maps__delete(&mg->maps[i]);
262 maps__delete_removed(&self->removed_maps[i]); 274 maps__delete_removed(&mg->removed_maps[i]);
263 } 275 }
264} 276}
265 277
266void map_groups__flush(struct map_groups *self) 278void map_groups__flush(struct map_groups *mg)
267{ 279{
268 int type; 280 int type;
269 281
270 for (type = 0; type < MAP__NR_TYPES; type++) { 282 for (type = 0; type < MAP__NR_TYPES; type++) {
271 struct rb_root *root = &self->maps[type]; 283 struct rb_root *root = &mg->maps[type];
272 struct rb_node *next = rb_first(root); 284 struct rb_node *next = rb_first(root);
273 285
274 while (next) { 286 while (next) {
@@ -280,17 +292,17 @@ void map_groups__flush(struct map_groups *self)
280 * instance in some hist_entry instances, so 292 * instance in some hist_entry instances, so
281 * just move them to a separate list. 293 * just move them to a separate list.
282 */ 294 */
283 list_add_tail(&pos->node, &self->removed_maps[pos->type]); 295 list_add_tail(&pos->node, &mg->removed_maps[pos->type]);
284 } 296 }
285 } 297 }
286} 298}
287 299
288struct symbol *map_groups__find_symbol(struct map_groups *self, 300struct symbol *map_groups__find_symbol(struct map_groups *mg,
289 enum map_type type, u64 addr, 301 enum map_type type, u64 addr,
290 struct map **mapp, 302 struct map **mapp,
291 symbol_filter_t filter) 303 symbol_filter_t filter)
292{ 304{
293 struct map *map = map_groups__find(self, type, addr); 305 struct map *map = map_groups__find(mg, type, addr);
294 306
295 if (map != NULL) { 307 if (map != NULL) {
296 if (mapp != NULL) 308 if (mapp != NULL)
@@ -301,7 +313,7 @@ struct symbol *map_groups__find_symbol(struct map_groups *self,
301 return NULL; 313 return NULL;
302} 314}
303 315
304struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, 316struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
305 enum map_type type, 317 enum map_type type,
306 const char *name, 318 const char *name,
307 struct map **mapp, 319 struct map **mapp,
@@ -309,7 +321,7 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
309{ 321{
310 struct rb_node *nd; 322 struct rb_node *nd;
311 323
312 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 324 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
313 struct map *pos = rb_entry(nd, struct map, rb_node); 325 struct map *pos = rb_entry(nd, struct map, rb_node);
314 struct symbol *sym = map__find_symbol_by_name(pos, name, filter); 326 struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
315 327
@@ -323,13 +335,13 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
323 return NULL; 335 return NULL;
324} 336}
325 337
326size_t __map_groups__fprintf_maps(struct map_groups *self, 338size_t __map_groups__fprintf_maps(struct map_groups *mg,
327 enum map_type type, int verbose, FILE *fp) 339 enum map_type type, int verbose, FILE *fp)
328{ 340{
329 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 341 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
330 struct rb_node *nd; 342 struct rb_node *nd;
331 343
332 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 344 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
333 struct map *pos = rb_entry(nd, struct map, rb_node); 345 struct map *pos = rb_entry(nd, struct map, rb_node);
334 printed += fprintf(fp, "Map:"); 346 printed += fprintf(fp, "Map:");
335 printed += map__fprintf(pos, fp); 347 printed += map__fprintf(pos, fp);
@@ -342,22 +354,22 @@ size_t __map_groups__fprintf_maps(struct map_groups *self,
342 return printed; 354 return printed;
343} 355}
344 356
345size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp) 357size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp)
346{ 358{
347 size_t printed = 0, i; 359 size_t printed = 0, i;
348 for (i = 0; i < MAP__NR_TYPES; ++i) 360 for (i = 0; i < MAP__NR_TYPES; ++i)
349 printed += __map_groups__fprintf_maps(self, i, verbose, fp); 361 printed += __map_groups__fprintf_maps(mg, i, verbose, fp);
350 return printed; 362 return printed;
351} 363}
352 364
353static size_t __map_groups__fprintf_removed_maps(struct map_groups *self, 365static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
354 enum map_type type, 366 enum map_type type,
355 int verbose, FILE *fp) 367 int verbose, FILE *fp)
356{ 368{
357 struct map *pos; 369 struct map *pos;
358 size_t printed = 0; 370 size_t printed = 0;
359 371
360 list_for_each_entry(pos, &self->removed_maps[type], node) { 372 list_for_each_entry(pos, &mg->removed_maps[type], node) {
361 printed += fprintf(fp, "Map:"); 373 printed += fprintf(fp, "Map:");
362 printed += map__fprintf(pos, fp); 374 printed += map__fprintf(pos, fp);
363 if (verbose > 1) { 375 if (verbose > 1) {
@@ -368,26 +380,26 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
368 return printed; 380 return printed;
369} 381}
370 382
371static size_t map_groups__fprintf_removed_maps(struct map_groups *self, 383static size_t map_groups__fprintf_removed_maps(struct map_groups *mg,
372 int verbose, FILE *fp) 384 int verbose, FILE *fp)
373{ 385{
374 size_t printed = 0, i; 386 size_t printed = 0, i;
375 for (i = 0; i < MAP__NR_TYPES; ++i) 387 for (i = 0; i < MAP__NR_TYPES; ++i)
376 printed += __map_groups__fprintf_removed_maps(self, i, verbose, fp); 388 printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp);
377 return printed; 389 return printed;
378} 390}
379 391
380size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp) 392size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp)
381{ 393{
382 size_t printed = map_groups__fprintf_maps(self, verbose, fp); 394 size_t printed = map_groups__fprintf_maps(mg, verbose, fp);
383 printed += fprintf(fp, "Removed maps:\n"); 395 printed += fprintf(fp, "Removed maps:\n");
384 return printed + map_groups__fprintf_removed_maps(self, verbose, fp); 396 return printed + map_groups__fprintf_removed_maps(mg, verbose, fp);
385} 397}
386 398
387int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, 399int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
388 int verbose, FILE *fp) 400 int verbose, FILE *fp)
389{ 401{
390 struct rb_root *root = &self->maps[map->type]; 402 struct rb_root *root = &mg->maps[map->type];
391 struct rb_node *next = rb_first(root); 403 struct rb_node *next = rb_first(root);
392 int err = 0; 404 int err = 0;
393 405
@@ -418,7 +430,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
418 } 430 }
419 431
420 before->end = map->start - 1; 432 before->end = map->start - 1;
421 map_groups__insert(self, before); 433 map_groups__insert(mg, before);
422 if (verbose >= 2) 434 if (verbose >= 2)
423 map__fprintf(before, fp); 435 map__fprintf(before, fp);
424 } 436 }
@@ -432,7 +444,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
432 } 444 }
433 445
434 after->start = map->end + 1; 446 after->start = map->end + 1;
435 map_groups__insert(self, after); 447 map_groups__insert(mg, after);
436 if (verbose >= 2) 448 if (verbose >= 2)
437 map__fprintf(after, fp); 449 map__fprintf(after, fp);
438 } 450 }
@@ -441,7 +453,7 @@ move_map:
441 * If we have references, just move them to a separate list. 453 * If we have references, just move them to a separate list.
442 */ 454 */
443 if (pos->referenced) 455 if (pos->referenced)
444 list_add_tail(&pos->node, &self->removed_maps[map->type]); 456 list_add_tail(&pos->node, &mg->removed_maps[map->type]);
445 else 457 else
446 map__delete(pos); 458 map__delete(pos);
447 459
@@ -455,7 +467,7 @@ move_map:
455/* 467/*
456 * XXX This should not really _copy_ te maps, but refcount them. 468 * XXX This should not really _copy_ te maps, but refcount them.
457 */ 469 */
458int map_groups__clone(struct map_groups *self, 470int map_groups__clone(struct map_groups *mg,
459 struct map_groups *parent, enum map_type type) 471 struct map_groups *parent, enum map_type type)
460{ 472{
461 struct rb_node *nd; 473 struct rb_node *nd;
@@ -464,7 +476,7 @@ int map_groups__clone(struct map_groups *self,
464 struct map *new = map__clone(map); 476 struct map *new = map__clone(map);
465 if (new == NULL) 477 if (new == NULL)
466 return -ENOMEM; 478 return -ENOMEM;
467 map_groups__insert(self, new); 479 map_groups__insert(mg, new);
468 } 480 }
469 return 0; 481 return 0;
470} 482}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index b397c0383728..890d85545d0f 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -123,17 +123,17 @@ void map__fixup_end(struct map *self);
123 123
124void map__reloc_vmlinux(struct map *self); 124void map__reloc_vmlinux(struct map *self);
125 125
126size_t __map_groups__fprintf_maps(struct map_groups *self, 126size_t __map_groups__fprintf_maps(struct map_groups *mg,
127 enum map_type type, int verbose, FILE *fp); 127 enum map_type type, int verbose, FILE *fp);
128void maps__insert(struct rb_root *maps, struct map *map); 128void maps__insert(struct rb_root *maps, struct map *map);
129void maps__remove(struct rb_root *self, struct map *map); 129void maps__remove(struct rb_root *maps, struct map *map);
130struct map *maps__find(struct rb_root *maps, u64 addr); 130struct map *maps__find(struct rb_root *maps, u64 addr);
131void map_groups__init(struct map_groups *self); 131void map_groups__init(struct map_groups *mg);
132void map_groups__exit(struct map_groups *self); 132void map_groups__exit(struct map_groups *mg);
133int map_groups__clone(struct map_groups *self, 133int map_groups__clone(struct map_groups *mg,
134 struct map_groups *parent, enum map_type type); 134 struct map_groups *parent, enum map_type type);
135size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); 135size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp);
136size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp); 136size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp);
137 137
138typedef void (*machine__process_t)(struct machine *self, void *data); 138typedef void (*machine__process_t)(struct machine *self, void *data);
139 139
@@ -162,29 +162,29 @@ static inline bool machine__is_host(struct machine *self)
162 return self ? self->pid == HOST_KERNEL_ID : false; 162 return self ? self->pid == HOST_KERNEL_ID : false;
163} 163}
164 164
165static inline void map_groups__insert(struct map_groups *self, struct map *map) 165static inline void map_groups__insert(struct map_groups *mg, struct map *map)
166{ 166{
167 maps__insert(&self->maps[map->type], map); 167 maps__insert(&mg->maps[map->type], map);
168 map->groups = self; 168 map->groups = mg;
169} 169}
170 170
171static inline void map_groups__remove(struct map_groups *self, struct map *map) 171static inline void map_groups__remove(struct map_groups *mg, struct map *map)
172{ 172{
173 maps__remove(&self->maps[map->type], map); 173 maps__remove(&mg->maps[map->type], map);
174} 174}
175 175
176static inline struct map *map_groups__find(struct map_groups *self, 176static inline struct map *map_groups__find(struct map_groups *mg,
177 enum map_type type, u64 addr) 177 enum map_type type, u64 addr)
178{ 178{
179 return maps__find(&self->maps[type], addr); 179 return maps__find(&mg->maps[type], addr);
180} 180}
181 181
182struct symbol *map_groups__find_symbol(struct map_groups *self, 182struct symbol *map_groups__find_symbol(struct map_groups *mg,
183 enum map_type type, u64 addr, 183 enum map_type type, u64 addr,
184 struct map **mapp, 184 struct map **mapp,
185 symbol_filter_t filter); 185 symbol_filter_t filter);
186 186
187struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, 187struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
188 enum map_type type, 188 enum map_type type,
189 const char *name, 189 const char *name,
190 struct map **mapp, 190 struct map **mapp,
@@ -208,11 +208,11 @@ struct symbol *machine__find_kernel_function(struct machine *self, u64 addr,
208} 208}
209 209
210static inline 210static inline
211struct symbol *map_groups__find_function_by_name(struct map_groups *self, 211struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
212 const char *name, struct map **mapp, 212 const char *name, struct map **mapp,
213 symbol_filter_t filter) 213 symbol_filter_t filter)
214{ 214{
215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); 215 return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter);
216} 216}
217 217
218static inline 218static inline
@@ -225,13 +225,13 @@ struct symbol *machine__find_kernel_function_by_name(struct machine *self,
225 filter); 225 filter);
226} 226}
227 227
228int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, 228int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
229 int verbose, FILE *fp); 229 int verbose, FILE *fp);
230 230
231struct map *map_groups__find_by_name(struct map_groups *self, 231struct map *map_groups__find_by_name(struct map_groups *mg,
232 enum map_type type, const char *name); 232 enum map_type type, const char *name);
233struct map *machine__new_module(struct machine *self, u64 start, const char *filename); 233struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
234 234
235void map_groups__flush(struct map_groups *self); 235void map_groups__flush(struct map_groups *mg);
236 236
237#endif /* __PERF_MAP_H */ 237#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 4ea7e19f5251..928918b796b2 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -697,7 +697,11 @@ parse_raw_event(const char **strp, struct perf_event_attr *attr)
697 return EVT_FAILED; 697 return EVT_FAILED;
698 n = hex2u64(str + 1, &config); 698 n = hex2u64(str + 1, &config);
699 if (n > 0) { 699 if (n > 0) {
700 *strp = str + n + 1; 700 const char *end = str + n + 1;
701 if (*end != '\0' && *end != ',' && *end != ':')
702 return EVT_FAILED;
703
704 *strp = end;
701 attr->type = PERF_TYPE_RAW; 705 attr->type = PERF_TYPE_RAW;
702 attr->config = config; 706 attr->config = config;
703 return EVT_HANDLED; 707 return EVT_HANDLED;
@@ -1097,6 +1101,4 @@ void print_events(const char *event_glob)
1097 printf("\n"); 1101 printf("\n");
1098 1102
1099 print_tracepoint_events(NULL, NULL); 1103 print_tracepoint_events(NULL, NULL);
1100
1101 exit(129);
1102} 1104}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index b82d54fa2c56..eb25900e2211 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1820,11 +1820,15 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1820 ret = -ENOMEM; 1820 ret = -ENOMEM;
1821 goto error; 1821 goto error;
1822 } 1822 }
1823 tev->point.module = strdup(module); 1823
1824 if (tev->point.module == NULL) { 1824 if (module) {
1825 ret = -ENOMEM; 1825 tev->point.module = strdup(module);
1826 goto error; 1826 if (tev->point.module == NULL) {
1827 ret = -ENOMEM;
1828 goto error;
1829 }
1827 } 1830 }
1831
1828 tev->point.offset = pev->point.offset; 1832 tev->point.offset = pev->point.offset;
1829 tev->point.retprobe = pev->point.retprobe; 1833 tev->point.retprobe = pev->point.retprobe;
1830 tev->nargs = pev->nargs; 1834 tev->nargs = pev->nargs;
@@ -1952,8 +1956,10 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
1952 1956
1953 pr_debug("Writing event: %s\n", buf); 1957 pr_debug("Writing event: %s\n", buf);
1954 ret = write(fd, buf, strlen(buf)); 1958 ret = write(fd, buf, strlen(buf));
1955 if (ret < 0) 1959 if (ret < 0) {
1960 ret = -errno;
1956 goto error; 1961 goto error;
1962 }
1957 1963
1958 printf("Remove event: %s\n", ent->s); 1964 printf("Remove event: %s\n", ent->s);
1959 return 0; 1965 return 0;
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 3e44a3e36519..5d732621a462 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -612,12 +612,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
612 return ret; 612 return ret;
613} 613}
614 614
615/* Find a variable in a subprogram die */ 615/* Find a variable in a scope DIE */
616static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 616static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
617{ 617{
618 Dwarf_Die vr_die, *scopes; 618 Dwarf_Die vr_die;
619 char buf[32], *ptr; 619 char buf[32], *ptr;
620 int ret, nscopes; 620 int ret = 0;
621 621
622 if (!is_c_varname(pf->pvar->var)) { 622 if (!is_c_varname(pf->pvar->var)) {
623 /* Copy raw parameters */ 623 /* Copy raw parameters */
@@ -652,30 +652,16 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
652 if (pf->tvar->name == NULL) 652 if (pf->tvar->name == NULL)
653 return -ENOMEM; 653 return -ENOMEM;
654 654
655 pr_debug("Searching '%s' variable in context.\n", 655 pr_debug("Searching '%s' variable in context.\n", pf->pvar->var);
656 pf->pvar->var);
657 /* Search child die for local variables and parameters. */ 656 /* Search child die for local variables and parameters. */
658 if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) 657 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
659 ret = convert_variable(&vr_die, pf); 658 /* Search again in global variables */
660 else { 659 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
661 /* Search upper class */ 660 ret = -ENOENT;
662 nscopes = dwarf_getscopes_die(sp_die, &scopes);
663 while (nscopes-- > 1) {
664 pr_debug("Searching variables in %s\n",
665 dwarf_diename(&scopes[nscopes]));
666 /* We should check this scope, so give dummy address */
667 if (die_find_variable_at(&scopes[nscopes],
668 pf->pvar->var, 0,
669 &vr_die)) {
670 ret = convert_variable(&vr_die, pf);
671 goto found;
672 }
673 }
674 if (scopes)
675 free(scopes);
676 ret = -ENOENT;
677 } 661 }
678found: 662 if (ret >= 0)
663 ret = convert_variable(&vr_die, pf);
664
679 if (ret < 0) 665 if (ret < 0)
680 pr_warning("Failed to find '%s' in this function.\n", 666 pr_warning("Failed to find '%s' in this function.\n",
681 pf->pvar->var); 667 pf->pvar->var);
@@ -718,26 +704,30 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
718 return 0; 704 return 0;
719} 705}
720 706
721/* Call probe_finder callback with real subprogram DIE */ 707/* Call probe_finder callback with scope DIE */
722static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) 708static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
723{ 709{
724 Dwarf_Die die_mem;
725 Dwarf_Attribute fb_attr; 710 Dwarf_Attribute fb_attr;
726 size_t nops; 711 size_t nops;
727 int ret; 712 int ret;
728 713
729 /* If no real subprogram, find a real one */ 714 if (!sc_die) {
730 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { 715 pr_err("Caller must pass a scope DIE. Program error.\n");
731 sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem); 716 return -EINVAL;
732 if (!sp_die) { 717 }
718
719 /* If not a real subprogram, find a real one */
720 if (dwarf_tag(sc_die) != DW_TAG_subprogram) {
721 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
733 pr_warning("Failed to find probe point in any " 722 pr_warning("Failed to find probe point in any "
734 "functions.\n"); 723 "functions.\n");
735 return -ENOENT; 724 return -ENOENT;
736 } 725 }
737 } 726 } else
727 memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die));
738 728
739 /* Get the frame base attribute/ops */ 729 /* Get the frame base attribute/ops from subprogram */
740 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 730 dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr);
741 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 731 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
742 if (ret <= 0 || nops == 0) { 732 if (ret <= 0 || nops == 0) {
743 pf->fb_ops = NULL; 733 pf->fb_ops = NULL;
@@ -755,7 +745,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
755 } 745 }
756 746
757 /* Call finder's callback handler */ 747 /* Call finder's callback handler */
758 ret = pf->callback(sp_die, pf); 748 ret = pf->callback(sc_die, pf);
759 749
760 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 750 /* *pf->fb_ops will be cached in libdw. Don't free it. */
761 pf->fb_ops = NULL; 751 pf->fb_ops = NULL;
@@ -763,17 +753,82 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
763 return ret; 753 return ret;
764} 754}
765 755
756struct find_scope_param {
757 const char *function;
758 const char *file;
759 int line;
760 int diff;
761 Dwarf_Die *die_mem;
762 bool found;
763};
764
765static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
766{
767 struct find_scope_param *fsp = data;
768 const char *file;
769 int lno;
770
771 /* Skip if declared file name does not match */
772 if (fsp->file) {
773 file = dwarf_decl_file(fn_die);
774 if (!file || strcmp(fsp->file, file) != 0)
775 return 0;
776 }
777 /* If the function name is given, that's what user expects */
778 if (fsp->function) {
779 if (die_compare_name(fn_die, fsp->function)) {
780 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
781 fsp->found = true;
782 return 1;
783 }
784 } else {
785 /* With the line number, find the nearest declared DIE */
786 dwarf_decl_line(fn_die, &lno);
787 if (lno < fsp->line && fsp->diff > fsp->line - lno) {
788 /* Keep a candidate and continue */
789 fsp->diff = fsp->line - lno;
790 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
791 fsp->found = true;
792 }
793 }
794 return 0;
795}
796
797/* Find an appropriate scope fits to given conditions */
798static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
799{
800 struct find_scope_param fsp = {
801 .function = pf->pev->point.function,
802 .file = pf->fname,
803 .line = pf->lno,
804 .diff = INT_MAX,
805 .die_mem = die_mem,
806 .found = false,
807 };
808
809 cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp);
810
811 return fsp.found ? die_mem : NULL;
812}
813
766static int probe_point_line_walker(const char *fname, int lineno, 814static int probe_point_line_walker(const char *fname, int lineno,
767 Dwarf_Addr addr, void *data) 815 Dwarf_Addr addr, void *data)
768{ 816{
769 struct probe_finder *pf = data; 817 struct probe_finder *pf = data;
818 Dwarf_Die *sc_die, die_mem;
770 int ret; 819 int ret;
771 820
772 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 821 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
773 return 0; 822 return 0;
774 823
775 pf->addr = addr; 824 pf->addr = addr;
776 ret = call_probe_finder(NULL, pf); 825 sc_die = find_best_scope(pf, &die_mem);
826 if (!sc_die) {
827 pr_warning("Failed to find scope of probe point.\n");
828 return -ENOENT;
829 }
830
831 ret = call_probe_finder(sc_die, pf);
777 832
778 /* Continue if no error, because the line will be in inline function */ 833 /* Continue if no error, because the line will be in inline function */
779 return ret < 0 ? ret : 0; 834 return ret < 0 ? ret : 0;
@@ -827,6 +882,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
827 Dwarf_Addr addr, void *data) 882 Dwarf_Addr addr, void *data)
828{ 883{
829 struct probe_finder *pf = data; 884 struct probe_finder *pf = data;
885 Dwarf_Die *sc_die, die_mem;
830 int ret; 886 int ret;
831 887
832 if (!line_list__has_line(&pf->lcache, lineno) || 888 if (!line_list__has_line(&pf->lcache, lineno) ||
@@ -836,7 +892,14 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
836 pr_debug("Probe line found: line:%d addr:0x%llx\n", 892 pr_debug("Probe line found: line:%d addr:0x%llx\n",
837 lineno, (unsigned long long)addr); 893 lineno, (unsigned long long)addr);
838 pf->addr = addr; 894 pf->addr = addr;
839 ret = call_probe_finder(NULL, pf); 895 pf->lno = lineno;
896 sc_die = find_best_scope(pf, &die_mem);
897 if (!sc_die) {
898 pr_warning("Failed to find scope of probe point.\n");
899 return -ENOENT;
900 }
901
902 ret = call_probe_finder(sc_die, pf);
840 903
841 /* 904 /*
842 * Continue if no error, because the lazy pattern will match 905 * Continue if no error, because the lazy pattern will match
@@ -861,42 +924,39 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
861 return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 924 return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
862} 925}
863 926
864/* Callback parameter with return value */
865struct dwarf_callback_param {
866 void *data;
867 int retval;
868};
869
870static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 927static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
871{ 928{
872 struct dwarf_callback_param *param = data; 929 struct probe_finder *pf = data;
873 struct probe_finder *pf = param->data;
874 struct perf_probe_point *pp = &pf->pev->point; 930 struct perf_probe_point *pp = &pf->pev->point;
875 Dwarf_Addr addr; 931 Dwarf_Addr addr;
932 int ret;
876 933
877 if (pp->lazy_line) 934 if (pp->lazy_line)
878 param->retval = find_probe_point_lazy(in_die, pf); 935 ret = find_probe_point_lazy(in_die, pf);
879 else { 936 else {
880 /* Get probe address */ 937 /* Get probe address */
881 if (dwarf_entrypc(in_die, &addr) != 0) { 938 if (dwarf_entrypc(in_die, &addr) != 0) {
882 pr_warning("Failed to get entry address of %s.\n", 939 pr_warning("Failed to get entry address of %s.\n",
883 dwarf_diename(in_die)); 940 dwarf_diename(in_die));
884 param->retval = -ENOENT; 941 return -ENOENT;
885 return DWARF_CB_ABORT;
886 } 942 }
887 pf->addr = addr; 943 pf->addr = addr;
888 pf->addr += pp->offset; 944 pf->addr += pp->offset;
889 pr_debug("found inline addr: 0x%jx\n", 945 pr_debug("found inline addr: 0x%jx\n",
890 (uintmax_t)pf->addr); 946 (uintmax_t)pf->addr);
891 947
892 param->retval = call_probe_finder(in_die, pf); 948 ret = call_probe_finder(in_die, pf);
893 if (param->retval < 0)
894 return DWARF_CB_ABORT;
895 } 949 }
896 950
897 return DWARF_CB_OK; 951 return ret;
898} 952}
899 953
954/* Callback parameter with return value for libdw */
955struct dwarf_callback_param {
956 void *data;
957 int retval;
958};
959
900/* Search function from function name */ 960/* Search function from function name */
901static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 961static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
902{ 962{
@@ -933,14 +993,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
933 /* TODO: Check the address in this function */ 993 /* TODO: Check the address in this function */
934 param->retval = call_probe_finder(sp_die, pf); 994 param->retval = call_probe_finder(sp_die, pf);
935 } 995 }
936 } else { 996 } else
937 struct dwarf_callback_param _param = {.data = (void *)pf,
938 .retval = 0};
939 /* Inlined function: search instances */ 997 /* Inlined function: search instances */
940 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, 998 param->retval = die_walk_instances(sp_die,
941 &_param); 999 probe_point_inline_cb, (void *)pf);
942 param->retval = _param.retval;
943 }
944 1000
945 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 1001 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
946} 1002}
@@ -1060,7 +1116,7 @@ found:
1060} 1116}
1061 1117
1062/* Add a found probe point into trace event list */ 1118/* Add a found probe point into trace event list */
1063static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) 1119static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1064{ 1120{
1065 struct trace_event_finder *tf = 1121 struct trace_event_finder *tf =
1066 container_of(pf, struct trace_event_finder, pf); 1122 container_of(pf, struct trace_event_finder, pf);
@@ -1075,8 +1131,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1075 } 1131 }
1076 tev = &tf->tevs[tf->ntevs++]; 1132 tev = &tf->tevs[tf->ntevs++];
1077 1133
1078 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, 1134 /* Trace point should be converted from subprogram DIE */
1079 &tev->point); 1135 ret = convert_to_trace_point(&pf->sp_die, pf->addr,
1136 pf->pev->point.retprobe, &tev->point);
1080 if (ret < 0) 1137 if (ret < 0)
1081 return ret; 1138 return ret;
1082 1139
@@ -1091,7 +1148,8 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1091 for (i = 0; i < pf->pev->nargs; i++) { 1148 for (i = 0; i < pf->pev->nargs; i++) {
1092 pf->pvar = &pf->pev->args[i]; 1149 pf->pvar = &pf->pev->args[i];
1093 pf->tvar = &tev->args[i]; 1150 pf->tvar = &tev->args[i];
1094 ret = find_variable(sp_die, pf); 1151 /* Variable should be found from scope DIE */
1152 ret = find_variable(sc_die, pf);
1095 if (ret != 0) 1153 if (ret != 0)
1096 return ret; 1154 return ret;
1097 } 1155 }
@@ -1159,13 +1217,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1159} 1217}
1160 1218
1161/* Add a found vars into available variables list */ 1219/* Add a found vars into available variables list */
1162static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) 1220static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
1163{ 1221{
1164 struct available_var_finder *af = 1222 struct available_var_finder *af =
1165 container_of(pf, struct available_var_finder, pf); 1223 container_of(pf, struct available_var_finder, pf);
1166 struct variable_list *vl; 1224 struct variable_list *vl;
1167 Dwarf_Die die_mem, *scopes = NULL; 1225 Dwarf_Die die_mem;
1168 int ret, nscopes; 1226 int ret;
1169 1227
1170 /* Check number of tevs */ 1228 /* Check number of tevs */
1171 if (af->nvls == af->max_vls) { 1229 if (af->nvls == af->max_vls) {
@@ -1174,8 +1232,9 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
1174 } 1232 }
1175 vl = &af->vls[af->nvls++]; 1233 vl = &af->vls[af->nvls++];
1176 1234
1177 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, 1235 /* Trace point should be converted from subprogram DIE */
1178 &vl->point); 1236 ret = convert_to_trace_point(&pf->sp_die, pf->addr,
1237 pf->pev->point.retprobe, &vl->point);
1179 if (ret < 0) 1238 if (ret < 0)
1180 return ret; 1239 return ret;
1181 1240
@@ -1187,19 +1246,14 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
1187 if (vl->vars == NULL) 1246 if (vl->vars == NULL)
1188 return -ENOMEM; 1247 return -ENOMEM;
1189 af->child = true; 1248 af->child = true;
1190 die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); 1249 die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem);
1191 1250
1192 /* Find external variables */ 1251 /* Find external variables */
1193 if (!af->externs) 1252 if (!af->externs)
1194 goto out; 1253 goto out;
1195 /* Don't need to search child DIE for externs. */ 1254 /* Don't need to search child DIE for externs. */
1196 af->child = false; 1255 af->child = false;
1197 nscopes = dwarf_getscopes_die(sp_die, &scopes); 1256 die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem);
1198 while (nscopes-- > 1)
1199 die_find_child(&scopes[nscopes], collect_variables_cb,
1200 (void *)af, &die_mem);
1201 if (scopes)
1202 free(scopes);
1203 1257
1204out: 1258out:
1205 if (strlist__empty(vl->vars)) { 1259 if (strlist__empty(vl->vars)) {
@@ -1391,10 +1445,14 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1391 1445
1392static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1446static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
1393{ 1447{
1394 struct dwarf_callback_param *param = data; 1448 find_line_range_by_line(in_die, data);
1395 1449
1396 param->retval = find_line_range_by_line(in_die, param->data); 1450 /*
1397 return DWARF_CB_ABORT; /* No need to find other instances */ 1451 * We have to check all instances of inlined function, because
1452 * some execution paths can be optimized out depends on the
1453 * function argument of instances
1454 */
1455 return 0;
1398} 1456}
1399 1457
1400/* Search function from function name */ 1458/* Search function from function name */
@@ -1422,15 +1480,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1422 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1480 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
1423 lr->start = lf->lno_s; 1481 lr->start = lf->lno_s;
1424 lr->end = lf->lno_e; 1482 lr->end = lf->lno_e;
1425 if (dwarf_func_inline(sp_die)) { 1483 if (dwarf_func_inline(sp_die))
1426 struct dwarf_callback_param _param; 1484 param->retval = die_walk_instances(sp_die,
1427 _param.data = (void *)lf; 1485 line_range_inline_cb, lf);
1428 _param.retval = 0; 1486 else
1429 dwarf_func_inline_instances(sp_die,
1430 line_range_inline_cb,
1431 &_param);
1432 param->retval = _param.retval;
1433 } else
1434 param->retval = find_line_range_by_line(sp_die, lf); 1487 param->retval = find_line_range_by_line(sp_die, lf);
1435 return DWARF_CB_ABORT; 1488 return DWARF_CB_ABORT;
1436 } 1489 }
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index c478b42a2473..1132c8f0ce89 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -57,7 +57,7 @@ struct probe_finder {
57 struct perf_probe_event *pev; /* Target probe event */ 57 struct perf_probe_event *pev; /* Target probe event */
58 58
59 /* Callback when a probe point is found */ 59 /* Callback when a probe point is found */
60 int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf); 60 int (*callback)(Dwarf_Die *sc_die, struct probe_finder *pf);
61 61
62 /* For function searching */ 62 /* For function searching */
63 int lno; /* Line number */ 63 int lno; /* Line number */
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 8e0b5a39d8a7..7624324efad4 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -187,16 +187,119 @@ static PyTypeObject pyrf_throttle_event__type = {
187 .tp_repr = (reprfunc)pyrf_throttle_event__repr, 187 .tp_repr = (reprfunc)pyrf_throttle_event__repr,
188}; 188};
189 189
190static char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object.");
191
192static PyMemberDef pyrf_lost_event__members[] = {
193 sample_members
194 member_def(lost_event, id, T_ULONGLONG, "event id"),
195 member_def(lost_event, lost, T_ULONGLONG, "number of lost events"),
196 { .name = NULL, },
197};
198
199static PyObject *pyrf_lost_event__repr(struct pyrf_event *pevent)
200{
201 PyObject *ret;
202 char *s;
203
204 if (asprintf(&s, "{ type: lost, id: %#" PRIx64 ", "
205 "lost: %#" PRIx64 " }",
206 pevent->event.lost.id, pevent->event.lost.lost) < 0) {
207 ret = PyErr_NoMemory();
208 } else {
209 ret = PyString_FromString(s);
210 free(s);
211 }
212 return ret;
213}
214
215static PyTypeObject pyrf_lost_event__type = {
216 PyVarObject_HEAD_INIT(NULL, 0)
217 .tp_name = "perf.lost_event",
218 .tp_basicsize = sizeof(struct pyrf_event),
219 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
220 .tp_doc = pyrf_lost_event__doc,
221 .tp_members = pyrf_lost_event__members,
222 .tp_repr = (reprfunc)pyrf_lost_event__repr,
223};
224
225static char pyrf_read_event__doc[] = PyDoc_STR("perf read event object.");
226
227static PyMemberDef pyrf_read_event__members[] = {
228 sample_members
229 member_def(read_event, pid, T_UINT, "event pid"),
230 member_def(read_event, tid, T_UINT, "event tid"),
231 { .name = NULL, },
232};
233
234static PyObject *pyrf_read_event__repr(struct pyrf_event *pevent)
235{
236 return PyString_FromFormat("{ type: read, pid: %u, tid: %u }",
237 pevent->event.read.pid,
238 pevent->event.read.tid);
239 /*
240 * FIXME: return the array of read values,
241 * making this method useful ;-)
242 */
243}
244
245static PyTypeObject pyrf_read_event__type = {
246 PyVarObject_HEAD_INIT(NULL, 0)
247 .tp_name = "perf.read_event",
248 .tp_basicsize = sizeof(struct pyrf_event),
249 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
250 .tp_doc = pyrf_read_event__doc,
251 .tp_members = pyrf_read_event__members,
252 .tp_repr = (reprfunc)pyrf_read_event__repr,
253};
254
255static char pyrf_sample_event__doc[] = PyDoc_STR("perf sample event object.");
256
257static PyMemberDef pyrf_sample_event__members[] = {
258 sample_members
259 member_def(perf_event_header, type, T_UINT, "event type"),
260 { .name = NULL, },
261};
262
263static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent)
264{
265 PyObject *ret;
266 char *s;
267
268 if (asprintf(&s, "{ type: sample }") < 0) {
269 ret = PyErr_NoMemory();
270 } else {
271 ret = PyString_FromString(s);
272 free(s);
273 }
274 return ret;
275}
276
277static PyTypeObject pyrf_sample_event__type = {
278 PyVarObject_HEAD_INIT(NULL, 0)
279 .tp_name = "perf.sample_event",
280 .tp_basicsize = sizeof(struct pyrf_event),
281 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
282 .tp_doc = pyrf_sample_event__doc,
283 .tp_members = pyrf_sample_event__members,
284 .tp_repr = (reprfunc)pyrf_sample_event__repr,
285};
286
190static int pyrf_event__setup_types(void) 287static int pyrf_event__setup_types(void)
191{ 288{
192 int err; 289 int err;
193 pyrf_mmap_event__type.tp_new = 290 pyrf_mmap_event__type.tp_new =
194 pyrf_task_event__type.tp_new = 291 pyrf_task_event__type.tp_new =
195 pyrf_comm_event__type.tp_new = 292 pyrf_comm_event__type.tp_new =
293 pyrf_lost_event__type.tp_new =
294 pyrf_read_event__type.tp_new =
295 pyrf_sample_event__type.tp_new =
196 pyrf_throttle_event__type.tp_new = PyType_GenericNew; 296 pyrf_throttle_event__type.tp_new = PyType_GenericNew;
197 err = PyType_Ready(&pyrf_mmap_event__type); 297 err = PyType_Ready(&pyrf_mmap_event__type);
198 if (err < 0) 298 if (err < 0)
199 goto out; 299 goto out;
300 err = PyType_Ready(&pyrf_lost_event__type);
301 if (err < 0)
302 goto out;
200 err = PyType_Ready(&pyrf_task_event__type); 303 err = PyType_Ready(&pyrf_task_event__type);
201 if (err < 0) 304 if (err < 0)
202 goto out; 305 goto out;
@@ -206,20 +309,26 @@ static int pyrf_event__setup_types(void)
206 err = PyType_Ready(&pyrf_throttle_event__type); 309 err = PyType_Ready(&pyrf_throttle_event__type);
207 if (err < 0) 310 if (err < 0)
208 goto out; 311 goto out;
312 err = PyType_Ready(&pyrf_read_event__type);
313 if (err < 0)
314 goto out;
315 err = PyType_Ready(&pyrf_sample_event__type);
316 if (err < 0)
317 goto out;
209out: 318out:
210 return err; 319 return err;
211} 320}
212 321
213static PyTypeObject *pyrf_event__type[] = { 322static PyTypeObject *pyrf_event__type[] = {
214 [PERF_RECORD_MMAP] = &pyrf_mmap_event__type, 323 [PERF_RECORD_MMAP] = &pyrf_mmap_event__type,
215 [PERF_RECORD_LOST] = &pyrf_mmap_event__type, 324 [PERF_RECORD_LOST] = &pyrf_lost_event__type,
216 [PERF_RECORD_COMM] = &pyrf_comm_event__type, 325 [PERF_RECORD_COMM] = &pyrf_comm_event__type,
217 [PERF_RECORD_EXIT] = &pyrf_task_event__type, 326 [PERF_RECORD_EXIT] = &pyrf_task_event__type,
218 [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type, 327 [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type,
219 [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type, 328 [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type,
220 [PERF_RECORD_FORK] = &pyrf_task_event__type, 329 [PERF_RECORD_FORK] = &pyrf_task_event__type,
221 [PERF_RECORD_READ] = &pyrf_mmap_event__type, 330 [PERF_RECORD_READ] = &pyrf_read_event__type,
222 [PERF_RECORD_SAMPLE] = &pyrf_mmap_event__type, 331 [PERF_RECORD_SAMPLE] = &pyrf_sample_event__type,
223}; 332};
224 333
225static PyObject *pyrf_event__new(union perf_event *event) 334static PyObject *pyrf_event__new(union perf_event *event)
@@ -694,7 +803,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
694 first = list_entry(evlist->entries.next, struct perf_evsel, node); 803 first = list_entry(evlist->entries.next, struct perf_evsel, node);
695 err = perf_event__parse_sample(event, first->attr.sample_type, 804 err = perf_event__parse_sample(event, first->attr.sample_type,
696 perf_evsel__sample_size(first), 805 perf_evsel__sample_size(first),
697 sample_id_all, &pevent->sample); 806 sample_id_all, &pevent->sample, false);
698 if (err) 807 if (err)
699 return PyErr_Format(PyExc_OSError, 808 return PyErr_Format(PyExc_OSError,
700 "perf: can't parse sample, err=%d", err); 809 "perf: can't parse sample, err=%d", err);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 72458d9da5b1..20e011c99a94 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1326,3 +1326,22 @@ int perf_session__cpu_bitmap(struct perf_session *session,
1326 1326
1327 return 0; 1327 return 0;
1328} 1328}
1329
1330void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
1331 bool full)
1332{
1333 struct stat st;
1334 int ret;
1335
1336 if (session == NULL || fp == NULL)
1337 return;
1338
1339 ret = fstat(session->fd, &st);
1340 if (ret == -1)
1341 return;
1342
1343 fprintf(fp, "# ========\n");
1344 fprintf(fp, "# captured on: %s", ctime(&st.st_ctime));
1345 perf_header__fprintf_info(session, fp, full);
1346 fprintf(fp, "# ========\n#\n");
1347}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 170601e67d6b..514b06d41f05 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -162,7 +162,8 @@ static inline int perf_session__parse_sample(struct perf_session *session,
162{ 162{
163 return perf_event__parse_sample(event, session->sample_type, 163 return perf_event__parse_sample(event, session->sample_type,
164 session->sample_size, 164 session->sample_size,
165 session->sample_id_all, sample); 165 session->sample_id_all, sample,
166 session->header.needs_swap);
166} 167}
167 168
168struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 169struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
@@ -176,4 +177,5 @@ void perf_session__print_ip(union perf_event *event,
176int perf_session__cpu_bitmap(struct perf_session *session, 177int perf_session__cpu_bitmap(struct perf_session *session,
177 const char *cpu_list, unsigned long *cpu_bitmap); 178 const char *cpu_list, unsigned long *cpu_bitmap);
178 179
180void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full);
179#endif /* __PERF_SESSION_H */ 181#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index bbc982f5dd8b..95d370074928 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -3,9 +3,27 @@
3from distutils.core import setup, Extension 3from distutils.core import setup, Extension
4from os import getenv 4from os import getenv
5 5
6from distutils.command.build_ext import build_ext as _build_ext
7from distutils.command.install_lib import install_lib as _install_lib
8
9class build_ext(_build_ext):
10 def finalize_options(self):
11 _build_ext.finalize_options(self)
12 self.build_lib = build_lib
13 self.build_temp = build_tmp
14
15class install_lib(_install_lib):
16 def finalize_options(self):
17 _install_lib.finalize_options(self)
18 self.build_dir = build_lib
19
20
6cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] 21cflags = ['-fno-strict-aliasing', '-Wno-write-strings']
7cflags += getenv('CFLAGS', '').split() 22cflags += getenv('CFLAGS', '').split()
8 23
24build_lib = getenv('PYTHON_EXTBUILD_LIB')
25build_tmp = getenv('PYTHON_EXTBUILD_TMP')
26
9perf = Extension('perf', 27perf = Extension('perf',
10 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', 28 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
11 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', 29 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
@@ -21,4 +39,5 @@ setup(name='perf',
21 author_email='acme@redhat.com', 39 author_email='acme@redhat.com',
22 license='GPLv2', 40 license='GPLv2',
23 url='http://perf.wiki.kernel.org', 41 url='http://perf.wiki.kernel.org',
24 ext_modules=[perf]) 42 ext_modules=[perf],
43 cmdclass={'build_ext': build_ext, 'install_lib': install_lib})
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 401e220566fd..16da30d8d765 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -151,11 +151,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
151{ 151{
152 u64 ip_l, ip_r; 152 u64 ip_l, ip_r;
153 153
154 if (!left->ms.sym && !right->ms.sym)
155 return right->level - left->level;
156
157 if (!left->ms.sym || !right->ms.sym)
158 return cmp_null(left->ms.sym, right->ms.sym);
159
154 if (left->ms.sym == right->ms.sym) 160 if (left->ms.sym == right->ms.sym)
155 return 0; 161 return 0;
156 162
157 ip_l = left->ms.sym ? left->ms.sym->start : left->ip; 163 ip_l = left->ms.sym->start;
158 ip_r = right->ms.sym ? right->ms.sym->start : right->ip; 164 ip_r = right->ms.sym->start;
159 165
160 return (int64_t)(ip_r - ip_l); 166 return (int64_t)(ip_r - ip_l);
161} 167}
@@ -171,7 +177,9 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
171 BITS_PER_LONG / 4, self->ip, o); 177 BITS_PER_LONG / 4, self->ip, o);
172 } 178 }
173 179
174 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level); 180 if (!sort_dso.elide)
181 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
182
175 if (self->ms.sym) 183 if (self->ms.sym)
176 ret += repsep_snprintf(bf + ret, size - ret, "%s", 184 ret += repsep_snprintf(bf + ret, size - ret, "%s",
177 self->ms.sym->name); 185 self->ms.sym->name);
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 77d0388ad415..3f67ae395752 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -45,6 +45,7 @@ extern enum sort_type sort__first_dimension;
45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding 45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding
46 */ 46 */
47struct hist_entry { 47struct hist_entry {
48 struct rb_node rb_node_in;
48 struct rb_node rb_node; 49 struct rb_node rb_node;
49 u64 period; 50 u64 period;
50 u64 period_sys; 51 u64 period_sys;
@@ -63,6 +64,7 @@ struct hist_entry {
63 64
64 bool init_have_children; 65 bool init_have_children;
65 char level; 66 char level;
67 bool used;
66 u8 filtered; 68 u8 filtered;
67 struct symbol *parent; 69 struct symbol *parent;
68 union { 70 union {
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index eec196329fd9..632b50c7bc26 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -24,7 +24,7 @@
24#include <sys/utsname.h> 24#include <sys/utsname.h>
25 25
26#ifndef KSYM_NAME_LEN 26#ifndef KSYM_NAME_LEN
27#define KSYM_NAME_LEN 128 27#define KSYM_NAME_LEN 256
28#endif 28#endif
29 29
30#ifndef NT_GNU_BUILD_ID 30#ifndef NT_GNU_BUILD_ID
@@ -46,6 +46,7 @@ struct symbol_conf symbol_conf = {
46 .exclude_other = true, 46 .exclude_other = true,
47 .use_modules = true, 47 .use_modules = true,
48 .try_vmlinux_path = true, 48 .try_vmlinux_path = true,
49 .annotate_src = true,
49 .symfs = "", 50 .symfs = "",
50}; 51};
51 52
@@ -74,16 +75,104 @@ static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
74 75
75bool symbol_type__is_a(char symbol_type, enum map_type map_type) 76bool symbol_type__is_a(char symbol_type, enum map_type map_type)
76{ 77{
78 symbol_type = toupper(symbol_type);
79
77 switch (map_type) { 80 switch (map_type) {
78 case MAP__FUNCTION: 81 case MAP__FUNCTION:
79 return symbol_type == 'T' || symbol_type == 'W'; 82 return symbol_type == 'T' || symbol_type == 'W';
80 case MAP__VARIABLE: 83 case MAP__VARIABLE:
81 return symbol_type == 'D' || symbol_type == 'd'; 84 return symbol_type == 'D';
82 default: 85 default:
83 return false; 86 return false;
84 } 87 }
85} 88}
86 89
90static int prefix_underscores_count(const char *str)
91{
92 const char *tail = str;
93
94 while (*tail == '_')
95 tail++;
96
97 return tail - str;
98}
99
100#define SYMBOL_A 0
101#define SYMBOL_B 1
102
103static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
104{
105 s64 a;
106 s64 b;
107
108 /* Prefer a symbol with non zero length */
109 a = syma->end - syma->start;
110 b = symb->end - symb->start;
111 if ((b == 0) && (a > 0))
112 return SYMBOL_A;
113 else if ((a == 0) && (b > 0))
114 return SYMBOL_B;
115
116 /* Prefer a non weak symbol over a weak one */
117 a = syma->binding == STB_WEAK;
118 b = symb->binding == STB_WEAK;
119 if (b && !a)
120 return SYMBOL_A;
121 if (a && !b)
122 return SYMBOL_B;
123
124 /* Prefer a global symbol over a non global one */
125 a = syma->binding == STB_GLOBAL;
126 b = symb->binding == STB_GLOBAL;
127 if (a && !b)
128 return SYMBOL_A;
129 if (b && !a)
130 return SYMBOL_B;
131
132 /* Prefer a symbol with less underscores */
133 a = prefix_underscores_count(syma->name);
134 b = prefix_underscores_count(symb->name);
135 if (b > a)
136 return SYMBOL_A;
137 else if (a > b)
138 return SYMBOL_B;
139
140 /* If all else fails, choose the symbol with the longest name */
141 if (strlen(syma->name) >= strlen(symb->name))
142 return SYMBOL_A;
143 else
144 return SYMBOL_B;
145}
146
147static void symbols__fixup_duplicate(struct rb_root *symbols)
148{
149 struct rb_node *nd;
150 struct symbol *curr, *next;
151
152 nd = rb_first(symbols);
153
154 while (nd) {
155 curr = rb_entry(nd, struct symbol, rb_node);
156again:
157 nd = rb_next(&curr->rb_node);
158 next = rb_entry(nd, struct symbol, rb_node);
159
160 if (!nd)
161 break;
162
163 if (curr->start != next->start)
164 continue;
165
166 if (choose_best_symbol(curr, next) == SYMBOL_A) {
167 rb_erase(&next->rb_node, symbols);
168 goto again;
169 } else {
170 nd = rb_next(&curr->rb_node);
171 rb_erase(&curr->rb_node, symbols);
172 }
173 }
174}
175
87static void symbols__fixup_end(struct rb_root *symbols) 176static void symbols__fixup_end(struct rb_root *symbols)
88{ 177{
89 struct rb_node *nd, *prevnd = rb_first(symbols); 178 struct rb_node *nd, *prevnd = rb_first(symbols);
@@ -438,18 +527,11 @@ int kallsyms__parse(const char *filename, void *arg,
438 char *line = NULL; 527 char *line = NULL;
439 size_t n; 528 size_t n;
440 int err = -1; 529 int err = -1;
441 u64 prev_start = 0;
442 char prev_symbol_type = 0;
443 char *prev_symbol_name;
444 FILE *file = fopen(filename, "r"); 530 FILE *file = fopen(filename, "r");
445 531
446 if (file == NULL) 532 if (file == NULL)
447 goto out_failure; 533 goto out_failure;
448 534
449 prev_symbol_name = malloc(KSYM_NAME_LEN);
450 if (prev_symbol_name == NULL)
451 goto out_close;
452
453 err = 0; 535 err = 0;
454 536
455 while (!feof(file)) { 537 while (!feof(file)) {
@@ -470,7 +552,7 @@ int kallsyms__parse(const char *filename, void *arg,
470 if (len + 2 >= line_len) 552 if (len + 2 >= line_len)
471 continue; 553 continue;
472 554
473 symbol_type = toupper(line[len]); 555 symbol_type = line[len];
474 len += 2; 556 len += 2;
475 symbol_name = line + len; 557 symbol_name = line + len;
476 len = line_len - len; 558 len = line_len - len;
@@ -480,24 +562,18 @@ int kallsyms__parse(const char *filename, void *arg,
480 break; 562 break;
481 } 563 }
482 564
483 if (prev_symbol_type) { 565 /*
484 u64 end = start; 566 * module symbols are not sorted so we add all
485 if (end != prev_start) 567 * symbols with zero length and rely on
486 --end; 568 * symbols__fixup_end() to fix it up.
487 err = process_symbol(arg, prev_symbol_name, 569 */
488 prev_symbol_type, prev_start, end); 570 err = process_symbol(arg, symbol_name,
489 if (err) 571 symbol_type, start, start);
490 break; 572 if (err)
491 } 573 break;
492
493 memcpy(prev_symbol_name, symbol_name, len + 1);
494 prev_symbol_type = symbol_type;
495 prev_start = start;
496 } 574 }
497 575
498 free(prev_symbol_name);
499 free(line); 576 free(line);
500out_close:
501 fclose(file); 577 fclose(file);
502 return err; 578 return err;
503 579
@@ -703,6 +779,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
703 if (dso__load_all_kallsyms(dso, filename, map) < 0) 779 if (dso__load_all_kallsyms(dso, filename, map) < 0)
704 return -1; 780 return -1;
705 781
782 symbols__fixup_duplicate(&dso->symbols[map->type]);
783 symbols__fixup_end(&dso->symbols[map->type]);
784
706 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 785 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
707 dso->symtab_type = SYMTAB__GUEST_KALLSYMS; 786 dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
708 else 787 else
@@ -1092,8 +1171,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1092 if (dso->has_build_id) { 1171 if (dso->has_build_id) {
1093 u8 build_id[BUILD_ID_SIZE]; 1172 u8 build_id[BUILD_ID_SIZE];
1094 1173
1095 if (elf_read_build_id(elf, build_id, 1174 if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
1096 BUILD_ID_SIZE) != BUILD_ID_SIZE)
1097 goto out_elf_end; 1175 goto out_elf_end;
1098 1176
1099 if (!dso__build_id_equal(dso, build_id)) 1177 if (!dso__build_id_equal(dso, build_id))
@@ -1111,6 +1189,8 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1111 } 1189 }
1112 1190
1113 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); 1191 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
1192 if (opdshdr.sh_type != SHT_PROGBITS)
1193 opdsec = NULL;
1114 if (opdsec) 1194 if (opdsec)
1115 opddata = elf_rawdata(opdsec, NULL); 1195 opddata = elf_rawdata(opdsec, NULL);
1116 1196
@@ -1276,6 +1356,7 @@ new_symbol:
1276 * For misannotated, zeroed, ASM function sizes. 1356 * For misannotated, zeroed, ASM function sizes.
1277 */ 1357 */
1278 if (nr > 0) { 1358 if (nr > 0) {
1359 symbols__fixup_duplicate(&dso->symbols[map->type]);
1279 symbols__fixup_end(&dso->symbols[map->type]); 1360 symbols__fixup_end(&dso->symbols[map->type]);
1280 if (kmap) { 1361 if (kmap) {
1281 /* 1362 /*
@@ -1362,8 +1443,8 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
1362 ptr = data->d_buf; 1443 ptr = data->d_buf;
1363 while (ptr < (data->d_buf + data->d_size)) { 1444 while (ptr < (data->d_buf + data->d_size)) {
1364 GElf_Nhdr *nhdr = ptr; 1445 GElf_Nhdr *nhdr = ptr;
1365 int namesz = NOTE_ALIGN(nhdr->n_namesz), 1446 size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
1366 descsz = NOTE_ALIGN(nhdr->n_descsz); 1447 descsz = NOTE_ALIGN(nhdr->n_descsz);
1367 const char *name; 1448 const char *name;
1368 1449
1369 ptr += sizeof(*nhdr); 1450 ptr += sizeof(*nhdr);
@@ -1372,8 +1453,10 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
1372 if (nhdr->n_type == NT_GNU_BUILD_ID && 1453 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1373 nhdr->n_namesz == sizeof("GNU")) { 1454 nhdr->n_namesz == sizeof("GNU")) {
1374 if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1455 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1375 memcpy(bf, ptr, BUILD_ID_SIZE); 1456 size_t sz = min(size, descsz);
1376 err = BUILD_ID_SIZE; 1457 memcpy(bf, ptr, sz);
1458 memset(bf + sz, 0, size - sz);
1459 err = descsz;
1377 break; 1460 break;
1378 } 1461 }
1379 } 1462 }
@@ -1425,7 +1508,7 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1425 while (1) { 1508 while (1) {
1426 char bf[BUFSIZ]; 1509 char bf[BUFSIZ];
1427 GElf_Nhdr nhdr; 1510 GElf_Nhdr nhdr;
1428 int namesz, descsz; 1511 size_t namesz, descsz;
1429 1512
1430 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1513 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1431 break; 1514 break;
@@ -1434,15 +1517,16 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1434 descsz = NOTE_ALIGN(nhdr.n_descsz); 1517 descsz = NOTE_ALIGN(nhdr.n_descsz);
1435 if (nhdr.n_type == NT_GNU_BUILD_ID && 1518 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1436 nhdr.n_namesz == sizeof("GNU")) { 1519 nhdr.n_namesz == sizeof("GNU")) {
1437 if (read(fd, bf, namesz) != namesz) 1520 if (read(fd, bf, namesz) != (ssize_t)namesz)
1438 break; 1521 break;
1439 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1522 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1440 if (read(fd, build_id, 1523 size_t sz = min(descsz, size);
1441 BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1524 if (read(fd, build_id, sz) == (ssize_t)sz) {
1525 memset(build_id + sz, 0, size - sz);
1442 err = 0; 1526 err = 0;
1443 break; 1527 break;
1444 } 1528 }
1445 } else if (read(fd, bf, descsz) != descsz) 1529 } else if (read(fd, bf, descsz) != (ssize_t)descsz)
1446 break; 1530 break;
1447 } else { 1531 } else {
1448 int n = namesz + descsz; 1532 int n = namesz + descsz;
@@ -1504,6 +1588,17 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1504 dso->adjust_symbols = 0; 1588 dso->adjust_symbols = 0;
1505 1589
1506 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1590 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1591 struct stat st;
1592
1593 if (lstat(dso->name, &st) < 0)
1594 return -1;
1595
1596 if (st.st_uid && (st.st_uid != geteuid())) {
1597 pr_warning("File %s not owned by current user or root, "
1598 "ignoring it.\n", dso->name);
1599 return -1;
1600 }
1601
1507 ret = dso__load_perf_map(dso, map, filter); 1602 ret = dso__load_perf_map(dso, map, filter);
1508 dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : 1603 dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
1509 SYMTAB__NOT_FOUND; 1604 SYMTAB__NOT_FOUND;
@@ -2170,27 +2265,22 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
2170 return ret; 2265 return ret;
2171} 2266}
2172 2267
2173struct dso *dso__new_kernel(const char *name) 2268static struct dso*
2269dso__kernel_findnew(struct machine *machine, const char *name,
2270 const char *short_name, int dso_type)
2174{ 2271{
2175 struct dso *dso = dso__new(name ?: "[kernel.kallsyms]"); 2272 /*
2176 2273 * The kernel dso could be created by build_id processing.
2177 if (dso != NULL) { 2274 */
2178 dso__set_short_name(dso, "[kernel]"); 2275 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
2179 dso->kernel = DSO_TYPE_KERNEL;
2180 }
2181
2182 return dso;
2183}
2184 2276
2185static struct dso *dso__new_guest_kernel(struct machine *machine, 2277 /*
2186 const char *name) 2278 * We need to run this in all cases, since during the build_id
2187{ 2279 * processing we had no idea this was the kernel dso.
2188 char bf[PATH_MAX]; 2280 */
2189 struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf,
2190 sizeof(bf)));
2191 if (dso != NULL) { 2281 if (dso != NULL) {
2192 dso__set_short_name(dso, "[guest.kernel]"); 2282 dso__set_short_name(dso, short_name);
2193 dso->kernel = DSO_TYPE_GUEST_KERNEL; 2283 dso->kernel = dso_type;
2194 } 2284 }
2195 2285
2196 return dso; 2286 return dso;
@@ -2208,24 +2298,36 @@ void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
2208 dso->has_build_id = true; 2298 dso->has_build_id = true;
2209} 2299}
2210 2300
2211static struct dso *machine__create_kernel(struct machine *machine) 2301static struct dso *machine__get_kernel(struct machine *machine)
2212{ 2302{
2213 const char *vmlinux_name = NULL; 2303 const char *vmlinux_name = NULL;
2214 struct dso *kernel; 2304 struct dso *kernel;
2215 2305
2216 if (machine__is_host(machine)) { 2306 if (machine__is_host(machine)) {
2217 vmlinux_name = symbol_conf.vmlinux_name; 2307 vmlinux_name = symbol_conf.vmlinux_name;
2218 kernel = dso__new_kernel(vmlinux_name); 2308 if (!vmlinux_name)
2309 vmlinux_name = "[kernel.kallsyms]";
2310
2311 kernel = dso__kernel_findnew(machine, vmlinux_name,
2312 "[kernel]",
2313 DSO_TYPE_KERNEL);
2219 } else { 2314 } else {
2315 char bf[PATH_MAX];
2316
2220 if (machine__is_default_guest(machine)) 2317 if (machine__is_default_guest(machine))
2221 vmlinux_name = symbol_conf.default_guest_vmlinux_name; 2318 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2222 kernel = dso__new_guest_kernel(machine, vmlinux_name); 2319 if (!vmlinux_name)
2320 vmlinux_name = machine__mmap_name(machine, bf,
2321 sizeof(bf));
2322
2323 kernel = dso__kernel_findnew(machine, vmlinux_name,
2324 "[guest.kernel]",
2325 DSO_TYPE_GUEST_KERNEL);
2223 } 2326 }
2224 2327
2225 if (kernel != NULL) { 2328 if (kernel != NULL && (!kernel->has_build_id))
2226 dso__read_running_kernel_build_id(kernel, machine); 2329 dso__read_running_kernel_build_id(kernel, machine);
2227 dsos__add(&machine->kernel_dsos, kernel); 2330
2228 }
2229 return kernel; 2331 return kernel;
2230} 2332}
2231 2333
@@ -2329,7 +2431,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
2329 2431
2330int machine__create_kernel_maps(struct machine *machine) 2432int machine__create_kernel_maps(struct machine *machine)
2331{ 2433{
2332 struct dso *kernel = machine__create_kernel(machine); 2434 struct dso *kernel = machine__get_kernel(machine);
2333 2435
2334 if (kernel == NULL || 2436 if (kernel == NULL ||
2335 __machine__create_kernel_maps(machine, kernel) < 0) 2437 __machine__create_kernel_maps(machine, kernel) < 0)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 325ee36a9d29..29f8d742e92f 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -72,11 +72,14 @@ struct symbol_conf {
72 use_modules, 72 use_modules,
73 sort_by_name, 73 sort_by_name,
74 show_nr_samples, 74 show_nr_samples,
75 show_total_period,
75 use_callchain, 76 use_callchain,
76 exclude_other, 77 exclude_other,
77 show_cpu_utilization, 78 show_cpu_utilization,
78 initialized, 79 initialized,
79 kptr_restrict; 80 kptr_restrict,
81 annotate_asm_raw,
82 annotate_src;
80 const char *vmlinux_name, 83 const char *vmlinux_name,
81 *kallsyms_name, 84 *kallsyms_name,
82 *source_prefix, 85 *source_prefix,
@@ -155,7 +158,6 @@ struct dso {
155}; 158};
156 159
157struct dso *dso__new(const char *name); 160struct dso *dso__new(const char *name);
158struct dso *dso__new_kernel(const char *name);
159void dso__delete(struct dso *dso); 161void dso__delete(struct dso *dso);
160 162
161int dso__name_len(const struct dso *dso); 163int dso__name_len(const struct dso *dso);
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index a11f60735a18..500471dffa4f 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -15,52 +15,6 @@
15#include "top.h" 15#include "top.h"
16#include <inttypes.h> 16#include <inttypes.h>
17 17
18/*
19 * Ordering weight: count-1 * count-2 * ... / count-n
20 */
21static double sym_weight(const struct sym_entry *sym, struct perf_top *top)
22{
23 double weight = sym->snap_count;
24 int counter;
25
26 if (!top->display_weighted)
27 return weight;
28
29 for (counter = 1; counter < top->evlist->nr_entries - 1; counter++)
30 weight *= sym->count[counter];
31
32 weight /= (sym->count[counter] + 1);
33
34 return weight;
35}
36
37static void perf_top__remove_active_sym(struct perf_top *top, struct sym_entry *syme)
38{
39 pthread_mutex_lock(&top->active_symbols_lock);
40 list_del_init(&syme->node);
41 pthread_mutex_unlock(&top->active_symbols_lock);
42}
43
44static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
45{
46 struct rb_node **p = &tree->rb_node;
47 struct rb_node *parent = NULL;
48 struct sym_entry *iter;
49
50 while (*p != NULL) {
51 parent = *p;
52 iter = rb_entry(parent, struct sym_entry, rb_node);
53
54 if (se->weight > iter->weight)
55 p = &(*p)->rb_left;
56 else
57 p = &(*p)->rb_right;
58 }
59
60 rb_link_node(&se->rb_node, parent, p);
61 rb_insert_color(&se->rb_node, tree);
62}
63
64#define SNPRINTF(buf, size, fmt, args...) \ 18#define SNPRINTF(buf, size, fmt, args...) \
65({ \ 19({ \
66 size_t r = snprintf(buf, size, fmt, ## args); \ 20 size_t r = snprintf(buf, size, fmt, ## args); \
@@ -69,7 +23,6 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
69 23
70size_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)
71{ 25{
72 struct perf_evsel *counter;
73 float samples_per_sec = top->samples / top->delay_secs; 26 float samples_per_sec = top->samples / top->delay_secs;
74 float ksamples_per_sec = top->kernel_samples / top->delay_secs; 27 float ksamples_per_sec = top->kernel_samples / top->delay_secs;
75 float esamples_percent = (100.0 * top->exact_samples) / top->samples; 28 float esamples_percent = (100.0 * top->exact_samples) / top->samples;
@@ -104,7 +57,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
104 esamples_percent); 57 esamples_percent);
105 } 58 }
106 59
107 if (top->evlist->nr_entries == 1 || !top->display_weighted) { 60 if (top->evlist->nr_entries == 1) {
108 struct perf_evsel *first; 61 struct perf_evsel *first;
109 first = list_entry(top->evlist->entries.next, struct perf_evsel, node); 62 first = list_entry(top->evlist->entries.next, struct perf_evsel, node);
110 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", 63 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
@@ -112,27 +65,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
112 top->freq ? "Hz" : ""); 65 top->freq ? "Hz" : "");
113 } 66 }
114 67
115 if (!top->display_weighted) { 68 ret += SNPRINTF(bf + ret, size - ret, "%s", event_name(top->sym_evsel));
116 ret += SNPRINTF(bf + ret, size - ret, "%s",
117 event_name(top->sym_evsel));
118 } else {
119 /*
120 * Don't let events eat all the space. Leaving 30 bytes
121 * for the rest should be enough.
122 */
123 size_t last_pos = size - 30;
124
125 list_for_each_entry(counter, &top->evlist->entries, node) {
126 ret += SNPRINTF(bf + ret, size - ret, "%s%s",
127 counter->idx ? "/" : "",
128 event_name(counter));
129 if (ret > last_pos) {
130 sprintf(bf + last_pos - 3, "..");
131 ret = last_pos - 1;
132 break;
133 }
134 }
135 }
136 69
137 ret += SNPRINTF(bf + ret, size - ret, "], "); 70 ret += SNPRINTF(bf + ret, size - ret, "], ");
138 71
@@ -166,73 +99,3 @@ void perf_top__reset_sample_counters(struct perf_top *top)
166 top->exact_samples = top->guest_kernel_samples = 99 top->exact_samples = top->guest_kernel_samples =
167 top->guest_us_samples = 0; 100 top->guest_us_samples = 0;
168} 101}
169
170float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)
171{
172 struct sym_entry *syme, *n;
173 float sum_ksamples = 0.0;
174 int snap = !top->display_weighted ? top->sym_evsel->idx : 0, j;
175
176 /* Sort the active symbols */
177 pthread_mutex_lock(&top->active_symbols_lock);
178 syme = list_entry(top->active_symbols.next, struct sym_entry, node);
179 pthread_mutex_unlock(&top->active_symbols_lock);
180
181 top->rb_entries = 0;
182 list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) {
183 syme->snap_count = syme->count[snap];
184 if (syme->snap_count != 0) {
185
186 if ((top->hide_user_symbols &&
187 syme->map->dso->kernel == DSO_TYPE_USER) ||
188 (top->hide_kernel_symbols &&
189 syme->map->dso->kernel == DSO_TYPE_KERNEL)) {
190 perf_top__remove_active_sym(top, syme);
191 continue;
192 }
193 syme->weight = sym_weight(syme, top);
194
195 if ((int)syme->snap_count >= top->count_filter) {
196 rb_insert_active_sym(root, syme);
197 ++top->rb_entries;
198 }
199 sum_ksamples += syme->snap_count;
200
201 for (j = 0; j < top->evlist->nr_entries; j++)
202 syme->count[j] = top->zero ? 0 : syme->count[j] * 7 / 8;
203 } else
204 perf_top__remove_active_sym(top, syme);
205 }
206
207 return sum_ksamples;
208}
209
210/*
211 * Find the longest symbol name that will be displayed
212 */
213void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
214 int *dso_width, int *dso_short_width, int *sym_width)
215{
216 struct rb_node *nd;
217 int printed = 0;
218
219 *sym_width = *dso_width = *dso_short_width = 0;
220
221 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
222 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
223 struct symbol *sym = sym_entry__symbol(syme);
224
225 if (++printed > top->print_entries ||
226 (int)syme->snap_count < top->count_filter)
227 continue;
228
229 if (syme->map->dso->long_name_len > *dso_width)
230 *dso_width = syme->map->dso->long_name_len;
231
232 if (syme->map->dso->short_name_len > *dso_short_width)
233 *dso_short_width = syme->map->dso->short_name_len;
234
235 if (sym->namelen > *sym_width)
236 *sym_width = sym->namelen;
237 }
238}
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index bfbf95bcc603..01d1057f3074 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -4,26 +4,10 @@
4#include "types.h" 4#include "types.h"
5#include "../perf.h" 5#include "../perf.h"
6#include <stddef.h> 6#include <stddef.h>
7#include <pthread.h>
8#include <linux/list.h>
9#include <linux/rbtree.h>
10 7
11struct perf_evlist; 8struct perf_evlist;
12struct perf_evsel; 9struct perf_evsel;
13 10struct perf_session;
14struct sym_entry {
15 struct rb_node rb_node;
16 struct list_head node;
17 unsigned long snap_count;
18 double weight;
19 struct map *map;
20 unsigned long count[0];
21};
22
23static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
24{
25 return ((void *)self) + symbol_conf.priv_size;
26}
27 11
28struct perf_top { 12struct perf_top {
29 struct perf_evlist *evlist; 13 struct perf_evlist *evlist;
@@ -31,34 +15,21 @@ struct perf_top {
31 * Symbols will be added here in perf_event__process_sample and will 15 * Symbols will be added here in perf_event__process_sample and will
32 * get out after decayed. 16 * get out after decayed.
33 */ 17 */
34 struct list_head active_symbols;
35 pthread_mutex_t active_symbols_lock;
36 pthread_cond_t active_symbols_cond;
37 u64 samples; 18 u64 samples;
38 u64 kernel_samples, us_samples; 19 u64 kernel_samples, us_samples;
39 u64 exact_samples; 20 u64 exact_samples;
40 u64 guest_us_samples, guest_kernel_samples; 21 u64 guest_us_samples, guest_kernel_samples;
22 u64 total_lost_warned;
41 int print_entries, count_filter, delay_secs; 23 int print_entries, count_filter, delay_secs;
42 int display_weighted, freq, rb_entries; 24 int freq;
43 pid_t target_pid, target_tid; 25 pid_t target_pid, target_tid;
44 bool hide_kernel_symbols, hide_user_symbols, zero; 26 bool hide_kernel_symbols, hide_user_symbols, zero;
45 const char *cpu_list; 27 const char *cpu_list;
46 struct sym_entry *sym_filter_entry; 28 struct hist_entry *sym_filter_entry;
47 struct perf_evsel *sym_evsel; 29 struct perf_evsel *sym_evsel;
30 struct perf_session *session;
48}; 31};
49 32
50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 33size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
51void perf_top__reset_sample_counters(struct perf_top *top); 34void perf_top__reset_sample_counters(struct perf_top *top);
52float perf_top__decay_samples(struct perf_top *top, struct rb_root *root);
53void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
54 int *dso_width, int *dso_short_width, int *sym_width);
55
56#ifdef NO_NEWT_SUPPORT
57static inline int perf_top__tui_browser(struct perf_top *top __used)
58{
59 return 0;
60}
61#else
62int perf_top__tui_browser(struct perf_top *top);
63#endif
64#endif /* __PERF_TOP_H */ 35#endif /* __PERF_TOP_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 3403f814ad72..2d530cf74f43 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -196,7 +196,8 @@ static void record_file(const char *file, size_t hdr_sz)
196 die("Can't read '%s'", file); 196 die("Can't read '%s'", file);
197 197
198 /* put in zeros for file size, then fill true size later */ 198 /* put in zeros for file size, then fill true size later */
199 write_or_die(&size, hdr_sz); 199 if (hdr_sz)
200 write_or_die(&size, hdr_sz);
200 201
201 do { 202 do {
202 r = read(fd, buf, BUFSIZ); 203 r = read(fd, buf, BUFSIZ);
@@ -212,7 +213,7 @@ static void record_file(const char *file, size_t hdr_sz)
212 if (bigendian()) 213 if (bigendian())
213 sizep += sizeof(u64) - hdr_sz; 214 sizep += sizeof(u64) - hdr_sz;
214 215
215 if (pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) 216 if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0)
216 die("writing to %s", output_file); 217 die("writing to %s", output_file);
217} 218}
218 219
@@ -428,6 +429,19 @@ get_tracepoints_path(struct list_head *pattrs)
428 return nr_tracepoints > 0 ? path.next : NULL; 429 return nr_tracepoints > 0 ? path.next : NULL;
429} 430}
430 431
432static void
433put_tracepoints_path(struct tracepoint_path *tps)
434{
435 while (tps) {
436 struct tracepoint_path *t = tps;
437
438 tps = tps->next;
439 free(t->name);
440 free(t->system);
441 free(t);
442 }
443}
444
431bool have_tracepoints(struct list_head *pattrs) 445bool have_tracepoints(struct list_head *pattrs)
432{ 446{
433 struct perf_evsel *pos; 447 struct perf_evsel *pos;
@@ -439,19 +453,11 @@ bool have_tracepoints(struct list_head *pattrs)
439 return false; 453 return false;
440} 454}
441 455
442int read_tracing_data(int fd, struct list_head *pattrs) 456static void tracing_data_header(void)
443{ 457{
444 char buf[BUFSIZ]; 458 char buf[20];
445 struct tracepoint_path *tps = get_tracepoints_path(pattrs);
446
447 /*
448 * What? No tracepoints? No sense writing anything here, bail out.
449 */
450 if (tps == NULL)
451 return -1;
452
453 output_fd = fd;
454 459
460 /* just guessing this is someone's birthday.. ;) */
455 buf[0] = 23; 461 buf[0] = 23;
456 buf[1] = 8; 462 buf[1] = 8;
457 buf[2] = 68; 463 buf[2] = 68;
@@ -476,28 +482,86 @@ int read_tracing_data(int fd, struct list_head *pattrs)
476 /* save page_size */ 482 /* save page_size */
477 page_size = sysconf(_SC_PAGESIZE); 483 page_size = sysconf(_SC_PAGESIZE);
478 write_or_die(&page_size, 4); 484 write_or_die(&page_size, 4);
485}
486
487struct tracing_data *tracing_data_get(struct list_head *pattrs,
488 int fd, bool temp)
489{
490 struct tracepoint_path *tps;
491 struct tracing_data *tdata;
492
493 output_fd = fd;
494
495 tps = get_tracepoints_path(pattrs);
496 if (!tps)
497 return NULL;
479 498
499 tdata = malloc_or_die(sizeof(*tdata));
500 tdata->temp = temp;
501 tdata->size = 0;
502
503 if (temp) {
504 int temp_fd;
505
506 snprintf(tdata->temp_file, sizeof(tdata->temp_file),
507 "/tmp/perf-XXXXXX");
508 if (!mkstemp(tdata->temp_file))
509 die("Can't make temp file");
510
511 temp_fd = open(tdata->temp_file, O_RDWR);
512 if (temp_fd < 0)
513 die("Can't read '%s'", tdata->temp_file);
514
515 /*
516 * Set the temp file the default output, so all the
517 * tracing data are stored into it.
518 */
519 output_fd = temp_fd;
520 }
521
522 tracing_data_header();
480 read_header_files(); 523 read_header_files();
481 read_ftrace_files(tps); 524 read_ftrace_files(tps);
482 read_event_files(tps); 525 read_event_files(tps);
483 read_proc_kallsyms(); 526 read_proc_kallsyms();
484 read_ftrace_printk(); 527 read_ftrace_printk();
485 528
486 return 0; 529 /*
530 * All tracing data are stored by now, we can restore
531 * the default output file in case we used temp file.
532 */
533 if (temp) {
534 tdata->size = lseek(output_fd, 0, SEEK_CUR);
535 close(output_fd);
536 output_fd = fd;
537 }
538
539 put_tracepoints_path(tps);
540 return tdata;
487} 541}
488 542
489ssize_t read_tracing_data_size(int fd, struct list_head *pattrs) 543void tracing_data_put(struct tracing_data *tdata)
490{ 544{
491 ssize_t size; 545 if (tdata->temp) {
492 int err = 0; 546 record_file(tdata->temp_file, 0);
547 unlink(tdata->temp_file);
548 }
493 549
494 calc_data_size = 1; 550 free(tdata);
495 err = read_tracing_data(fd, pattrs); 551}
496 size = calc_data_size - 1;
497 calc_data_size = 0;
498 552
499 if (err < 0) 553int read_tracing_data(int fd, struct list_head *pattrs)
500 return err; 554{
555 struct tracing_data *tdata;
501 556
502 return size; 557 /*
558 * We work over the real file, so we can write data
559 * directly, no temp file is needed.
560 */
561 tdata = tracing_data_get(pattrs, fd, false);
562 if (!tdata)
563 return -ENOMEM;
564
565 tracing_data_put(tdata);
566 return 0;
503} 567}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index f674dda3363b..a84100817649 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -263,7 +263,18 @@ void *raw_field_ptr(struct event *event, const char *name, void *data);
263unsigned long long eval_flag(const char *flag); 263unsigned long long eval_flag(const char *flag);
264 264
265int read_tracing_data(int fd, struct list_head *pattrs); 265int read_tracing_data(int fd, struct list_head *pattrs);
266ssize_t read_tracing_data_size(int fd, struct list_head *pattrs); 266
267struct tracing_data {
268 /* size is only valid if temp is 'true' */
269 ssize_t size;
270 bool temp;
271 char temp_file[50];
272};
273
274struct tracing_data *tracing_data_get(struct list_head *pattrs,
275 int fd, bool temp);
276void tracing_data_put(struct tracing_data *tdata);
277
267 278
268/* taken from kernel/trace/trace.h */ 279/* taken from kernel/trace/trace.h */
269enum trace_flag_type { 280enum trace_flag_type {
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
index 611219f80680..5359f371d30a 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,4 +1,8 @@
1#include "../util.h"
2#include "../cache.h"
3#include "../../perf.h"
1#include "libslang.h" 4#include "libslang.h"
5#include <newt.h>
2#include "ui.h" 6#include "ui.h"
3#include <linux/compiler.h> 7#include <linux/compiler.h>
4#include <linux/list.h> 8#include <linux/list.h>
@@ -7,13 +11,13 @@
7#include <sys/ttydefaults.h> 11#include <sys/ttydefaults.h>
8#include "browser.h" 12#include "browser.h"
9#include "helpline.h" 13#include "helpline.h"
14#include "keysyms.h"
10#include "../color.h" 15#include "../color.h"
11#include "../util.h"
12#include <stdio.h>
13 16
14static int ui_browser__percent_color(double percent, bool current) 17static int ui_browser__percent_color(struct ui_browser *browser,
18 double percent, bool current)
15{ 19{
16 if (current) 20 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
17 return HE_COLORSET_SELECTED; 21 return HE_COLORSET_SELECTED;
18 if (percent >= MIN_RED) 22 if (percent >= MIN_RED)
19 return HE_COLORSET_TOP; 23 return HE_COLORSET_TOP;
@@ -30,7 +34,7 @@ void ui_browser__set_color(struct ui_browser *self __used, int color)
30void ui_browser__set_percent_color(struct ui_browser *self, 34void ui_browser__set_percent_color(struct ui_browser *self,
31 double percent, bool current) 35 double percent, bool current)
32{ 36{
33 int color = ui_browser__percent_color(percent, current); 37 int color = ui_browser__percent_color(self, percent, current);
34 ui_browser__set_color(self, color); 38 ui_browser__set_color(self, color);
35} 39}
36 40
@@ -39,31 +43,62 @@ void ui_browser__gotorc(struct ui_browser *self, int y, int x)
39 SLsmg_gotorc(self->y + y, self->x + x); 43 SLsmg_gotorc(self->y + y, self->x + x);
40} 44}
41 45
46static struct list_head *
47ui_browser__list_head_filter_entries(struct ui_browser *browser,
48 struct list_head *pos)
49{
50 do {
51 if (!browser->filter || !browser->filter(browser, pos))
52 return pos;
53 pos = pos->next;
54 } while (pos != browser->entries);
55
56 return NULL;
57}
58
59static struct list_head *
60ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
61 struct list_head *pos)
62{
63 do {
64 if (!browser->filter || !browser->filter(browser, pos))
65 return pos;
66 pos = pos->prev;
67 } while (pos != browser->entries);
68
69 return NULL;
70}
71
42void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) 72void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
43{ 73{
44 struct list_head *head = self->entries; 74 struct list_head *head = self->entries;
45 struct list_head *pos; 75 struct list_head *pos;
46 76
77 if (self->nr_entries == 0)
78 return;
79
47 switch (whence) { 80 switch (whence) {
48 case SEEK_SET: 81 case SEEK_SET:
49 pos = head->next; 82 pos = ui_browser__list_head_filter_entries(self, head->next);
50 break; 83 break;
51 case SEEK_CUR: 84 case SEEK_CUR:
52 pos = self->top; 85 pos = self->top;
53 break; 86 break;
54 case SEEK_END: 87 case SEEK_END:
55 pos = head->prev; 88 pos = ui_browser__list_head_filter_prev_entries(self, head->prev);
56 break; 89 break;
57 default: 90 default:
58 return; 91 return;
59 } 92 }
60 93
94 assert(pos != NULL);
95
61 if (offset > 0) { 96 if (offset > 0) {
62 while (offset-- != 0) 97 while (offset-- != 0)
63 pos = pos->next; 98 pos = ui_browser__list_head_filter_entries(self, pos->next);
64 } else { 99 } else {
65 while (offset++ != 0) 100 while (offset++ != 0)
66 pos = pos->prev; 101 pos = ui_browser__list_head_filter_prev_entries(self, pos->prev);
67 } 102 }
68 103
69 self->top = pos; 104 self->top = pos;
@@ -127,11 +162,8 @@ bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
127 162
128void ui_browser__refresh_dimensions(struct ui_browser *self) 163void ui_browser__refresh_dimensions(struct ui_browser *self)
129{ 164{
130 int cols, rows; 165 self->width = SLtt_Screen_Cols - 1;
131 newtGetScreenSize(&cols, &rows); 166 self->height = SLtt_Screen_Rows - 2;
132
133 self->width = cols - 1;
134 self->height = rows - 2;
135 self->y = 1; 167 self->y = 1;
136 self->x = 0; 168 self->x = 0;
137} 169}
@@ -142,26 +174,11 @@ void ui_browser__reset_index(struct ui_browser *self)
142 self->seek(self, 0, SEEK_SET); 174 self->seek(self, 0, SEEK_SET);
143} 175}
144 176
145void ui_browser__add_exit_key(struct ui_browser *self, int key)
146{
147 newtFormAddHotKey(self->form, key);
148}
149
150void ui_browser__add_exit_keys(struct ui_browser *self, int keys[])
151{
152 int i = 0;
153
154 while (keys[i] && i < 64) {
155 ui_browser__add_exit_key(self, keys[i]);
156 ++i;
157 }
158}
159
160void __ui_browser__show_title(struct ui_browser *browser, const char *title) 177void __ui_browser__show_title(struct ui_browser *browser, const char *title)
161{ 178{
162 SLsmg_gotorc(0, 0); 179 SLsmg_gotorc(0, 0);
163 ui_browser__set_color(browser, NEWT_COLORSET_ROOT); 180 ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
164 slsmg_write_nstring(title, browser->width); 181 slsmg_write_nstring(title, browser->width + 1);
165} 182}
166 183
167void ui_browser__show_title(struct ui_browser *browser, const char *title) 184void ui_browser__show_title(struct ui_browser *browser, const char *title)
@@ -174,78 +191,189 @@ void ui_browser__show_title(struct ui_browser *browser, const char *title)
174int ui_browser__show(struct ui_browser *self, const char *title, 191int ui_browser__show(struct ui_browser *self, const char *title,
175 const char *helpline, ...) 192 const char *helpline, ...)
176{ 193{
194 int err;
177 va_list ap; 195 va_list ap;
178 int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP,
179 NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ',
180 NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 };
181
182 if (self->form != NULL)
183 newtFormDestroy(self->form);
184 196
185 ui_browser__refresh_dimensions(self); 197 ui_browser__refresh_dimensions(self);
186 self->form = newtForm(NULL, NULL, 0);
187 if (self->form == NULL)
188 return -1;
189
190 self->sb = newtVerticalScrollbar(self->width, 1, self->height,
191 HE_COLORSET_NORMAL,
192 HE_COLORSET_SELECTED);
193 if (self->sb == NULL)
194 return -1;
195 198
196 pthread_mutex_lock(&ui__lock); 199 pthread_mutex_lock(&ui__lock);
197 __ui_browser__show_title(self, title); 200 __ui_browser__show_title(self, title);
198 201
199 ui_browser__add_exit_keys(self, keys); 202 self->title = title;
200 newtFormAddComponent(self->form, self->sb); 203 free(self->helpline);
204 self->helpline = NULL;
201 205
202 va_start(ap, helpline); 206 va_start(ap, helpline);
203 ui_helpline__vpush(helpline, ap); 207 err = vasprintf(&self->helpline, helpline, ap);
204 va_end(ap); 208 va_end(ap);
209 if (err > 0)
210 ui_helpline__push(self->helpline);
205 pthread_mutex_unlock(&ui__lock); 211 pthread_mutex_unlock(&ui__lock);
206 return 0; 212 return err ? 0 : -1;
207} 213}
208 214
209void ui_browser__hide(struct ui_browser *self) 215void ui_browser__hide(struct ui_browser *browser __used)
210{ 216{
211 pthread_mutex_lock(&ui__lock); 217 pthread_mutex_lock(&ui__lock);
212 newtFormDestroy(self->form);
213 self->form = NULL;
214 ui_helpline__pop(); 218 ui_helpline__pop();
215 pthread_mutex_unlock(&ui__lock); 219 pthread_mutex_unlock(&ui__lock);
216} 220}
217 221
218int ui_browser__refresh(struct ui_browser *self) 222static void ui_browser__scrollbar_set(struct ui_browser *browser)
223{
224 int height = browser->height, h = 0, pct = 0,
225 col = browser->width,
226 row = browser->y - 1;
227
228 if (browser->nr_entries > 1) {
229 pct = ((browser->index * (browser->height - 1)) /
230 (browser->nr_entries - 1));
231 }
232
233 while (h < height) {
234 ui_browser__gotorc(browser, row++, col);
235 SLsmg_set_char_set(1);
236 SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_BOARD_CHAR);
237 SLsmg_set_char_set(0);
238 ++h;
239 }
240}
241
242static int __ui_browser__refresh(struct ui_browser *browser)
219{ 243{
220 int row; 244 int row;
245 int width = browser->width;
246
247 row = browser->refresh(browser);
248 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
249
250 if (!browser->use_navkeypressed || browser->navkeypressed)
251 ui_browser__scrollbar_set(browser);
252 else
253 width += 1;
221 254
255 SLsmg_fill_region(browser->y + row, browser->x,
256 browser->height - row, width, ' ');
257
258 return 0;
259}
260
261int ui_browser__refresh(struct ui_browser *browser)
262{
222 pthread_mutex_lock(&ui__lock); 263 pthread_mutex_lock(&ui__lock);
223 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); 264 __ui_browser__refresh(browser);
224 row = self->refresh(self);
225 ui_browser__set_color(self, HE_COLORSET_NORMAL);
226 SLsmg_fill_region(self->y + row, self->x,
227 self->height - row, self->width, ' ');
228 pthread_mutex_unlock(&ui__lock); 265 pthread_mutex_unlock(&ui__lock);
229 266
230 return 0; 267 return 0;
231} 268}
232 269
233int ui_browser__run(struct ui_browser *self) 270/*
271 * Here we're updating nr_entries _after_ we started browsing, i.e. we have to
272 * forget about any reference to any entry in the underlying data structure,
273 * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
274 * after an output_resort and hist decay.
275 */
276void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
234{ 277{
235 struct newtExitStruct es; 278 off_t offset = nr_entries - browser->nr_entries;
279
280 browser->nr_entries = nr_entries;
236 281
237 if (ui_browser__refresh(self) < 0) 282 if (offset < 0) {
238 return -1; 283 if (browser->top_idx < (u64)-offset)
284 offset = -browser->top_idx;
285
286 browser->index += offset;
287 browser->top_idx += offset;
288 }
289
290 browser->top = NULL;
291 browser->seek(browser, browser->top_idx, SEEK_SET);
292}
293
294static int ui__getch(int delay_secs)
295{
296 struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
297 fd_set read_set;
298 int err, key;
299
300 FD_ZERO(&read_set);
301 FD_SET(0, &read_set);
302
303 if (delay_secs) {
304 timeout.tv_sec = delay_secs;
305 timeout.tv_usec = 0;
306 }
307
308 err = select(1, &read_set, NULL, NULL, ptimeout);
309
310 if (err == 0)
311 return K_TIMER;
312
313 if (err == -1) {
314 if (errno == EINTR)
315 return K_RESIZE;
316 return K_ERROR;
317 }
318
319 key = SLang_getkey();
320 if (key != K_ESC)
321 return key;
322
323 FD_ZERO(&read_set);
324 FD_SET(0, &read_set);
325 timeout.tv_sec = 0;
326 timeout.tv_usec = 20;
327 err = select(1, &read_set, NULL, NULL, &timeout);
328 if (err == 0)
329 return K_ESC;
330
331 SLang_ungetkey(key);
332 return SLkp_getkey();
333}
334
335int ui_browser__run(struct ui_browser *self, int delay_secs)
336{
337 int err, key;
338
339 pthread__unblock_sigwinch();
239 340
240 while (1) { 341 while (1) {
241 off_t offset; 342 off_t offset;
242 343
243 newtFormRun(self->form, &es); 344 pthread_mutex_lock(&ui__lock);
244 345 err = __ui_browser__refresh(self);
245 if (es.reason != NEWT_EXIT_HOTKEY) 346 SLsmg_refresh();
347 pthread_mutex_unlock(&ui__lock);
348 if (err < 0)
246 break; 349 break;
247 switch (es.u.key) { 350
248 case NEWT_KEY_DOWN: 351 key = ui__getch(delay_secs);
352
353 if (key == K_RESIZE) {
354 pthread_mutex_lock(&ui__lock);
355 SLtt_get_screen_size();
356 SLsmg_reinit_smg();
357 pthread_mutex_unlock(&ui__lock);
358 ui_browser__refresh_dimensions(self);
359 __ui_browser__show_title(self, self->title);
360 ui_helpline__puts(self->helpline);
361 continue;
362 }
363
364 if (self->use_navkeypressed && !self->navkeypressed) {
365 if (key == K_DOWN || key == K_UP ||
366 key == K_PGDN || key == K_PGUP ||
367 key == K_HOME || key == K_END ||
368 key == ' ') {
369 self->navkeypressed = true;
370 continue;
371 } else
372 return key;
373 }
374
375 switch (key) {
376 case K_DOWN:
249 if (self->index == self->nr_entries - 1) 377 if (self->index == self->nr_entries - 1)
250 break; 378 break;
251 ++self->index; 379 ++self->index;
@@ -254,7 +382,7 @@ int ui_browser__run(struct ui_browser *self)
254 self->seek(self, +1, SEEK_CUR); 382 self->seek(self, +1, SEEK_CUR);
255 } 383 }
256 break; 384 break;
257 case NEWT_KEY_UP: 385 case K_UP:
258 if (self->index == 0) 386 if (self->index == 0)
259 break; 387 break;
260 --self->index; 388 --self->index;
@@ -263,7 +391,7 @@ int ui_browser__run(struct ui_browser *self)
263 self->seek(self, -1, SEEK_CUR); 391 self->seek(self, -1, SEEK_CUR);
264 } 392 }
265 break; 393 break;
266 case NEWT_KEY_PGDN: 394 case K_PGDN:
267 case ' ': 395 case ' ':
268 if (self->top_idx + self->height > self->nr_entries - 1) 396 if (self->top_idx + self->height > self->nr_entries - 1)
269 break; 397 break;
@@ -275,7 +403,7 @@ int ui_browser__run(struct ui_browser *self)
275 self->top_idx += offset; 403 self->top_idx += offset;
276 self->seek(self, +offset, SEEK_CUR); 404 self->seek(self, +offset, SEEK_CUR);
277 break; 405 break;
278 case NEWT_KEY_PGUP: 406 case K_PGUP:
279 if (self->top_idx == 0) 407 if (self->top_idx == 0)
280 break; 408 break;
281 409
@@ -288,10 +416,10 @@ int ui_browser__run(struct ui_browser *self)
288 self->top_idx -= offset; 416 self->top_idx -= offset;
289 self->seek(self, -offset, SEEK_CUR); 417 self->seek(self, -offset, SEEK_CUR);
290 break; 418 break;
291 case NEWT_KEY_HOME: 419 case K_HOME:
292 ui_browser__reset_index(self); 420 ui_browser__reset_index(self);
293 break; 421 break;
294 case NEWT_KEY_END: 422 case K_END:
295 offset = self->height - 1; 423 offset = self->height - 1;
296 if (offset >= self->nr_entries) 424 if (offset >= self->nr_entries)
297 offset = self->nr_entries - 1; 425 offset = self->nr_entries - 1;
@@ -301,10 +429,8 @@ int ui_browser__run(struct ui_browser *self)
301 self->seek(self, -offset, SEEK_END); 429 self->seek(self, -offset, SEEK_END);
302 break; 430 break;
303 default: 431 default:
304 return es.u.key; 432 return key;
305 } 433 }
306 if (ui_browser__refresh(self) < 0)
307 return -1;
308 } 434 }
309 return -1; 435 return -1;
310} 436}
@@ -316,41 +442,105 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
316 int row = 0; 442 int row = 0;
317 443
318 if (self->top == NULL || self->top == self->entries) 444 if (self->top == NULL || self->top == self->entries)
319 self->top = head->next; 445 self->top = ui_browser__list_head_filter_entries(self, head->next);
320 446
321 pos = self->top; 447 pos = self->top;
322 448
323 list_for_each_from(pos, head) { 449 list_for_each_from(pos, head) {
324 ui_browser__gotorc(self, row, 0); 450 if (!self->filter || !self->filter(self, pos)) {
325 self->write(self, pos, row); 451 ui_browser__gotorc(self, row, 0);
326 if (++row == self->height) 452 self->write(self, pos, row);
327 break; 453 if (++row == self->height)
454 break;
455 }
328 } 456 }
329 457
330 return row; 458 return row;
331} 459}
332 460
333static struct newtPercentTreeColors { 461static struct ui_browser__colorset {
334 const char *topColorFg, *topColorBg; 462 const char *name, *fg, *bg;
335 const char *mediumColorFg, *mediumColorBg; 463 int colorset;
336 const char *normalColorFg, *normalColorBg; 464} ui_browser__colorsets[] = {
337 const char *selColorFg, *selColorBg; 465 {
338 const char *codeColorFg, *codeColorBg; 466 .colorset = HE_COLORSET_TOP,
339} defaultPercentTreeColors = { 467 .name = "top",
340 "red", "lightgray", 468 .fg = "red",
341 "green", "lightgray", 469 .bg = "default",
342 "black", "lightgray", 470 },
343 "lightgray", "magenta", 471 {
344 "blue", "lightgray", 472 .colorset = HE_COLORSET_MEDIUM,
473 .name = "medium",
474 .fg = "green",
475 .bg = "default",
476 },
477 {
478 .colorset = HE_COLORSET_NORMAL,
479 .name = "normal",
480 .fg = "default",
481 .bg = "default",
482 },
483 {
484 .colorset = HE_COLORSET_SELECTED,
485 .name = "selected",
486 .fg = "black",
487 .bg = "lightgray",
488 },
489 {
490 .colorset = HE_COLORSET_CODE,
491 .name = "code",
492 .fg = "blue",
493 .bg = "default",
494 },
495 {
496 .name = NULL,
497 }
345}; 498};
346 499
500
501static int ui_browser__color_config(const char *var, const char *value,
502 void *data __used)
503{
504 char *fg = NULL, *bg;
505 int i;
506
507 /* same dir for all commands */
508 if (prefixcmp(var, "colors.") != 0)
509 return 0;
510
511 for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
512 const char *name = var + 7;
513
514 if (strcmp(ui_browser__colorsets[i].name, name) != 0)
515 continue;
516
517 fg = strdup(value);
518 if (fg == NULL)
519 break;
520
521 bg = strchr(fg, ',');
522 if (bg == NULL)
523 break;
524
525 *bg = '\0';
526 while (isspace(*++bg));
527 ui_browser__colorsets[i].bg = bg;
528 ui_browser__colorsets[i].fg = fg;
529 return 0;
530 }
531
532 free(fg);
533 return -1;
534}
535
347void ui_browser__init(void) 536void ui_browser__init(void)
348{ 537{
349 struct newtPercentTreeColors *c = &defaultPercentTreeColors; 538 int i = 0;
350 539
351 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); 540 perf_config(ui_browser__color_config, NULL);
352 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); 541
353 sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg); 542 while (ui_browser__colorsets[i].name) {
354 sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg); 543 struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
355 sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg); 544 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
545 }
356} 546}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index fc63dda10910..a2c707d33c5e 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -2,7 +2,6 @@
2#define _PERF_UI_BROWSER_H_ 1 2#define _PERF_UI_BROWSER_H_ 1
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <newt.h>
6#include <sys/types.h> 5#include <sys/types.h>
7#include "../types.h" 6#include "../types.h"
8 7
@@ -13,15 +12,19 @@
13#define HE_COLORSET_CODE 54 12#define HE_COLORSET_CODE 54
14 13
15struct ui_browser { 14struct ui_browser {
16 newtComponent form, sb;
17 u64 index, top_idx; 15 u64 index, top_idx;
18 void *top, *entries; 16 void *top, *entries;
19 u16 y, x, width, height; 17 u16 y, x, width, height;
20 void *priv; 18 void *priv;
19 const char *title;
20 char *helpline;
21 unsigned int (*refresh)(struct ui_browser *self); 21 unsigned int (*refresh)(struct ui_browser *self);
22 void (*write)(struct ui_browser *self, void *entry, int row); 22 void (*write)(struct ui_browser *self, void *entry, int row);
23 void (*seek)(struct ui_browser *self, off_t offset, int whence); 23 void (*seek)(struct ui_browser *self, off_t offset, int whence);
24 bool (*filter)(struct ui_browser *self, void *entry);
24 u32 nr_entries; 25 u32 nr_entries;
26 bool navkeypressed;
27 bool use_navkeypressed;
25}; 28};
26 29
27void ui_browser__set_color(struct ui_browser *self, int color); 30void ui_browser__set_color(struct ui_browser *self, int color);
@@ -32,15 +35,14 @@ void ui_browser__refresh_dimensions(struct ui_browser *self);
32void ui_browser__reset_index(struct ui_browser *self); 35void ui_browser__reset_index(struct ui_browser *self);
33 36
34void ui_browser__gotorc(struct ui_browser *self, int y, int x); 37void ui_browser__gotorc(struct ui_browser *self, int y, int x);
35void ui_browser__add_exit_key(struct ui_browser *self, int key);
36void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]);
37void __ui_browser__show_title(struct ui_browser *browser, const char *title); 38void __ui_browser__show_title(struct ui_browser *browser, const char *title);
38void ui_browser__show_title(struct ui_browser *browser, const char *title); 39void ui_browser__show_title(struct ui_browser *browser, const char *title);
39int ui_browser__show(struct ui_browser *self, const char *title, 40int ui_browser__show(struct ui_browser *self, const char *title,
40 const char *helpline, ...); 41 const char *helpline, ...);
41void ui_browser__hide(struct ui_browser *self); 42void ui_browser__hide(struct ui_browser *self);
42int ui_browser__refresh(struct ui_browser *self); 43int ui_browser__refresh(struct ui_browser *self);
43int ui_browser__run(struct ui_browser *self); 44int ui_browser__run(struct ui_browser *browser, int delay_secs);
45void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
44 46
45void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); 47void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
46unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); 48unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 0229723aceb3..4e0cb7fea7d9 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -6,6 +6,7 @@
6#include "../../sort.h" 6#include "../../sort.h"
7#include "../../symbol.h" 7#include "../../symbol.h"
8#include <pthread.h> 8#include <pthread.h>
9#include <newt.h>
9 10
10static void ui__error_window(const char *fmt, ...) 11static void ui__error_window(const char *fmt, ...)
11{ 12{
@@ -20,12 +21,17 @@ struct annotate_browser {
20 struct ui_browser b; 21 struct ui_browser b;
21 struct rb_root entries; 22 struct rb_root entries;
22 struct rb_node *curr_hot; 23 struct rb_node *curr_hot;
24 struct objdump_line *selection;
25 int nr_asm_entries;
26 int nr_entries;
27 bool hide_src_code;
23}; 28};
24 29
25struct objdump_line_rb_node { 30struct objdump_line_rb_node {
26 struct rb_node rb_node; 31 struct rb_node rb_node;
27 double percent; 32 double percent;
28 u32 idx; 33 u32 idx;
34 int idx_asm;
29}; 35};
30 36
31static inline 37static inline
@@ -34,9 +40,22 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
34 return (struct objdump_line_rb_node *)(self + 1); 40 return (struct objdump_line_rb_node *)(self + 1);
35} 41}
36 42
43static bool objdump_line__filter(struct ui_browser *browser, void *entry)
44{
45 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
46
47 if (ab->hide_src_code) {
48 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
49 return ol->offset == -1;
50 }
51
52 return false;
53}
54
37static void annotate_browser__write(struct ui_browser *self, void *entry, int row) 55static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
38{ 56{
39 struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); 57 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
58 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
40 bool current_entry = ui_browser__is_current_entry(self, row); 59 bool current_entry = ui_browser__is_current_entry(self, row);
41 int width = self->width; 60 int width = self->width;
42 61
@@ -51,6 +70,11 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
51 70
52 SLsmg_write_char(':'); 71 SLsmg_write_char(':');
53 slsmg_write_nstring(" ", 8); 72 slsmg_write_nstring(" ", 8);
73
74 /* The scroll bar isn't being used */
75 if (!self->navkeypressed)
76 width += 1;
77
54 if (!*ol->line) 78 if (!*ol->line)
55 slsmg_write_nstring(" ", width - 18); 79 slsmg_write_nstring(" ", width - 18);
56 else 80 else
@@ -58,6 +82,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
58 82
59 if (!current_entry) 83 if (!current_entry)
60 ui_browser__set_color(self, HE_COLORSET_CODE); 84 ui_browser__set_color(self, HE_COLORSET_CODE);
85 else
86 ab->selection = ol;
61} 87}
62 88
63static double objdump_line__calc_percent(struct objdump_line *self, 89static double objdump_line__calc_percent(struct objdump_line *self,
@@ -141,7 +167,8 @@ static void annotate_browser__set_top(struct annotate_browser *self,
141static void annotate_browser__calc_percent(struct annotate_browser *browser, 167static void annotate_browser__calc_percent(struct annotate_browser *browser,
142 int evidx) 168 int evidx)
143{ 169{
144 struct symbol *sym = browser->b.priv; 170 struct map_symbol *ms = browser->b.priv;
171 struct symbol *sym = ms->sym;
145 struct annotation *notes = symbol__annotation(sym); 172 struct annotation *notes = symbol__annotation(sym);
146 struct objdump_line *pos; 173 struct objdump_line *pos;
147 174
@@ -163,25 +190,60 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
163 browser->curr_hot = rb_last(&browser->entries); 190 browser->curr_hot = rb_last(&browser->entries);
164} 191}
165 192
193static bool annotate_browser__toggle_source(struct annotate_browser *browser)
194{
195 struct objdump_line *ol;
196 struct objdump_line_rb_node *olrb;
197 off_t offset = browser->b.index - browser->b.top_idx;
198
199 browser->b.seek(&browser->b, offset, SEEK_CUR);
200 ol = list_entry(browser->b.top, struct objdump_line, node);
201 olrb = objdump_line__rb(ol);
202
203 if (browser->hide_src_code) {
204 if (olrb->idx_asm < offset)
205 offset = olrb->idx;
206
207 browser->b.nr_entries = browser->nr_entries;
208 browser->hide_src_code = false;
209 browser->b.seek(&browser->b, -offset, SEEK_CUR);
210 browser->b.top_idx = olrb->idx - offset;
211 browser->b.index = olrb->idx;
212 } else {
213 if (olrb->idx_asm < 0) {
214 ui_helpline__puts("Only available for assembly lines.");
215 browser->b.seek(&browser->b, -offset, SEEK_CUR);
216 return false;
217 }
218
219 if (olrb->idx_asm < offset)
220 offset = olrb->idx_asm;
221
222 browser->b.nr_entries = browser->nr_asm_entries;
223 browser->hide_src_code = true;
224 browser->b.seek(&browser->b, -offset, SEEK_CUR);
225 browser->b.top_idx = olrb->idx_asm - offset;
226 browser->b.index = olrb->idx_asm;
227 }
228
229 return true;
230}
231
166static int annotate_browser__run(struct annotate_browser *self, int evidx, 232static int annotate_browser__run(struct annotate_browser *self, int evidx,
167 int refresh) 233 int nr_events, void(*timer)(void *arg),
234 void *arg, int delay_secs)
168{ 235{
169 struct rb_node *nd = NULL; 236 struct rb_node *nd = NULL;
170 struct symbol *sym = self->b.priv; 237 struct map_symbol *ms = self->b.priv;
171 /* 238 struct symbol *sym = ms->sym;
172 * RIGHT To allow builtin-annotate to cycle thru multiple symbols by 239 const char *help = "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, "
173 * examining the exit key for this function. 240 "H: Hottest, -> Line action, S -> Toggle source "
174 */ 241 "code view";
175 int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
176 NEWT_KEY_RIGHT, 0 };
177 int key; 242 int key;
178 243
179 if (ui_browser__show(&self->b, sym->name, 244 if (ui_browser__show(&self->b, sym->name, help) < 0)
180 "<-, -> or ESC: exit, TAB/shift+TAB: "
181 "cycle hottest lines, H: Hottest") < 0)
182 return -1; 245 return -1;
183 246
184 ui_browser__add_exit_keys(&self->b, exit_keys);
185 annotate_browser__calc_percent(self, evidx); 247 annotate_browser__calc_percent(self, evidx);
186 248
187 if (self->curr_hot) 249 if (self->curr_hot)
@@ -189,13 +251,10 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
189 251
190 nd = self->curr_hot; 252 nd = self->curr_hot;
191 253
192 if (refresh != 0)
193 newtFormSetTimer(self->b.form, refresh);
194
195 while (1) { 254 while (1) {
196 key = ui_browser__run(&self->b); 255 key = ui_browser__run(&self->b, delay_secs);
197 256
198 if (refresh != 0) { 257 if (delay_secs != 0) {
199 annotate_browser__calc_percent(self, evidx); 258 annotate_browser__calc_percent(self, evidx);
200 /* 259 /*
201 * Current line focus got out of the list of most active 260 * Current line focus got out of the list of most active
@@ -207,15 +266,14 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
207 } 266 }
208 267
209 switch (key) { 268 switch (key) {
210 case -1: 269 case K_TIMER:
211 /* 270 if (timer != NULL)
212 * FIXME we need to check if it was 271 timer(arg);
213 * es.reason == NEWT_EXIT_TIMER 272
214 */ 273 if (delay_secs != 0)
215 if (refresh != 0)
216 symbol__annotate_decay_histogram(sym, evidx); 274 symbol__annotate_decay_histogram(sym, evidx);
217 continue; 275 continue;
218 case NEWT_KEY_TAB: 276 case K_TAB:
219 if (nd != NULL) { 277 if (nd != NULL) {
220 nd = rb_prev(nd); 278 nd = rb_prev(nd);
221 if (nd == NULL) 279 if (nd == NULL)
@@ -223,7 +281,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
223 } else 281 } else
224 nd = self->curr_hot; 282 nd = self->curr_hot;
225 break; 283 break;
226 case NEWT_KEY_UNTAB: 284 case K_UNTAB:
227 if (nd != NULL) 285 if (nd != NULL)
228 nd = rb_next(nd); 286 nd = rb_next(nd);
229 if (nd == NULL) 287 if (nd == NULL)
@@ -234,8 +292,68 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
234 case 'H': 292 case 'H':
235 nd = self->curr_hot; 293 nd = self->curr_hot;
236 break; 294 break;
237 default: 295 case 'S':
296 if (annotate_browser__toggle_source(self))
297 ui_helpline__puts(help);
298 continue;
299 case K_ENTER:
300 case K_RIGHT:
301 if (self->selection == NULL) {
302 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
303 continue;
304 }
305
306 if (self->selection->offset == -1) {
307 ui_helpline__puts("Actions are only available for assembly lines.");
308 continue;
309 } else {
310 char *s = strstr(self->selection->line, "callq ");
311 struct annotation *notes;
312 struct symbol *target;
313 u64 ip;
314
315 if (s == NULL) {
316 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
317 continue;
318 }
319
320 s = strchr(s, ' ');
321 if (s++ == NULL) {
322 ui_helpline__puts("Invallid callq instruction.");
323 continue;
324 }
325
326 ip = strtoull(s, NULL, 16);
327 ip = ms->map->map_ip(ms->map, ip);
328 target = map__find_symbol(ms->map, ip, NULL);
329 if (target == NULL) {
330 ui_helpline__puts("The called function was not found.");
331 continue;
332 }
333
334 notes = symbol__annotation(target);
335 pthread_mutex_lock(&notes->lock);
336
337 if (notes->src == NULL &&
338 symbol__alloc_hist(target, nr_events) < 0) {
339 pthread_mutex_unlock(&notes->lock);
340 ui__warning("Not enough memory for annotating '%s' symbol!\n",
341 target->name);
342 continue;
343 }
344
345 pthread_mutex_unlock(&notes->lock);
346 symbol__tui_annotate(target, ms->map, evidx, nr_events,
347 timer, arg, delay_secs);
348 }
349 continue;
350 case K_LEFT:
351 case K_ESC:
352 case 'q':
353 case CTRL('c'):
238 goto out; 354 goto out;
355 default:
356 continue;
239 } 357 }
240 358
241 if (nd != NULL) 359 if (nd != NULL)
@@ -246,22 +364,31 @@ out:
246 return key; 364 return key;
247} 365}
248 366
249int hist_entry__tui_annotate(struct hist_entry *he, int evidx) 367int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
368 void(*timer)(void *arg), void *arg, int delay_secs)
250{ 369{
251 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0); 370 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events,
371 timer, arg, delay_secs);
252} 372}
253 373
254int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 374int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
255 int refresh) 375 int nr_events, void(*timer)(void *arg), void *arg,
376 int delay_secs)
256{ 377{
257 struct objdump_line *pos, *n; 378 struct objdump_line *pos, *n;
258 struct annotation *notes; 379 struct annotation *notes;
380 struct map_symbol ms = {
381 .map = map,
382 .sym = sym,
383 };
259 struct annotate_browser browser = { 384 struct annotate_browser browser = {
260 .b = { 385 .b = {
261 .refresh = ui_browser__list_head_refresh, 386 .refresh = ui_browser__list_head_refresh,
262 .seek = ui_browser__list_head_seek, 387 .seek = ui_browser__list_head_seek,
263 .write = annotate_browser__write, 388 .write = annotate_browser__write,
264 .priv = sym, 389 .filter = objdump_line__filter,
390 .priv = &ms,
391 .use_navkeypressed = true,
265 }, 392 },
266 }; 393 };
267 int ret; 394 int ret;
@@ -288,12 +415,18 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
288 if (browser.b.width < line_len) 415 if (browser.b.width < line_len)
289 browser.b.width = line_len; 416 browser.b.width = line_len;
290 rbpos = objdump_line__rb(pos); 417 rbpos = objdump_line__rb(pos);
291 rbpos->idx = browser.b.nr_entries++; 418 rbpos->idx = browser.nr_entries++;
419 if (pos->offset != -1)
420 rbpos->idx_asm = browser.nr_asm_entries++;
421 else
422 rbpos->idx_asm = -1;
292 } 423 }
293 424
425 browser.b.nr_entries = browser.nr_entries;
294 browser.b.entries = &notes->src->source, 426 browser.b.entries = &notes->src->source,
295 browser.b.width += 18; /* Percentage */ 427 browser.b.width += 18; /* Percentage */
296 ret = annotate_browser__run(&browser, evidx, refresh); 428 ret = annotate_browser__run(&browser, evidx, nr_events,
429 timer, arg, delay_secs);
297 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 430 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
298 list_del(&pos->node); 431 list_del(&pos->node);
299 objdump_line__free(pos); 432 objdump_line__free(pos);
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 5d767c622dfc..4663dcb2a19b 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -24,8 +24,12 @@ struct hist_browser {
24 struct hists *hists; 24 struct hists *hists;
25 struct hist_entry *he_selection; 25 struct hist_entry *he_selection;
26 struct map_symbol *selection; 26 struct map_symbol *selection;
27 bool has_symbols;
27}; 28};
28 29
30static int hists__browser_title(struct hists *self, char *bf, size_t size,
31 const char *ev_name);
32
29static void hist_browser__refresh_dimensions(struct hist_browser *self) 33static void hist_browser__refresh_dimensions(struct hist_browser *self)
30{ 34{
31 /* 3 == +/- toggle symbol before actual hist_entry rendering */ 35 /* 3 == +/- toggle symbol before actual hist_entry rendering */
@@ -290,28 +294,34 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
290 ui_browser__reset_index(&self->b); 294 ui_browser__reset_index(&self->b);
291} 295}
292 296
293static int hist_browser__run(struct hist_browser *self, const char *title) 297static int hist_browser__run(struct hist_browser *self, const char *ev_name,
298 void(*timer)(void *arg), void *arg, int delay_secs)
294{ 299{
295 int key; 300 int key;
296 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', 301 char title[160];
297 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT,
298 NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, };
299 302
300 self->b.entries = &self->hists->entries; 303 self->b.entries = &self->hists->entries;
301 self->b.nr_entries = self->hists->nr_entries; 304 self->b.nr_entries = self->hists->nr_entries;
302 305
303 hist_browser__refresh_dimensions(self); 306 hist_browser__refresh_dimensions(self);
307 hists__browser_title(self->hists, title, sizeof(title), ev_name);
304 308
305 if (ui_browser__show(&self->b, title, 309 if (ui_browser__show(&self->b, title,
306 "Press '?' for help on key bindings") < 0) 310 "Press '?' for help on key bindings") < 0)
307 return -1; 311 return -1;
308 312
309 ui_browser__add_exit_keys(&self->b, exit_keys);
310
311 while (1) { 313 while (1) {
312 key = ui_browser__run(&self->b); 314 key = ui_browser__run(&self->b, delay_secs);
313 315
314 switch (key) { 316 switch (key) {
317 case -1:
318 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
319 timer(arg);
320 ui_browser__update_nr_entries(&self->b, self->hists->nr_entries);
321 hists__browser_title(self->hists, title, sizeof(title),
322 ev_name);
323 ui_browser__show_title(&self->b, title);
324 continue;
315 case 'D': { /* Debug */ 325 case 'D': { /* Debug */
316 static int seq; 326 static int seq;
317 struct hist_entry *h = rb_entry(self->b.top, 327 struct hist_entry *h = rb_entry(self->b.top,
@@ -334,7 +344,7 @@ static int hist_browser__run(struct hist_browser *self, const char *title)
334 /* Expand the whole world. */ 344 /* Expand the whole world. */
335 hist_browser__set_folding(self, true); 345 hist_browser__set_folding(self, true);
336 break; 346 break;
337 case NEWT_KEY_ENTER: 347 case K_ENTER:
338 if (hist_browser__toggle_fold(self)) 348 if (hist_browser__toggle_fold(self))
339 break; 349 break;
340 /* fall thru */ 350 /* fall thru */
@@ -532,7 +542,7 @@ static int hist_browser__show_entry(struct hist_browser *self,
532 char s[256]; 542 char s[256];
533 double percent; 543 double percent;
534 int printed = 0; 544 int printed = 0;
535 int color, width = self->b.width; 545 int width = self->b.width - 6; /* The percentage */
536 char folded_sign = ' '; 546 char folded_sign = ' ';
537 bool current_entry = ui_browser__is_current_entry(&self->b, row); 547 bool current_entry = ui_browser__is_current_entry(&self->b, row);
538 off_t row_offset = entry->row_offset; 548 off_t row_offset = entry->row_offset;
@@ -548,26 +558,35 @@ static int hist_browser__show_entry(struct hist_browser *self,
548 } 558 }
549 559
550 if (row_offset == 0) { 560 if (row_offset == 0) {
551 hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false, 561 hist_entry__snprintf(entry, s, sizeof(s), self->hists);
552 0, false, self->hists->stats.total_period);
553 percent = (entry->period * 100.0) / self->hists->stats.total_period; 562 percent = (entry->period * 100.0) / self->hists->stats.total_period;
554 563
555 color = HE_COLORSET_SELECTED; 564 ui_browser__set_percent_color(&self->b, percent, current_entry);
556 if (!current_entry) {
557 if (percent >= MIN_RED)
558 color = HE_COLORSET_TOP;
559 else if (percent >= MIN_GREEN)
560 color = HE_COLORSET_MEDIUM;
561 else
562 color = HE_COLORSET_NORMAL;
563 }
564
565 ui_browser__set_color(&self->b, color);
566 ui_browser__gotorc(&self->b, row, 0); 565 ui_browser__gotorc(&self->b, row, 0);
567 if (symbol_conf.use_callchain) { 566 if (symbol_conf.use_callchain) {
568 slsmg_printf("%c ", folded_sign); 567 slsmg_printf("%c ", folded_sign);
569 width -= 2; 568 width -= 2;
570 } 569 }
570
571 slsmg_printf(" %5.2f%%", percent);
572
573 /* The scroll bar isn't being used */
574 if (!self->b.navkeypressed)
575 width += 1;
576
577 if (!current_entry || !self->b.navkeypressed)
578 ui_browser__set_color(&self->b, HE_COLORSET_NORMAL);
579
580 if (symbol_conf.show_nr_samples) {
581 slsmg_printf(" %11u", entry->nr_events);
582 width -= 12;
583 }
584
585 if (symbol_conf.show_total_period) {
586 slsmg_printf(" %12" PRIu64, entry->period);
587 width -= 13;
588 }
589
571 slsmg_write_nstring(s, width); 590 slsmg_write_nstring(s, width);
572 ++row; 591 ++row;
573 ++printed; 592 ++printed;
@@ -585,14 +604,23 @@ static int hist_browser__show_entry(struct hist_browser *self,
585 return printed; 604 return printed;
586} 605}
587 606
607static void ui_browser__hists_init_top(struct ui_browser *browser)
608{
609 if (browser->top == NULL) {
610 struct hist_browser *hb;
611
612 hb = container_of(browser, struct hist_browser, b);
613 browser->top = rb_first(&hb->hists->entries);
614 }
615}
616
588static unsigned int hist_browser__refresh(struct ui_browser *self) 617static unsigned int hist_browser__refresh(struct ui_browser *self)
589{ 618{
590 unsigned row = 0; 619 unsigned row = 0;
591 struct rb_node *nd; 620 struct rb_node *nd;
592 struct hist_browser *hb = container_of(self, struct hist_browser, b); 621 struct hist_browser *hb = container_of(self, struct hist_browser, b);
593 622
594 if (self->top == NULL) 623 ui_browser__hists_init_top(self);
595 self->top = rb_first(&hb->hists->entries);
596 624
597 for (nd = self->top; nd; nd = rb_next(nd)) { 625 for (nd = self->top; nd; nd = rb_next(nd)) {
598 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 626 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -644,6 +672,8 @@ static void ui_browser__hists_seek(struct ui_browser *self,
644 if (self->nr_entries == 0) 672 if (self->nr_entries == 0)
645 return; 673 return;
646 674
675 ui_browser__hists_init_top(self);
676
647 switch (whence) { 677 switch (whence) {
648 case SEEK_SET: 678 case SEEK_SET:
649 nd = hists__filter_entries(rb_first(self->entries)); 679 nd = hists__filter_entries(rb_first(self->entries));
@@ -761,6 +791,8 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
761 self->hists = hists; 791 self->hists = hists;
762 self->b.refresh = hist_browser__refresh; 792 self->b.refresh = hist_browser__refresh;
763 self->b.seek = ui_browser__hists_seek; 793 self->b.seek = ui_browser__hists_seek;
794 self->b.use_navkeypressed = true,
795 self->has_symbols = sort_sym.list.next != NULL;
764 } 796 }
765 797
766 return self; 798 return self;
@@ -782,11 +814,12 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self)
782} 814}
783 815
784static int hists__browser_title(struct hists *self, char *bf, size_t size, 816static int hists__browser_title(struct hists *self, char *bf, size_t size,
785 const char *ev_name, const struct dso *dso, 817 const char *ev_name)
786 const struct thread *thread)
787{ 818{
788 char unit; 819 char unit;
789 int printed; 820 int printed;
821 const struct dso *dso = self->dso_filter;
822 const struct thread *thread = self->thread_filter;
790 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; 823 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
791 824
792 nr_events = convert_unit(nr_events, &unit); 825 nr_events = convert_unit(nr_events, &unit);
@@ -803,16 +836,15 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
803 return printed; 836 return printed;
804} 837}
805 838
806static int perf_evsel__hists_browse(struct perf_evsel *evsel, 839static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
807 const char *helpline, const char *ev_name, 840 const char *helpline, const char *ev_name,
808 bool left_exits) 841 bool left_exits,
842 void(*timer)(void *arg), void *arg,
843 int delay_secs)
809{ 844{
810 struct hists *self = &evsel->hists; 845 struct hists *self = &evsel->hists;
811 struct hist_browser *browser = hist_browser__new(self); 846 struct hist_browser *browser = hist_browser__new(self);
812 struct pstack *fstack; 847 struct pstack *fstack;
813 const struct thread *thread_filter = NULL;
814 const struct dso *dso_filter = NULL;
815 char msg[160];
816 int key = -1; 848 int key = -1;
817 849
818 if (browser == NULL) 850 if (browser == NULL)
@@ -824,8 +856,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
824 856
825 ui_helpline__push(helpline); 857 ui_helpline__push(helpline);
826 858
827 hists__browser_title(self, msg, sizeof(msg), ev_name,
828 dso_filter, thread_filter);
829 while (1) { 859 while (1) {
830 const struct thread *thread = NULL; 860 const struct thread *thread = NULL;
831 const struct dso *dso = NULL; 861 const struct dso *dso = NULL;
@@ -834,7 +864,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
834 annotate = -2, zoom_dso = -2, zoom_thread = -2, 864 annotate = -2, zoom_dso = -2, zoom_thread = -2,
835 browse_map = -2; 865 browse_map = -2;
836 866
837 key = hist_browser__run(browser, msg); 867 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
838 868
839 if (browser->he_selection != NULL) { 869 if (browser->he_selection != NULL) {
840 thread = hist_browser__selected_thread(browser); 870 thread = hist_browser__selected_thread(browser);
@@ -842,14 +872,23 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
842 } 872 }
843 873
844 switch (key) { 874 switch (key) {
845 case NEWT_KEY_TAB: 875 case K_TAB:
846 case NEWT_KEY_UNTAB: 876 case K_UNTAB:
877 if (nr_events == 1)
878 continue;
847 /* 879 /*
848 * Exit the browser, let hists__browser_tree 880 * Exit the browser, let hists__browser_tree
849 * go to the next or previous 881 * go to the next or previous
850 */ 882 */
851 goto out_free_stack; 883 goto out_free_stack;
852 case 'a': 884 case 'a':
885 if (!browser->has_symbols) {
886 ui__warning(
887 "Annotation is only available for symbolic views, "
888 "include \"sym\" in --sort to use it.");
889 continue;
890 }
891
853 if (browser->selection == NULL || 892 if (browser->selection == NULL ||
854 browser->selection->sym == NULL || 893 browser->selection->sym == NULL ||
855 browser->selection->map->dso->annotate_warned) 894 browser->selection->map->dso->annotate_warned)
@@ -859,25 +898,29 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
859 goto zoom_dso; 898 goto zoom_dso;
860 case 't': 899 case 't':
861 goto zoom_thread; 900 goto zoom_thread;
862 case NEWT_KEY_F1: 901 case K_F1:
863 case 'h': 902 case 'h':
864 case '?': 903 case '?':
865 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n" 904 ui__help_window("h/?/F1 Show this window\n"
866 "<- Zoom out\n" 905 "UP/DOWN/PGUP\n"
867 "a Annotate current symbol\n" 906 "PGDN/SPACE Navigate\n"
868 "h/?/F1 Show this window\n" 907 "q/ESC/CTRL+C Exit browser\n\n"
869 "C Collapse all callchains\n" 908 "For multiple event sessions:\n\n"
870 "E Expand all callchains\n" 909 "TAB/UNTAB Switch events\n\n"
871 "d Zoom into current DSO\n" 910 "For symbolic views (--sort has sym):\n\n"
872 "t Zoom into current Thread\n" 911 "-> Zoom into DSO/Threads & Annotate current symbol\n"
873 "TAB/UNTAB Switch events\n" 912 "<- Zoom out\n"
874 "q/CTRL+C Exit browser"); 913 "a Annotate current symbol\n"
914 "C Collapse all callchains\n"
915 "E Expand all callchains\n"
916 "d Zoom into current DSO\n"
917 "t Zoom into current Thread\n");
875 continue; 918 continue;
876 case NEWT_KEY_ENTER: 919 case K_ENTER:
877 case NEWT_KEY_RIGHT: 920 case K_RIGHT:
878 /* menu */ 921 /* menu */
879 break; 922 break;
880 case NEWT_KEY_LEFT: { 923 case K_LEFT: {
881 const void *top; 924 const void *top;
882 925
883 if (pstack__empty(fstack)) { 926 if (pstack__empty(fstack)) {
@@ -889,21 +932,27 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
889 continue; 932 continue;
890 } 933 }
891 top = pstack__pop(fstack); 934 top = pstack__pop(fstack);
892 if (top == &dso_filter) 935 if (top == &browser->hists->dso_filter)
893 goto zoom_out_dso; 936 goto zoom_out_dso;
894 if (top == &thread_filter) 937 if (top == &browser->hists->thread_filter)
895 goto zoom_out_thread; 938 goto zoom_out_thread;
896 continue; 939 continue;
897 } 940 }
898 case NEWT_KEY_ESCAPE: 941 case K_ESC:
899 if (!left_exits && 942 if (!left_exits &&
900 !ui__dialog_yesno("Do you really want to exit?")) 943 !ui__dialog_yesno("Do you really want to exit?"))
901 continue; 944 continue;
902 /* Fall thru */ 945 /* Fall thru */
903 default: 946 case 'q':
947 case CTRL('c'):
904 goto out_free_stack; 948 goto out_free_stack;
949 default:
950 continue;
905 } 951 }
906 952
953 if (!browser->has_symbols)
954 goto add_exit_option;
955
907 if (browser->selection != NULL && 956 if (browser->selection != NULL &&
908 browser->selection->sym != NULL && 957 browser->selection->sym != NULL &&
909 !browser->selection->map->dso->annotate_warned && 958 !browser->selection->map->dso->annotate_warned &&
@@ -913,14 +962,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
913 962
914 if (thread != NULL && 963 if (thread != NULL &&
915 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 964 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
916 (thread_filter ? "out of" : "into"), 965 (browser->hists->thread_filter ? "out of" : "into"),
917 (thread->comm_set ? thread->comm : ""), 966 (thread->comm_set ? thread->comm : ""),
918 thread->pid) > 0) 967 thread->pid) > 0)
919 zoom_thread = nr_options++; 968 zoom_thread = nr_options++;
920 969
921 if (dso != NULL && 970 if (dso != NULL &&
922 asprintf(&options[nr_options], "Zoom %s %s DSO", 971 asprintf(&options[nr_options], "Zoom %s %s DSO",
923 (dso_filter ? "out of" : "into"), 972 (browser->hists->dso_filter ? "out of" : "into"),
924 (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 973 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
925 zoom_dso = nr_options++; 974 zoom_dso = nr_options++;
926 975
@@ -928,7 +977,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
928 browser->selection->map != NULL && 977 browser->selection->map != NULL &&
929 asprintf(&options[nr_options], "Browse map details") > 0) 978 asprintf(&options[nr_options], "Browse map details") > 0)
930 browse_map = nr_options++; 979 browse_map = nr_options++;
931 980add_exit_option:
932 options[nr_options++] = (char *)"Exit"; 981 options[nr_options++] = (char *)"Exit";
933 982
934 choice = ui__popup_menu(nr_options, options); 983 choice = ui__popup_menu(nr_options, options);
@@ -948,46 +997,52 @@ do_annotate:
948 he = hist_browser__selected_entry(browser); 997 he = hist_browser__selected_entry(browser);
949 if (he == NULL) 998 if (he == NULL)
950 continue; 999 continue;
951 1000 /*
952 hist_entry__tui_annotate(he, evsel->idx); 1001 * Don't let this be freed, say, by hists__decay_entry.
1002 */
1003 he->used = true;
1004 hist_entry__tui_annotate(he, evsel->idx, nr_events,
1005 timer, arg, delay_secs);
1006 he->used = false;
1007 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
953 } else if (choice == browse_map) 1008 } else if (choice == browse_map)
954 map__browse(browser->selection->map); 1009 map__browse(browser->selection->map);
955 else if (choice == zoom_dso) { 1010 else if (choice == zoom_dso) {
956zoom_dso: 1011zoom_dso:
957 if (dso_filter) { 1012 if (browser->hists->dso_filter) {
958 pstack__remove(fstack, &dso_filter); 1013 pstack__remove(fstack, &browser->hists->dso_filter);
959zoom_out_dso: 1014zoom_out_dso:
960 ui_helpline__pop(); 1015 ui_helpline__pop();
961 dso_filter = NULL; 1016 browser->hists->dso_filter = NULL;
1017 sort_dso.elide = false;
962 } else { 1018 } else {
963 if (dso == NULL) 1019 if (dso == NULL)
964 continue; 1020 continue;
965 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1021 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
966 dso->kernel ? "the Kernel" : dso->short_name); 1022 dso->kernel ? "the Kernel" : dso->short_name);
967 dso_filter = dso; 1023 browser->hists->dso_filter = dso;
968 pstack__push(fstack, &dso_filter); 1024 sort_dso.elide = true;
1025 pstack__push(fstack, &browser->hists->dso_filter);
969 } 1026 }
970 hists__filter_by_dso(self, dso_filter); 1027 hists__filter_by_dso(self);
971 hists__browser_title(self, msg, sizeof(msg), ev_name,
972 dso_filter, thread_filter);
973 hist_browser__reset(browser); 1028 hist_browser__reset(browser);
974 } else if (choice == zoom_thread) { 1029 } else if (choice == zoom_thread) {
975zoom_thread: 1030zoom_thread:
976 if (thread_filter) { 1031 if (browser->hists->thread_filter) {
977 pstack__remove(fstack, &thread_filter); 1032 pstack__remove(fstack, &browser->hists->thread_filter);
978zoom_out_thread: 1033zoom_out_thread:
979 ui_helpline__pop(); 1034 ui_helpline__pop();
980 thread_filter = NULL; 1035 browser->hists->thread_filter = NULL;
1036 sort_thread.elide = false;
981 } else { 1037 } else {
982 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1038 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
983 thread->comm_set ? thread->comm : "", 1039 thread->comm_set ? thread->comm : "",
984 thread->pid); 1040 thread->pid);
985 thread_filter = thread; 1041 browser->hists->thread_filter = thread;
986 pstack__push(fstack, &thread_filter); 1042 sort_thread.elide = true;
1043 pstack__push(fstack, &browser->hists->thread_filter);
987 } 1044 }
988 hists__filter_by_thread(self, thread_filter); 1045 hists__filter_by_thread(self);
989 hists__browser_title(self, msg, sizeof(msg), ev_name,
990 dso_filter, thread_filter);
991 hist_browser__reset(browser); 1046 hist_browser__reset(browser);
992 } 1047 }
993 } 1048 }
@@ -1026,9 +1081,10 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1026 menu->selection = evsel; 1081 menu->selection = evsel;
1027} 1082}
1028 1083
1029static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) 1084static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1085 int nr_events, const char *help,
1086 void(*timer)(void *arg), void *arg, int delay_secs)
1030{ 1087{
1031 int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
1032 struct perf_evlist *evlist = menu->b.priv; 1088 struct perf_evlist *evlist = menu->b.priv;
1033 struct perf_evsel *pos; 1089 struct perf_evsel *pos;
1034 const char *ev_name, *title = "Available samples"; 1090 const char *ev_name, *title = "Available samples";
@@ -1038,50 +1094,65 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
1038 "ESC: exit, ENTER|->: Browse histograms") < 0) 1094 "ESC: exit, ENTER|->: Browse histograms") < 0)
1039 return -1; 1095 return -1;
1040 1096
1041 ui_browser__add_exit_keys(&menu->b, exit_keys);
1042
1043 while (1) { 1097 while (1) {
1044 key = ui_browser__run(&menu->b); 1098 key = ui_browser__run(&menu->b, delay_secs);
1045 1099
1046 switch (key) { 1100 switch (key) {
1047 case NEWT_KEY_RIGHT: 1101 case K_TIMER:
1048 case NEWT_KEY_ENTER: 1102 timer(arg);
1103 continue;
1104 case K_RIGHT:
1105 case K_ENTER:
1049 if (!menu->selection) 1106 if (!menu->selection)
1050 continue; 1107 continue;
1051 pos = menu->selection; 1108 pos = menu->selection;
1052browse_hists: 1109browse_hists:
1110 perf_evlist__set_selected(evlist, pos);
1111 /*
1112 * Give the calling tool a chance to populate the non
1113 * default evsel resorted hists tree.
1114 */
1115 if (timer)
1116 timer(arg);
1053 ev_name = event_name(pos); 1117 ev_name = event_name(pos);
1054 key = perf_evsel__hists_browse(pos, help, ev_name, true); 1118 key = perf_evsel__hists_browse(pos, nr_events, help,
1119 ev_name, true, timer,
1120 arg, delay_secs);
1055 ui_browser__show_title(&menu->b, title); 1121 ui_browser__show_title(&menu->b, title);
1056 break; 1122 switch (key) {
1057 case NEWT_KEY_LEFT: 1123 case K_TAB:
1124 if (pos->node.next == &evlist->entries)
1125 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1126 else
1127 pos = list_entry(pos->node.next, struct perf_evsel, node);
1128 goto browse_hists;
1129 case K_UNTAB:
1130 if (pos->node.prev == &evlist->entries)
1131 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1132 else
1133 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1134 goto browse_hists;
1135 case K_ESC:
1136 if (!ui__dialog_yesno("Do you really want to exit?"))
1137 continue;
1138 /* Fall thru */
1139 case 'q':
1140 case CTRL('c'):
1141 goto out;
1142 default:
1143 continue;
1144 }
1145 case K_LEFT:
1058 continue; 1146 continue;
1059 case NEWT_KEY_ESCAPE: 1147 case K_ESC:
1060 if (!ui__dialog_yesno("Do you really want to exit?")) 1148 if (!ui__dialog_yesno("Do you really want to exit?"))
1061 continue; 1149 continue;
1062 /* Fall thru */ 1150 /* Fall thru */
1063 default:
1064 goto out;
1065 }
1066
1067 switch (key) {
1068 case NEWT_KEY_TAB:
1069 if (pos->node.next == &evlist->entries)
1070 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1071 else
1072 pos = list_entry(pos->node.next, struct perf_evsel, node);
1073 goto browse_hists;
1074 case NEWT_KEY_UNTAB:
1075 if (pos->node.prev == &evlist->entries)
1076 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1077 else
1078 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1079 goto browse_hists;
1080 case 'q': 1151 case 'q':
1081 case CTRL('c'): 1152 case CTRL('c'):
1082 goto out; 1153 goto out;
1083 default: 1154 default:
1084 break; 1155 continue;
1085 } 1156 }
1086 } 1157 }
1087 1158
@@ -1091,7 +1162,9 @@ out:
1091} 1162}
1092 1163
1093static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1164static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1094 const char *help) 1165 const char *help,
1166 void(*timer)(void *arg), void *arg,
1167 int delay_secs)
1095{ 1168{
1096 struct perf_evsel *pos; 1169 struct perf_evsel *pos;
1097 struct perf_evsel_menu menu = { 1170 struct perf_evsel_menu menu = {
@@ -1121,18 +1194,24 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1121 pos->name = strdup(ev_name); 1194 pos->name = strdup(ev_name);
1122 } 1195 }
1123 1196
1124 return perf_evsel_menu__run(&menu, help); 1197 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
1198 arg, delay_secs);
1125} 1199}
1126 1200
1127int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help) 1201int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1202 void(*timer)(void *arg), void *arg,
1203 int delay_secs)
1128{ 1204{
1129 1205
1130 if (evlist->nr_entries == 1) { 1206 if (evlist->nr_entries == 1) {
1131 struct perf_evsel *first = list_entry(evlist->entries.next, 1207 struct perf_evsel *first = list_entry(evlist->entries.next,
1132 struct perf_evsel, node); 1208 struct perf_evsel, node);
1133 const char *ev_name = event_name(first); 1209 const char *ev_name = event_name(first);
1134 return perf_evsel__hists_browse(first, help, ev_name, false); 1210 return perf_evsel__hists_browse(first, evlist->nr_entries, help,
1211 ev_name, false, timer, arg,
1212 delay_secs);
1135 } 1213 }
1136 1214
1137 return __perf_evlist__tui_browse_hists(evlist, help); 1215 return __perf_evlist__tui_browse_hists(evlist, help,
1216 timer, arg, delay_secs);
1138} 1217}
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
index 8462bffe20bc..6905bcc8be2d 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -1,5 +1,6 @@
1#include "../libslang.h" 1#include "../libslang.h"
2#include <elf.h> 2#include <elf.h>
3#include <newt.h>
3#include <inttypes.h> 4#include <inttypes.h>
4#include <sys/ttydefaults.h> 5#include <sys/ttydefaults.h>
5#include <ctype.h> 6#include <ctype.h>
@@ -108,11 +109,8 @@ static int map_browser__run(struct map_browser *self)
108 verbose ? "" : "restart with -v to use") < 0) 109 verbose ? "" : "restart with -v to use") < 0)
109 return -1; 110 return -1;
110 111
111 if (verbose)
112 ui_browser__add_exit_key(&self->b, '/');
113
114 while (1) { 112 while (1) {
115 key = ui_browser__run(&self->b); 113 key = ui_browser__run(&self->b, 0);
116 114
117 if (verbose && key == '/') 115 if (verbose && key == '/')
118 map_browser__search(self); 116 map_browser__search(self);
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c
deleted file mode 100644
index 5a06538532af..000000000000
--- a/tools/perf/util/ui/browsers/top.c
+++ /dev/null
@@ -1,213 +0,0 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9#include "../browser.h"
10#include "../../annotate.h"
11#include "../helpline.h"
12#include "../libslang.h"
13#include "../util.h"
14#include "../../evlist.h"
15#include "../../hist.h"
16#include "../../sort.h"
17#include "../../symbol.h"
18#include "../../top.h"
19
20struct perf_top_browser {
21 struct ui_browser b;
22 struct rb_root root;
23 struct sym_entry *selection;
24 float sum_ksamples;
25 int dso_width;
26 int dso_short_width;
27 int sym_width;
28};
29
30static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row)
31{
32 struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b);
33 struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node);
34 bool current_entry = ui_browser__is_current_entry(browser, row);
35 struct symbol *symbol = sym_entry__symbol(syme);
36 struct perf_top *top = browser->priv;
37 int width = browser->width;
38 double pcnt;
39
40 pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) /
41 top_browser->sum_ksamples));
42 ui_browser__set_percent_color(browser, pcnt, current_entry);
43
44 if (top->evlist->nr_entries == 1 || !top->display_weighted) {
45 slsmg_printf("%20.2f ", syme->weight);
46 width -= 24;
47 } else {
48 slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count);
49 width -= 23;
50 }
51
52 slsmg_printf("%4.1f%%", pcnt);
53 width -= 7;
54
55 if (verbose) {
56 slsmg_printf(" %016" PRIx64, symbol->start);
57 width -= 17;
58 }
59
60 slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width,
61 symbol->name);
62 width -= top_browser->sym_width;
63 slsmg_write_nstring(width >= syme->map->dso->long_name_len ?
64 syme->map->dso->long_name :
65 syme->map->dso->short_name, width);
66
67 if (current_entry)
68 top_browser->selection = syme;
69}
70
71static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser)
72{
73 struct perf_top *top = browser->b.priv;
74 u64 top_idx = browser->b.top_idx;
75
76 browser->root = RB_ROOT;
77 browser->b.top = NULL;
78 browser->sum_ksamples = perf_top__decay_samples(top, &browser->root);
79 /*
80 * No active symbols
81 */
82 if (top->rb_entries == 0)
83 return;
84
85 perf_top__find_widths(top, &browser->root, &browser->dso_width,
86 &browser->dso_short_width,
87 &browser->sym_width);
88 if (browser->sym_width + browser->dso_width > browser->b.width - 29) {
89 browser->dso_width = browser->dso_short_width;
90 if (browser->sym_width + browser->dso_width > browser->b.width - 29)
91 browser->sym_width = browser->b.width - browser->dso_width - 29;
92 }
93
94 /*
95 * Adjust the ui_browser indexes since the entries in the browser->root
96 * rb_tree may have changed, then seek it from start, so that we get a
97 * possible new top of the screen.
98 */
99 browser->b.nr_entries = top->rb_entries;
100
101 if (top_idx >= browser->b.nr_entries) {
102 if (browser->b.height >= browser->b.nr_entries)
103 top_idx = browser->b.nr_entries - browser->b.height;
104 else
105 top_idx = 0;
106 }
107
108 if (browser->b.index >= top_idx + browser->b.height)
109 browser->b.index = top_idx + browser->b.index - browser->b.top_idx;
110
111 if (browser->b.index >= browser->b.nr_entries)
112 browser->b.index = browser->b.nr_entries - 1;
113
114 browser->b.top_idx = top_idx;
115 browser->b.seek(&browser->b, top_idx, SEEK_SET);
116}
117
118static void perf_top_browser__annotate(struct perf_top_browser *browser)
119{
120 struct sym_entry *syme = browser->selection;
121 struct symbol *sym = sym_entry__symbol(syme);
122 struct annotation *notes = symbol__annotation(sym);
123 struct perf_top *top = browser->b.priv;
124
125 if (notes->src != NULL)
126 goto do_annotation;
127
128 pthread_mutex_lock(&notes->lock);
129
130 top->sym_filter_entry = NULL;
131
132 if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) {
133 pr_err("Not enough memory for annotating '%s' symbol!\n",
134 sym->name);
135 pthread_mutex_unlock(&notes->lock);
136 return;
137 }
138
139 top->sym_filter_entry = syme;
140
141 pthread_mutex_unlock(&notes->lock);
142do_annotation:
143 symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000);
144}
145
146static int perf_top_browser__run(struct perf_top_browser *browser)
147{
148 int key;
149 char title[160];
150 struct perf_top *top = browser->b.priv;
151 int delay_msecs = top->delay_secs * 1000;
152 int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
153
154 perf_top_browser__update_rb_tree(browser);
155 perf_top__header_snprintf(top, title, sizeof(title));
156 perf_top__reset_sample_counters(top);
157
158 if (ui_browser__show(&browser->b, title,
159 "ESC: exit, ENTER|->|a: Live Annotate") < 0)
160 return -1;
161
162 newtFormSetTimer(browser->b.form, delay_msecs);
163 ui_browser__add_exit_keys(&browser->b, exit_keys);
164
165 while (1) {
166 key = ui_browser__run(&browser->b);
167
168 switch (key) {
169 case -1:
170 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
171 perf_top_browser__update_rb_tree(browser);
172 perf_top__header_snprintf(top, title, sizeof(title));
173 perf_top__reset_sample_counters(top);
174 ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT);
175 SLsmg_gotorc(0, 0);
176 slsmg_write_nstring(title, browser->b.width);
177 break;
178 case 'a':
179 case NEWT_KEY_RIGHT:
180 case NEWT_KEY_ENTER:
181 if (browser->selection)
182 perf_top_browser__annotate(browser);
183 break;
184 case NEWT_KEY_LEFT:
185 continue;
186 case NEWT_KEY_ESCAPE:
187 if (!ui__dialog_yesno("Do you really want to exit?"))
188 continue;
189 /* Fall thru */
190 default:
191 goto out;
192 }
193 }
194out:
195 ui_browser__hide(&browser->b);
196 return key;
197}
198
199int perf_top__tui_browser(struct perf_top *top)
200{
201 struct perf_top_browser browser = {
202 .b = {
203 .entries = &browser.root,
204 .refresh = ui_browser__rb_tree_refresh,
205 .seek = ui_browser__rb_tree_seek,
206 .write = perf_top_browser__write,
207 .priv = top,
208 },
209 };
210
211 ui_helpline__push("Press <- or ESC to exit");
212 return perf_top_browser__run(&browser);
213}
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h
index ab6028d0c401..fdcbc0270acd 100644
--- a/tools/perf/util/ui/helpline.h
+++ b/tools/perf/util/ui/helpline.h
@@ -1,6 +1,9 @@
1#ifndef _PERF_UI_HELPLINE_H_ 1#ifndef _PERF_UI_HELPLINE_H_
2#define _PERF_UI_HELPLINE_H_ 1 2#define _PERF_UI_HELPLINE_H_ 1
3 3
4#include <stdio.h>
5#include <stdarg.h>
6
4void ui_helpline__init(void); 7void ui_helpline__init(void);
5void ui_helpline__pop(void); 8void ui_helpline__pop(void);
6void ui_helpline__push(const char *msg); 9void ui_helpline__push(const char *msg);
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/util/ui/keysyms.h
new file mode 100644
index 000000000000..3458b1985761
--- /dev/null
+++ b/tools/perf/util/ui/keysyms.h
@@ -0,0 +1,25 @@
1#ifndef _PERF_KEYSYMS_H_
2#define _PERF_KEYSYMS_H_ 1
3
4#include "libslang.h"
5
6#define K_DOWN SL_KEY_DOWN
7#define K_END SL_KEY_END
8#define K_ENTER '\r'
9#define K_ESC 033
10#define K_F1 SL_KEY_F(1)
11#define K_HOME SL_KEY_HOME
12#define K_LEFT SL_KEY_LEFT
13#define K_PGDN SL_KEY_NPAGE
14#define K_PGUP SL_KEY_PPAGE
15#define K_RIGHT SL_KEY_RIGHT
16#define K_TAB '\t'
17#define K_UNTAB SL_KEY_UNTAB
18#define K_UP SL_KEY_UP
19
20/* Not really keys */
21#define K_TIMER -1
22#define K_ERROR -2
23#define K_RESIZE -3
24
25#endif /* _PERF_KEYSYMS_H_ */
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h
index 2b63e1c9b181..4d54b6450f5b 100644
--- a/tools/perf/util/ui/libslang.h
+++ b/tools/perf/util/ui/libslang.h
@@ -24,4 +24,6 @@
24#define sltt_set_color SLtt_set_color 24#define sltt_set_color SLtt_set_color
25#endif 25#endif
26 26
27#define SL_KEY_UNTAB 0x1000
28
27#endif /* _PERF_UI_SLANG_H_ */ 29#endif /* _PERF_UI_SLANG_H_ */
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c
index ee46d671db59..1e6ba06980c4 100644
--- a/tools/perf/util/ui/setup.c
+++ b/tools/perf/util/ui/setup.c
@@ -7,6 +7,7 @@
7#include "browser.h" 7#include "browser.h"
8#include "helpline.h" 8#include "helpline.h"
9#include "ui.h" 9#include "ui.h"
10#include "libslang.h"
10 11
11pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; 12pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
12 13
@@ -17,6 +18,33 @@ static void newt_suspend(void *d __used)
17 newtResume(); 18 newtResume();
18} 19}
19 20
21static int ui__init(void)
22{
23 int err = SLkp_init();
24
25 if (err < 0)
26 goto out;
27
28 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
29out:
30 return err;
31}
32
33static void ui__exit(void)
34{
35 SLtt_set_cursor_visibility(1);
36 SLsmg_refresh();
37 SLsmg_reset_smg();
38 SLang_reset_tty();
39}
40
41static void ui__signal(int sig)
42{
43 ui__exit();
44 psignal(sig, "perf");
45 exit(0);
46}
47
20void setup_browser(bool fallback_to_pager) 48void setup_browser(bool fallback_to_pager)
21{ 49{
22 if (!isatty(1) || !use_browser || dump_trace) { 50 if (!isatty(1) || !use_browser || dump_trace) {
@@ -28,10 +56,16 @@ void setup_browser(bool fallback_to_pager)
28 56
29 use_browser = 1; 57 use_browser = 1;
30 newtInit(); 58 newtInit();
31 newtCls(); 59 ui__init();
32 newtSetSuspendCallback(newt_suspend, NULL); 60 newtSetSuspendCallback(newt_suspend, NULL);
33 ui_helpline__init(); 61 ui_helpline__init();
34 ui_browser__init(); 62 ui_browser__init();
63
64 signal(SIGSEGV, ui__signal);
65 signal(SIGFPE, ui__signal);
66 signal(SIGINT, ui__signal);
67 signal(SIGQUIT, ui__signal);
68 signal(SIGTERM, ui__signal);
35} 69}
36 70
37void exit_browser(bool wait_for_ok) 71void exit_browser(bool wait_for_ok)
@@ -41,6 +75,6 @@ void exit_browser(bool wait_for_ok)
41 char title[] = "Fatal Error", ok[] = "Ok"; 75 char title[] = "Fatal Error", ok[] = "Ok";
42 newtWinMessage(title, ok, ui_helpline__last_msg); 76 newtWinMessage(title, ok, ui_helpline__last_msg);
43 } 77 }
44 newtFinished(); 78 ui__exit();
45 } 79 }
46} 80}
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index 94c2cf0a98b8..e8a03aceceb1 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -24,7 +24,7 @@
24 24
25# Set the following to `true' to make a unstripped, unoptimized 25# Set the following to `true' to make a unstripped, unoptimized
26# binary. Leave this set to `false' for production use. 26# binary. Leave this set to `false' for production use.
27DEBUG ?= false 27DEBUG ?= true
28 28
29# make the build silent. Set this to something else to make it noisy again. 29# make the build silent. Set this to something else to make it noisy again.
30V ?= false 30V ?= false
@@ -35,7 +35,7 @@ NLS ?= true
35 35
36# Set the following to 'true' to build/install the 36# Set the following to 'true' to build/install the
37# cpufreq-bench benchmarking tool 37# cpufreq-bench benchmarking tool
38CPUFRQ_BENCH ?= true 38CPUFREQ_BENCH ?= true
39 39
40# Prefix to the directories we're installing to 40# Prefix to the directories we're installing to
41DESTDIR ?= 41DESTDIR ?=
@@ -137,9 +137,10 @@ CFLAGS += -pipe
137ifeq ($(strip $(NLS)),true) 137ifeq ($(strip $(NLS)),true)
138 INSTALL_NLS += install-gmo 138 INSTALL_NLS += install-gmo
139 COMPILE_NLS += create-gmo 139 COMPILE_NLS += create-gmo
140 CFLAGS += -DNLS
140endif 141endif
141 142
142ifeq ($(strip $(CPUFRQ_BENCH)),true) 143ifeq ($(strip $(CPUFREQ_BENCH)),true)
143 INSTALL_BENCH += install-bench 144 INSTALL_BENCH += install-bench
144 COMPILE_BENCH += compile-bench 145 COMPILE_BENCH += compile-bench
145endif 146endif
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile
index dbf13998462a..3326217dd311 100644
--- a/tools/power/cpupower/debug/x86_64/Makefile
+++ b/tools/power/cpupower/debug/x86_64/Makefile
@@ -1,10 +1,10 @@
1default: all 1default: all
2 2
3centrino-decode: centrino-decode.c 3centrino-decode: ../i386/centrino-decode.c
4 $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c 4 $(CC) $(CFLAGS) -o $@ $<
5 5
6powernow-k8-decode: powernow-k8-decode.c 6powernow-k8-decode: ../i386/powernow-k8-decode.c
7 $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c 7 $(CC) $(CFLAGS) -o $@ $<
8 8
9all: centrino-decode powernow-k8-decode 9all: centrino-decode powernow-k8-decode
10 10
diff --git a/tools/power/cpupower/debug/x86_64/centrino-decode.c b/tools/power/cpupower/debug/x86_64/centrino-decode.c
deleted file mode 120000
index 26fb3f1d8fc7..000000000000
--- a/tools/power/cpupower/debug/x86_64/centrino-decode.c
+++ /dev/null
@@ -1 +0,0 @@
1../i386/centrino-decode.c \ No newline at end of file
diff --git a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c b/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c
deleted file mode 120000
index eb30c79cf9df..000000000000
--- a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c
+++ /dev/null
@@ -1 +0,0 @@
1../i386/powernow-k8-decode.c \ No newline at end of file
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1
index 3194811d58f5..bb60a8d1e45a 100644
--- a/tools/power/cpupower/man/cpupower-frequency-info.1
+++ b/tools/power/cpupower/man/cpupower-frequency-info.1
@@ -1,10 +1,10 @@
1.TH "cpufreq-info" "1" "0.1" "Mattia Dongili" "" 1.TH "cpupower-frequency-info" "1" "0.1" "Mattia Dongili" ""
2.SH "NAME" 2.SH "NAME"
3.LP 3.LP
4cpufreq\-info \- Utility to retrieve cpufreq kernel information 4cpupower frequency\-info \- Utility to retrieve cpufreq kernel information
5.SH "SYNTAX" 5.SH "SYNTAX"
6.LP 6.LP
7cpufreq\-info [\fIoptions\fP] 7cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP]
8.SH "DESCRIPTION" 8.SH "DESCRIPTION"
9.LP 9.LP
10A small tool which prints out cpufreq information helpful to developers and interested users. 10A small tool which prints out cpufreq information helpful to developers and interested users.
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1
index 26e3e13eee3b..685f469093ad 100644
--- a/tools/power/cpupower/man/cpupower-frequency-set.1
+++ b/tools/power/cpupower/man/cpupower-frequency-set.1
@@ -1,13 +1,13 @@
1.TH "cpufreq-set" "1" "0.1" "Mattia Dongili" "" 1.TH "cpupower-freqency-set" "1" "0.1" "Mattia Dongili" ""
2.SH "NAME" 2.SH "NAME"
3.LP 3.LP
4cpufreq\-set \- A small tool which allows to modify cpufreq settings. 4cpupower frequency\-set \- A small tool which allows to modify cpufreq settings.
5.SH "SYNTAX" 5.SH "SYNTAX"
6.LP 6.LP
7cpufreq\-set [\fIoptions\fP] 7cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP]
8.SH "DESCRIPTION" 8.SH "DESCRIPTION"
9.LP 9.LP
10cpufreq\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time. 10cpupower frequency\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time.
11.SH "OPTIONS" 11.SH "OPTIONS"
12.LP 12.LP
13.TP 13.TP
diff --git a/tools/power/cpupower/man/cpupower.1 b/tools/power/cpupower/man/cpupower.1
index 78c20feab85c..baf741d06e82 100644
--- a/tools/power/cpupower/man/cpupower.1
+++ b/tools/power/cpupower/man/cpupower.1
@@ -3,7 +3,7 @@
3cpupower \- Shows and sets processor power related values 3cpupower \- Shows and sets processor power related values
4.SH SYNOPSIS 4.SH SYNOPSIS
5.ft B 5.ft B
6.B cpupower [ \-c cpulist ] subcommand [ARGS] 6.B cpupower [ \-c cpulist ] <command> [ARGS]
7 7
8.B cpupower \-v|\-\-version 8.B cpupower \-v|\-\-version
9 9
@@ -13,24 +13,24 @@ cpupower \- Shows and sets processor power related values
13\fBcpupower \fP is a collection of tools to examine and tune power saving 13\fBcpupower \fP is a collection of tools to examine and tune power saving
14related features of your processor. 14related features of your processor.
15 15
16The manpages of the subcommands (cpupower\-<subcommand>(1)) provide detailed 16The manpages of the commands (cpupower\-<command>(1)) provide detailed
17descriptions of supported features. Run \fBcpupower help\fP to get an overview 17descriptions of supported features. Run \fBcpupower help\fP to get an overview
18of supported subcommands. 18of supported commands.
19 19
20.SH Options 20.SH Options
21.PP 21.PP
22\-\-help, \-h 22\-\-help, \-h
23.RS 4 23.RS 4
24Shows supported subcommands and general usage. 24Shows supported commands and general usage.
25.RE 25.RE
26.PP 26.PP
27\-\-cpu cpulist, \-c cpulist 27\-\-cpu cpulist, \-c cpulist
28.RS 4 28.RS 4
29Only show or set values for specific cores. 29Only show or set values for specific cores.
30This option is not supported by all subcommands, details can be found in the 30This option is not supported by all commands, details can be found in the
31manpages of the subcommands. 31manpages of the commands.
32 32
33Some subcommands access all cores (typically the *\-set commands), some only 33Some commands access all cores (typically the *\-set commands), some only
34the first core (typically the *\-info commands) by default. 34the first core (typically the *\-info commands) by default.
35 35
36The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via 36The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h
index c870ffba5219..c10496fbe3c6 100644
--- a/tools/power/cpupower/utils/builtin.h
+++ b/tools/power/cpupower/utils/builtin.h
@@ -8,11 +8,4 @@ extern int cmd_freq_info(int argc, const char **argv);
8extern int cmd_idle_info(int argc, const char **argv); 8extern int cmd_idle_info(int argc, const char **argv);
9extern int cmd_monitor(int argc, const char **argv); 9extern int cmd_monitor(int argc, const char **argv);
10 10
11extern void set_help(void);
12extern void info_help(void);
13extern void freq_set_help(void);
14extern void freq_info_help(void);
15extern void idle_info_help(void);
16extern void monitor_help(void);
17
18#endif 11#endif
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
index 5a1d25f056b3..28953c9a7bd5 100644
--- a/tools/power/cpupower/utils/cpufreq-info.c
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -510,37 +510,6 @@ static int get_latency(unsigned int cpu, unsigned int human)
510 return 0; 510 return 0;
511} 511}
512 512
513void freq_info_help(void)
514{
515 printf(_("Usage: cpupower freqinfo [options]\n"));
516 printf(_("Options:\n"));
517 printf(_(" -e, --debug Prints out debug information [default]\n"));
518 printf(_(" -f, --freq Get frequency the CPU currently runs at, according\n"
519 " to the cpufreq core *\n"));
520 printf(_(" -w, --hwfreq Get frequency the CPU currently runs at, by reading\n"
521 " it from hardware (only available to root) *\n"));
522 printf(_(" -l, --hwlimits Determine the minimum and maximum CPU frequency allowed *\n"));
523 printf(_(" -d, --driver Determines the used cpufreq kernel driver *\n"));
524 printf(_(" -p, --policy Gets the currently used cpufreq policy *\n"));
525 printf(_(" -g, --governors Determines available cpufreq governors *\n"));
526 printf(_(" -r, --related-cpus Determines which CPUs run at the same hardware frequency *\n"));
527 printf(_(" -a, --affected-cpus Determines which CPUs need to have their frequency\n"
528 " coordinated by software *\n"));
529 printf(_(" -s, --stats Shows cpufreq statistics if available\n"));
530 printf(_(" -y, --latency Determines the maximum latency on CPU frequency changes *\n"));
531 printf(_(" -b, --boost Checks for turbo or boost modes *\n"));
532 printf(_(" -o, --proc Prints out information like provided by the /proc/cpufreq\n"
533 " interface in 2.4. and early 2.6. kernels\n"));
534 printf(_(" -m, --human human-readable output for the -f, -w, -s and -y parameters\n"));
535 printf(_(" -h, --help Prints out this screen\n"));
536
537 printf("\n");
538 printf(_("If no argument is given, full output about\n"
539 "cpufreq is printed which is useful e.g. for reporting bugs.\n\n"));
540 printf(_("By default info of CPU 0 is shown which can be overridden\n"
541 "with the cpupower --cpu main command option.\n"));
542}
543
544static struct option info_opts[] = { 513static struct option info_opts[] = {
545 { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'}, 514 { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'},
546 { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'}, 515 { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'},
@@ -556,7 +525,6 @@ static struct option info_opts[] = {
556 { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'}, 525 { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'},
557 { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, 526 { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
558 { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'}, 527 { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'},
559 { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
560 { }, 528 { },
561}; 529};
562 530
@@ -570,16 +538,12 @@ int cmd_freq_info(int argc, char **argv)
570 int output_param = 0; 538 int output_param = 0;
571 539
572 do { 540 do {
573 ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL); 541 ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL);
574 switch (ret) { 542 switch (ret) {
575 case '?': 543 case '?':
576 output_param = '?'; 544 output_param = '?';
577 cont = 0; 545 cont = 0;
578 break; 546 break;
579 case 'h':
580 output_param = 'h';
581 cont = 0;
582 break;
583 case -1: 547 case -1:
584 cont = 0; 548 cont = 0;
585 break; 549 break;
@@ -642,11 +606,7 @@ int cmd_freq_info(int argc, char **argv)
642 return -EINVAL; 606 return -EINVAL;
643 case '?': 607 case '?':
644 printf(_("invalid or unknown argument\n")); 608 printf(_("invalid or unknown argument\n"));
645 freq_info_help();
646 return -EINVAL; 609 return -EINVAL;
647 case 'h':
648 freq_info_help();
649 return EXIT_SUCCESS;
650 case 'o': 610 case 'o':
651 proc_cpufreq_output(); 611 proc_cpufreq_output();
652 return EXIT_SUCCESS; 612 return EXIT_SUCCESS;
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
index 5f783622bf31..dd1539eb8c63 100644
--- a/tools/power/cpupower/utils/cpufreq-set.c
+++ b/tools/power/cpupower/utils/cpufreq-set.c
@@ -20,34 +20,11 @@
20 20
21#define NORM_FREQ_LEN 32 21#define NORM_FREQ_LEN 32
22 22
23void freq_set_help(void)
24{
25 printf(_("Usage: cpupower frequency-set [options]\n"));
26 printf(_("Options:\n"));
27 printf(_(" -d FREQ, --min FREQ new minimum CPU frequency the governor may select\n"));
28 printf(_(" -u FREQ, --max FREQ new maximum CPU frequency the governor may select\n"));
29 printf(_(" -g GOV, --governor GOV new cpufreq governor\n"));
30 printf(_(" -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n"
31 " governor to be available and loaded\n"));
32 printf(_(" -r, --related Switches all hardware-related CPUs\n"));
33 printf(_(" -h, --help Prints out this screen\n"));
34 printf("\n");
35 printf(_("Notes:\n"
36 "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"));
37 printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n"
38 " except the -c CPU, --cpu CPU parameter\n"
39 "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
40 " by postfixing the value with the wanted unit name, without any space\n"
41 " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"));
42
43}
44
45static struct option set_opts[] = { 23static struct option set_opts[] = {
46 { .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'}, 24 { .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'},
47 { .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'}, 25 { .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'},
48 { .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'}, 26 { .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'},
49 { .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'}, 27 { .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'},
50 { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
51 { .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'}, 28 { .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'},
52 { }, 29 { },
53}; 30};
@@ -80,7 +57,6 @@ const struct freq_units def_units[] = {
80static void print_unknown_arg(void) 57static void print_unknown_arg(void)
81{ 58{
82 printf(_("invalid or unknown argument\n")); 59 printf(_("invalid or unknown argument\n"));
83 freq_set_help();
84} 60}
85 61
86static unsigned long string_to_frequency(const char *str) 62static unsigned long string_to_frequency(const char *str)
@@ -231,14 +207,11 @@ int cmd_freq_set(int argc, char **argv)
231 207
232 /* parameter parsing */ 208 /* parameter parsing */
233 do { 209 do {
234 ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL); 210 ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL);
235 switch (ret) { 211 switch (ret) {
236 case '?': 212 case '?':
237 print_unknown_arg(); 213 print_unknown_arg();
238 return -EINVAL; 214 return -EINVAL;
239 case 'h':
240 freq_set_help();
241 return 0;
242 case -1: 215 case -1:
243 cont = 0; 216 cont = 0;
244 break; 217 break;
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index 70da3574f1e9..b028267c1376 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -139,30 +139,14 @@ static void proc_cpuidle_cpu_output(unsigned int cpu)
139 } 139 }
140} 140}
141 141
142/* --freq / -f */
143
144void idle_info_help(void)
145{
146 printf(_ ("Usage: cpupower idleinfo [options]\n"));
147 printf(_ ("Options:\n"));
148 printf(_ (" -s, --silent Only show general C-state information\n"));
149 printf(_ (" -o, --proc Prints out information like provided by the /proc/acpi/processor/*/power\n"
150 " interface in older kernels\n"));
151 printf(_ (" -h, --help Prints out this screen\n"));
152
153 printf("\n");
154}
155
156static struct option info_opts[] = { 142static struct option info_opts[] = {
157 { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'}, 143 { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'},
158 { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, 144 { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
159 { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
160 { }, 145 { },
161}; 146};
162 147
163static inline void cpuidle_exit(int fail) 148static inline void cpuidle_exit(int fail)
164{ 149{
165 idle_info_help();
166 exit(EXIT_FAILURE); 150 exit(EXIT_FAILURE);
167} 151}
168 152
@@ -174,7 +158,7 @@ int cmd_idle_info(int argc, char **argv)
174 unsigned int cpu = 0; 158 unsigned int cpu = 0;
175 159
176 do { 160 do {
177 ret = getopt_long(argc, argv, "hos", info_opts, NULL); 161 ret = getopt_long(argc, argv, "os", info_opts, NULL);
178 if (ret == -1) 162 if (ret == -1)
179 break; 163 break;
180 switch (ret) { 164 switch (ret) {
@@ -182,10 +166,6 @@ int cmd_idle_info(int argc, char **argv)
182 output_param = '?'; 166 output_param = '?';
183 cont = 0; 167 cont = 0;
184 break; 168 break;
185 case 'h':
186 output_param = 'h';
187 cont = 0;
188 break;
189 case 's': 169 case 's':
190 verbose = 0; 170 verbose = 0;
191 break; 171 break;
@@ -211,8 +191,6 @@ int cmd_idle_info(int argc, char **argv)
211 case '?': 191 case '?':
212 printf(_("invalid or unknown argument\n")); 192 printf(_("invalid or unknown argument\n"));
213 cpuidle_exit(EXIT_FAILURE); 193 cpuidle_exit(EXIT_FAILURE);
214 case 'h':
215 cpuidle_exit(EXIT_SUCCESS);
216 } 194 }
217 195
218 /* Default is: show output of CPU 0 only */ 196 /* Default is: show output of CPU 0 only */
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c
index 85253cb7600e..3f68632c28c7 100644
--- a/tools/power/cpupower/utils/cpupower-info.c
+++ b/tools/power/cpupower/utils/cpupower-info.c
@@ -16,31 +16,16 @@
16#include "helpers/helpers.h" 16#include "helpers/helpers.h"
17#include "helpers/sysfs.h" 17#include "helpers/sysfs.h"
18 18
19void info_help(void)
20{
21 printf(_("Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"));
22 printf(_("Options:\n"));
23 printf(_(" -b, --perf-bias Gets CPU's power vs performance policy on some\n"
24 " Intel models [0-15], see manpage for details\n"));
25 printf(_(" -m, --sched-mc Gets the kernel's multi core scheduler policy.\n"));
26 printf(_(" -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n"));
27 printf(_(" -h, --help Prints out this screen\n"));
28 printf(_("\nPassing no option will show all info, by default only on core 0\n"));
29 printf("\n");
30}
31
32static struct option set_opts[] = { 19static struct option set_opts[] = {
33 { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, 20 { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
34 { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, 21 { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'},
35 { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, 22 { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'},
36 { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
37 { }, 23 { },
38}; 24};
39 25
40static void print_wrong_arg_exit(void) 26static void print_wrong_arg_exit(void)
41{ 27{
42 printf(_("invalid or unknown argument\n")); 28 printf(_("invalid or unknown argument\n"));
43 info_help();
44 exit(EXIT_FAILURE); 29 exit(EXIT_FAILURE);
45} 30}
46 31
@@ -64,11 +49,8 @@ int cmd_info(int argc, char **argv)
64 textdomain(PACKAGE); 49 textdomain(PACKAGE);
65 50
66 /* parameter parsing */ 51 /* parameter parsing */
67 while ((ret = getopt_long(argc, argv, "msbh", set_opts, NULL)) != -1) { 52 while ((ret = getopt_long(argc, argv, "msb", set_opts, NULL)) != -1) {
68 switch (ret) { 53 switch (ret) {
69 case 'h':
70 info_help();
71 return 0;
72 case 'b': 54 case 'b':
73 if (params.perf_bias) 55 if (params.perf_bias)
74 print_wrong_arg_exit(); 56 print_wrong_arg_exit();
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c
index bc1b391e46f0..dc4de3762111 100644
--- a/tools/power/cpupower/utils/cpupower-set.c
+++ b/tools/power/cpupower/utils/cpupower-set.c
@@ -17,30 +17,16 @@
17#include "helpers/sysfs.h" 17#include "helpers/sysfs.h"
18#include "helpers/bitmask.h" 18#include "helpers/bitmask.h"
19 19
20void set_help(void)
21{
22 printf(_("Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"));
23 printf(_("Options:\n"));
24 printf(_(" -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n"
25 " Intel models [0-15], see manpage for details\n"));
26 printf(_(" -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n"));
27 printf(_(" -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler policy.\n"));
28 printf(_(" -h, --help Prints out this screen\n"));
29 printf("\n");
30}
31
32static struct option set_opts[] = { 20static struct option set_opts[] = {
33 { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, 21 { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
34 { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, 22 { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'},
35 { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, 23 { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'},
36 { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
37 { }, 24 { },
38}; 25};
39 26
40static void print_wrong_arg_exit(void) 27static void print_wrong_arg_exit(void)
41{ 28{
42 printf(_("invalid or unknown argument\n")); 29 printf(_("invalid or unknown argument\n"));
43 set_help();
44 exit(EXIT_FAILURE); 30 exit(EXIT_FAILURE);
45} 31}
46 32
@@ -66,12 +52,9 @@ int cmd_set(int argc, char **argv)
66 52
67 params.params = 0; 53 params.params = 0;
68 /* parameter parsing */ 54 /* parameter parsing */
69 while ((ret = getopt_long(argc, argv, "m:s:b:h", 55 while ((ret = getopt_long(argc, argv, "m:s:b:",
70 set_opts, NULL)) != -1) { 56 set_opts, NULL)) != -1) {
71 switch (ret) { 57 switch (ret) {
72 case 'h':
73 set_help();
74 return 0;
75 case 'b': 58 case 'b':
76 if (params.perf_bias) 59 if (params.perf_bias)
77 print_wrong_arg_exit(); 60 print_wrong_arg_exit();
@@ -110,10 +93,8 @@ int cmd_set(int argc, char **argv)
110 } 93 }
111 }; 94 };
112 95
113 if (!params.params) { 96 if (!params.params)
114 set_help(); 97 print_wrong_arg_exit();
115 return -EINVAL;
116 }
117 98
118 if (params.sched_mc) { 99 if (params.sched_mc) {
119 ret = sysfs_set_sched("mc", sched_mc); 100 ret = sysfs_set_sched("mc", sched_mc);
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
index 5844ae0f786f..52bee591c1c5 100644
--- a/tools/power/cpupower/utils/cpupower.c
+++ b/tools/power/cpupower/utils/cpupower.c
@@ -11,6 +11,7 @@
11#include <stdlib.h> 11#include <stdlib.h>
12#include <string.h> 12#include <string.h>
13#include <unistd.h> 13#include <unistd.h>
14#include <errno.h>
14 15
15#include "builtin.h" 16#include "builtin.h"
16#include "helpers/helpers.h" 17#include "helpers/helpers.h"
@@ -19,13 +20,12 @@
19struct cmd_struct { 20struct cmd_struct {
20 const char *cmd; 21 const char *cmd;
21 int (*main)(int, const char **); 22 int (*main)(int, const char **);
22 void (*usage)(void);
23 int needs_root; 23 int needs_root;
24}; 24};
25 25
26#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 26#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
27 27
28int cmd_help(int argc, const char **argv); 28static int cmd_help(int argc, const char **argv);
29 29
30/* Global cpu_info object available for all binaries 30/* Global cpu_info object available for all binaries
31 * Info only retrieved from CPU 0 31 * Info only retrieved from CPU 0
@@ -44,55 +44,66 @@ int be_verbose;
44static void print_help(void); 44static void print_help(void);
45 45
46static struct cmd_struct commands[] = { 46static struct cmd_struct commands[] = {
47 { "frequency-info", cmd_freq_info, freq_info_help, 0 }, 47 { "frequency-info", cmd_freq_info, 0 },
48 { "frequency-set", cmd_freq_set, freq_set_help, 1 }, 48 { "frequency-set", cmd_freq_set, 1 },
49 { "idle-info", cmd_idle_info, idle_info_help, 0 }, 49 { "idle-info", cmd_idle_info, 0 },
50 { "set", cmd_set, set_help, 1 }, 50 { "set", cmd_set, 1 },
51 { "info", cmd_info, info_help, 0 }, 51 { "info", cmd_info, 0 },
52 { "monitor", cmd_monitor, monitor_help, 0 }, 52 { "monitor", cmd_monitor, 0 },
53 { "help", cmd_help, print_help, 0 }, 53 { "help", cmd_help, 0 },
54 /* { "bench", cmd_bench, NULL, 1 }, */ 54 /* { "bench", cmd_bench, 1 }, */
55}; 55};
56 56
57int cmd_help(int argc, const char **argv)
58{
59 unsigned int i;
60
61 if (argc > 1) {
62 for (i = 0; i < ARRAY_SIZE(commands); i++) {
63 struct cmd_struct *p = commands + i;
64 if (strcmp(p->cmd, argv[1]))
65 continue;
66 if (p->usage) {
67 p->usage();
68 return EXIT_SUCCESS;
69 }
70 }
71 }
72 print_help();
73 if (argc == 1)
74 return EXIT_SUCCESS; /* cpupower help */
75 return EXIT_FAILURE;
76}
77
78static void print_help(void) 57static void print_help(void)
79{ 58{
80 unsigned int i; 59 unsigned int i;
81 60
82#ifdef DEBUG 61#ifdef DEBUG
83 printf(_("cpupower [ -d ][ -c cpulist ] subcommand [ARGS]\n")); 62 printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n"));
84 printf(_(" -d, --debug May increase output (stderr) on some subcommands\n"));
85#else 63#else
86 printf(_("cpupower [ -c cpulist ] subcommand [ARGS]\n")); 64 printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n"));
87#endif 65#endif
88 printf(_("cpupower --version\n")); 66 printf(_("Supported commands are:\n"));
89 printf(_("Supported subcommands are:\n"));
90 for (i = 0; i < ARRAY_SIZE(commands); i++) 67 for (i = 0; i < ARRAY_SIZE(commands); i++)
91 printf("\t%s\n", commands[i].cmd); 68 printf("\t%s\n", commands[i].cmd);
92 printf(_("\nSome subcommands can make use of the -c cpulist option.\n")); 69 printf(_("\nNot all commands can make use of the -c cpulist option.\n"));
93 printf(_("Look at the general cpupower manpage how to use it\n")); 70 printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n"));
94 printf(_("and read up the subcommand's manpage whether it is supported.\n")); 71}
95 printf(_("\nUse cpupower help subcommand for getting help for above subcommands.\n")); 72
73static int print_man_page(const char *subpage)
74{
75 int len;
76 char *page;
77
78 len = 10; /* enough for "cpupower-" */
79 if (subpage != NULL)
80 len += strlen(subpage);
81
82 page = malloc(len);
83 if (!page)
84 return -ENOMEM;
85
86 sprintf(page, "cpupower");
87 if ((subpage != NULL) && strcmp(subpage, "help")) {
88 strcat(page, "-");
89 strcat(page, subpage);
90 }
91
92 execlp("man", "man", page, NULL);
93
94 /* should not be reached */
95 return -EINVAL;
96}
97
98static int cmd_help(int argc, const char **argv)
99{
100 if (argc > 1) {
101 print_man_page(argv[1]); /* exits within execlp() */
102 return EXIT_FAILURE;
103 }
104
105 print_help();
106 return EXIT_SUCCESS;
96} 107}
97 108
98static void print_version(void) 109static void print_version(void)
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index 592ee362b877..2747e738efb0 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -16,11 +16,20 @@
16#include "helpers/bitmask.h" 16#include "helpers/bitmask.h"
17 17
18/* Internationalization ****************************/ 18/* Internationalization ****************************/
19#ifdef NLS
20
19#define _(String) gettext(String) 21#define _(String) gettext(String)
20#ifndef gettext_noop 22#ifndef gettext_noop
21#define gettext_noop(String) String 23#define gettext_noop(String) String
22#endif 24#endif
23#define N_(String) gettext_noop(String) 25#define N_(String) gettext_noop(String)
26
27#else /* !NLS */
28
29#define _(String) String
30#define N_(String) String
31
32#endif
24/* Internationalization ****************************/ 33/* Internationalization ****************************/
25 34
26extern int run_as_root; 35extern int run_as_root;
@@ -96,6 +105,9 @@ struct cpupower_topology {
96 int pkg; 105 int pkg;
97 int core; 106 int core;
98 int cpu; 107 int cpu;
108
109 /* flags */
110 unsigned int is_online:1;
99 } *core_info; 111 } *core_info;
100}; 112};
101 113
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 55e2466674c6..c6343024a611 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -56,6 +56,56 @@ static unsigned int sysfs_write_file(const char *path,
56 return (unsigned int) numwrite; 56 return (unsigned int) numwrite;
57} 57}
58 58
59/*
60 * Detect whether a CPU is online
61 *
62 * Returns:
63 * 1 -> if CPU is online
64 * 0 -> if CPU is offline
65 * negative errno values in error case
66 */
67int sysfs_is_cpu_online(unsigned int cpu)
68{
69 char path[SYSFS_PATH_MAX];
70 int fd;
71 ssize_t numread;
72 unsigned long long value;
73 char linebuf[MAX_LINE_LEN];
74 char *endp;
75 struct stat statbuf;
76
77 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
78
79 if (stat(path, &statbuf) != 0)
80 return 0;
81
82 /*
83 * kernel without CONFIG_HOTPLUG_CPU
84 * -> cpuX directory exists, but not cpuX/online file
85 */
86 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
87 if (stat(path, &statbuf) != 0)
88 return 1;
89
90 fd = open(path, O_RDONLY);
91 if (fd == -1)
92 return -errno;
93
94 numread = read(fd, linebuf, MAX_LINE_LEN - 1);
95 if (numread < 1) {
96 close(fd);
97 return -EIO;
98 }
99 linebuf[numread] = '\0';
100 close(fd);
101
102 value = strtoull(linebuf, &endp, 0);
103 if (value > 1 || value < 0)
104 return -EINVAL;
105
106 return value;
107}
108
59/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ 109/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
60 110
61/* 111/*
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h
index f9373e090637..8cb797bbceb0 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.h
+++ b/tools/power/cpupower/utils/helpers/sysfs.h
@@ -7,6 +7,8 @@
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 int sysfs_is_cpu_online(unsigned int cpu);
11
10extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, 12extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
11 unsigned int idlestate); 13 unsigned int idlestate);
12extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, 14extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
index 385ee5c7570c..4eae2c47ba48 100644
--- a/tools/power/cpupower/utils/helpers/topology.c
+++ b/tools/power/cpupower/utils/helpers/topology.c
@@ -41,6 +41,8 @@ struct cpuid_core_info {
41 unsigned int pkg; 41 unsigned int pkg;
42 unsigned int thread; 42 unsigned int thread;
43 unsigned int cpu; 43 unsigned int cpu;
44 /* flags */
45 unsigned int is_online:1;
44}; 46};
45 47
46static int __compare(const void *t1, const void *t2) 48static int __compare(const void *t1, const void *t2)
@@ -78,6 +80,8 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
78 return -ENOMEM; 80 return -ENOMEM;
79 cpu_top->pkgs = cpu_top->cores = 0; 81 cpu_top->pkgs = cpu_top->cores = 0;
80 for (cpu = 0; cpu < cpus; cpu++) { 82 for (cpu = 0; cpu < cpus; cpu++) {
83 cpu_top->core_info[cpu].cpu = cpu;
84 cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu);
81 cpu_top->core_info[cpu].pkg = 85 cpu_top->core_info[cpu].pkg =
82 sysfs_topology_read_file(cpu, "physical_package_id"); 86 sysfs_topology_read_file(cpu, "physical_package_id");
83 if ((int)cpu_top->core_info[cpu].pkg != -1 && 87 if ((int)cpu_top->core_info[cpu].pkg != -1 &&
@@ -85,7 +89,6 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
85 cpu_top->pkgs = cpu_top->core_info[cpu].pkg; 89 cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
86 cpu_top->core_info[cpu].core = 90 cpu_top->core_info[cpu].core =
87 sysfs_topology_read_file(cpu, "core_id"); 91 sysfs_topology_read_file(cpu, "core_id");
88 cpu_top->core_info[cpu].cpu = cpu;
89 } 92 }
90 cpu_top->pkgs++; 93 cpu_top->pkgs++;
91 94
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
index d048b96a6155..bcd22a1a3970 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
@@ -134,7 +134,7 @@ static struct cpuidle_monitor *cpuidle_register(void)
134 /* Assume idle state count is the same for all CPUs */ 134 /* Assume idle state count is the same for all CPUs */
135 cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0); 135 cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0);
136 136
137 if (cpuidle_sysfs_monitor.hw_states_num == 0) 137 if (cpuidle_sysfs_monitor.hw_states_num <= 0)
138 return NULL; 138 return NULL;
139 139
140 for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { 140 for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
index ba4bf068380d..0d6571e418db 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
@@ -43,6 +43,12 @@ static struct cpupower_topology cpu_top;
43/* ToDo: Document this in the manpage */ 43/* ToDo: Document this in the manpage */
44static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; 44static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
45 45
46static void print_wrong_arg_exit(void)
47{
48 printf(_("invalid or unknown argument\n"));
49 exit(EXIT_FAILURE);
50}
51
46long long timespec_diff_us(struct timespec start, struct timespec end) 52long long timespec_diff_us(struct timespec start, struct timespec end)
47{ 53{
48 struct timespec temp; 54 struct timespec temp;
@@ -56,21 +62,6 @@ long long timespec_diff_us(struct timespec start, struct timespec end)
56 return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000); 62 return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000);
57} 63}
58 64
59void monitor_help(void)
60{
61 printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] command\n"));
62 printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] [ -i interval_sec ]\n"));
63 printf(_("cpupower monitor: -l\n"));
64 printf(_("\t command: pass an arbitrary command to measure specific workload\n"));
65 printf(_("\t -i: time intervall to measure for in seconds (default 1)\n"));
66 printf(_("\t -l: list available CPU sleep monitors (for use with -m)\n"));
67 printf(_("\t -m: show specific CPU sleep monitors only (in same order)\n"));
68 printf(_("\t -h: print this help\n"));
69 printf("\n");
70 printf(_("only one of: -l, -m are allowed\nIf none of them is passed,"));
71 printf(_(" all supported monitors are shown\n"));
72}
73
74void print_n_spaces(int n) 65void print_n_spaces(int n)
75{ 66{
76 int x; 67 int x;
@@ -149,6 +140,10 @@ void print_results(int topology_depth, int cpu)
149 unsigned long long result; 140 unsigned long long result;
150 cstate_t s; 141 cstate_t s;
151 142
143 /* Be careful CPUs may got resorted for pkg value do not just use cpu */
144 if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu))
145 return;
146
152 if (topology_depth > 2) 147 if (topology_depth > 2)
153 printf("%4d|", cpu_top.core_info[cpu].pkg); 148 printf("%4d|", cpu_top.core_info[cpu].pkg);
154 if (topology_depth > 1) 149 if (topology_depth > 1)
@@ -190,9 +185,13 @@ void print_results(int topology_depth, int cpu)
190 } 185 }
191 } 186 }
192 } 187 }
193 /* cpu offline */ 188 /*
194 if (cpu_top.core_info[cpu].pkg == -1 || 189 * The monitor could still provide useful data, for example
195 cpu_top.core_info[cpu].core == -1) { 190 * AMD HW counters partly sit in PCI config space.
191 * It's up to the monitor plug-in to check .is_online, this one
192 * is just for additional info.
193 */
194 if (!cpu_top.core_info[cpu].is_online) {
196 printf(_(" *is offline\n")); 195 printf(_(" *is offline\n"));
197 return; 196 return;
198 } else 197 } else
@@ -238,7 +237,6 @@ static void parse_monitor_param(char *param)
238 if (hits == 0) { 237 if (hits == 0) {
239 printf(_("No matching monitor found in %s, " 238 printf(_("No matching monitor found in %s, "
240 "try -l option\n"), param); 239 "try -l option\n"), param);
241 monitor_help();
242 exit(EXIT_FAILURE); 240 exit(EXIT_FAILURE);
243 } 241 }
244 /* Override detected/registerd monitors array with requested one */ 242 /* Override detected/registerd monitors array with requested one */
@@ -335,37 +333,27 @@ static void cmdline(int argc, char *argv[])
335 int opt; 333 int opt;
336 progname = basename(argv[0]); 334 progname = basename(argv[0]);
337 335
338 while ((opt = getopt(argc, argv, "+hli:m:")) != -1) { 336 while ((opt = getopt(argc, argv, "+li:m:")) != -1) {
339 switch (opt) { 337 switch (opt) {
340 case 'h':
341 monitor_help();
342 exit(EXIT_SUCCESS);
343 case 'l': 338 case 'l':
344 if (mode) { 339 if (mode)
345 monitor_help(); 340 print_wrong_arg_exit();
346 exit(EXIT_FAILURE);
347 }
348 mode = list; 341 mode = list;
349 break; 342 break;
350 case 'i': 343 case 'i':
351 /* only allow -i with -m or no option */ 344 /* only allow -i with -m or no option */
352 if (mode && mode != show) { 345 if (mode && mode != show)
353 monitor_help(); 346 print_wrong_arg_exit();
354 exit(EXIT_FAILURE);
355 }
356 interval = atoi(optarg); 347 interval = atoi(optarg);
357 break; 348 break;
358 case 'm': 349 case 'm':
359 if (mode) { 350 if (mode)
360 monitor_help(); 351 print_wrong_arg_exit();
361 exit(EXIT_FAILURE);
362 }
363 mode = show; 352 mode = show;
364 show_monitors_param = optarg; 353 show_monitors_param = optarg;
365 break; 354 break;
366 default: 355 default:
367 monitor_help(); 356 print_wrong_arg_exit();
368 exit(EXIT_FAILURE);
369 } 357 }
370 } 358 }
371 if (!mode) 359 if (!mode)
@@ -385,6 +373,10 @@ int cmd_monitor(int argc, char **argv)
385 return EXIT_FAILURE; 373 return EXIT_FAILURE;
386 } 374 }
387 375
376 /* Default is: monitor all CPUs */
377 if (bitmask_isallclear(cpus_chosen))
378 bitmask_setall(cpus_chosen);
379
388 dprint("System has up to %d CPU cores\n", cpu_count); 380 dprint("System has up to %d CPU cores\n", cpu_count);
389 381
390 for (num = 0; all_monitors[num]; num++) { 382 for (num = 0; all_monitors[num]; num++) {
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
index 63ca87a05e5f..5650ab5a2c20 100644
--- a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
@@ -22,12 +22,15 @@
22 22
23#define MSR_TSC 0x10 23#define MSR_TSC 0x10
24 24
25#define MSR_AMD_HWCR 0xc0010015
26
25enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT }; 27enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT };
26 28
27static int mperf_get_count_percent(unsigned int self_id, double *percent, 29static int mperf_get_count_percent(unsigned int self_id, double *percent,
28 unsigned int cpu); 30 unsigned int cpu);
29static int mperf_get_count_freq(unsigned int id, unsigned long long *count, 31static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
30 unsigned int cpu); 32 unsigned int cpu);
33static struct timespec time_start, time_end;
31 34
32static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { 35static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {
33 { 36 {
@@ -54,19 +57,33 @@ static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {
54 }, 57 },
55}; 58};
56 59
60enum MAX_FREQ_MODE { MAX_FREQ_SYSFS, MAX_FREQ_TSC_REF };
61static int max_freq_mode;
62/*
63 * The max frequency mperf is ticking at (in C0), either retrieved via:
64 * 1) calculated after measurements if we know TSC ticks at mperf/P0 frequency
65 * 2) cpufreq /sys/devices/.../cpu0/cpufreq/cpuinfo_max_freq at init time
66 * 1. Is preferred as it also works without cpufreq subsystem (e.g. on Xen)
67 */
68static unsigned long max_frequency;
69
57static unsigned long long tsc_at_measure_start; 70static unsigned long long tsc_at_measure_start;
58static unsigned long long tsc_at_measure_end; 71static unsigned long long tsc_at_measure_end;
59static unsigned long max_frequency;
60static unsigned long long *mperf_previous_count; 72static unsigned long long *mperf_previous_count;
61static unsigned long long *aperf_previous_count; 73static unsigned long long *aperf_previous_count;
62static unsigned long long *mperf_current_count; 74static unsigned long long *mperf_current_count;
63static unsigned long long *aperf_current_count; 75static unsigned long long *aperf_current_count;
76
64/* valid flag for all CPUs. If a MSR read failed it will be zero */ 77/* valid flag for all CPUs. If a MSR read failed it will be zero */
65static int *is_valid; 78static int *is_valid;
66 79
67static int mperf_get_tsc(unsigned long long *tsc) 80static int mperf_get_tsc(unsigned long long *tsc)
68{ 81{
69 return read_msr(0, MSR_TSC, tsc); 82 int ret;
83 ret = read_msr(0, MSR_TSC, tsc);
84 if (ret)
85 dprint("Reading TSC MSR failed, returning %llu\n", *tsc);
86 return ret;
70} 87}
71 88
72static int mperf_init_stats(unsigned int cpu) 89static int mperf_init_stats(unsigned int cpu)
@@ -97,36 +114,11 @@ static int mperf_measure_stats(unsigned int cpu)
97 return 0; 114 return 0;
98} 115}
99 116
100/*
101 * get_average_perf()
102 *
103 * Returns the average performance (also considers boosted frequencies)
104 *
105 * Input:
106 * aperf_diff: Difference of the aperf register over a time period
107 * mperf_diff: Difference of the mperf register over the same time period
108 * max_freq: Maximum frequency (P0)
109 *
110 * Returns:
111 * Average performance over the time period
112 */
113static unsigned long get_average_perf(unsigned long long aperf_diff,
114 unsigned long long mperf_diff)
115{
116 unsigned int perf_percent = 0;
117 if (((unsigned long)(-1) / 100) < aperf_diff) {
118 int shift_count = 7;
119 aperf_diff >>= shift_count;
120 mperf_diff >>= shift_count;
121 }
122 perf_percent = (aperf_diff * 100) / mperf_diff;
123 return (max_frequency * perf_percent) / 100;
124}
125
126static int mperf_get_count_percent(unsigned int id, double *percent, 117static int mperf_get_count_percent(unsigned int id, double *percent,
127 unsigned int cpu) 118 unsigned int cpu)
128{ 119{
129 unsigned long long aperf_diff, mperf_diff, tsc_diff; 120 unsigned long long aperf_diff, mperf_diff, tsc_diff;
121 unsigned long long timediff;
130 122
131 if (!is_valid[cpu]) 123 if (!is_valid[cpu])
132 return -1; 124 return -1;
@@ -136,11 +128,19 @@ static int mperf_get_count_percent(unsigned int id, double *percent,
136 128
137 mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; 129 mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
138 aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; 130 aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
139 tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
140 131
141 *percent = 100.0 * mperf_diff / tsc_diff; 132 if (max_freq_mode == MAX_FREQ_TSC_REF) {
142 dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n", 133 tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
143 mperf_cstates[id].name, mperf_diff, tsc_diff); 134 *percent = 100.0 * mperf_diff / tsc_diff;
135 dprint("%s: TSC Ref - mperf_diff: %llu, tsc_diff: %llu\n",
136 mperf_cstates[id].name, mperf_diff, tsc_diff);
137 } else if (max_freq_mode == MAX_FREQ_SYSFS) {
138 timediff = timespec_diff_us(time_start, time_end);
139 *percent = 100.0 * mperf_diff / timediff;
140 dprint("%s: MAXFREQ - mperf_diff: %llu, time_diff: %llu\n",
141 mperf_cstates[id].name, mperf_diff, timediff);
142 } else
143 return -1;
144 144
145 if (id == Cx) 145 if (id == Cx)
146 *percent = 100.0 - *percent; 146 *percent = 100.0 - *percent;
@@ -154,7 +154,7 @@ static int mperf_get_count_percent(unsigned int id, double *percent,
154static int mperf_get_count_freq(unsigned int id, unsigned long long *count, 154static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
155 unsigned int cpu) 155 unsigned int cpu)
156{ 156{
157 unsigned long long aperf_diff, mperf_diff; 157 unsigned long long aperf_diff, mperf_diff, time_diff, tsc_diff;
158 158
159 if (id != AVG_FREQ) 159 if (id != AVG_FREQ)
160 return 1; 160 return 1;
@@ -165,11 +165,21 @@ static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
165 mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; 165 mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
166 aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; 166 aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
167 167
168 /* Return MHz for now, might want to return KHz if column width is more 168 if (max_freq_mode == MAX_FREQ_TSC_REF) {
169 generic */ 169 /* Calculate max_freq from TSC count */
170 *count = get_average_perf(aperf_diff, mperf_diff) / 1000; 170 tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
171 dprint("%s: %llu\n", mperf_cstates[id].name, *count); 171 time_diff = timespec_diff_us(time_start, time_end);
172 max_frequency = tsc_diff / time_diff;
173 }
172 174
175 *count = max_frequency * ((double)aperf_diff / mperf_diff);
176 dprint("%s: Average freq based on %s maximum frequency:\n",
177 mperf_cstates[id].name,
178 (max_freq_mode == MAX_FREQ_TSC_REF) ? "TSC calculated" : "sysfs read");
179 dprint("%max_frequency: %lu", max_frequency);
180 dprint("aperf_diff: %llu\n", aperf_diff);
181 dprint("mperf_diff: %llu\n", mperf_diff);
182 dprint("avg freq: %llu\n", *count);
173 return 0; 183 return 0;
174} 184}
175 185
@@ -178,6 +188,7 @@ static int mperf_start(void)
178 int cpu; 188 int cpu;
179 unsigned long long dbg; 189 unsigned long long dbg;
180 190
191 clock_gettime(CLOCK_REALTIME, &time_start);
181 mperf_get_tsc(&tsc_at_measure_start); 192 mperf_get_tsc(&tsc_at_measure_start);
182 193
183 for (cpu = 0; cpu < cpu_count; cpu++) 194 for (cpu = 0; cpu < cpu_count; cpu++)
@@ -193,32 +204,104 @@ static int mperf_stop(void)
193 unsigned long long dbg; 204 unsigned long long dbg;
194 int cpu; 205 int cpu;
195 206
196 mperf_get_tsc(&tsc_at_measure_end);
197
198 for (cpu = 0; cpu < cpu_count; cpu++) 207 for (cpu = 0; cpu < cpu_count; cpu++)
199 mperf_measure_stats(cpu); 208 mperf_measure_stats(cpu);
200 209
210 mperf_get_tsc(&tsc_at_measure_end);
211 clock_gettime(CLOCK_REALTIME, &time_end);
212
201 mperf_get_tsc(&dbg); 213 mperf_get_tsc(&dbg);
202 dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); 214 dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);
203 215
204 return 0; 216 return 0;
205} 217}
206 218
207struct cpuidle_monitor mperf_monitor; 219/*
208 220 * Mperf register is defined to tick at P0 (maximum) frequency
209struct cpuidle_monitor *mperf_register(void) 221 *
222 * Instead of reading out P0 which can be tricky to read out from HW,
223 * we use TSC counter if it reliably ticks at P0/mperf frequency.
224 *
225 * Still try to fall back to:
226 * /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
227 * on older Intel HW without invariant TSC feature.
228 * Or on AMD machines where TSC does not tick at P0 (do not exist yet, but
229 * it's still double checked (MSR_AMD_HWCR)).
230 *
231 * On these machines the user would still get useful mperf
232 * stats when acpi-cpufreq driver is loaded.
233 */
234static int init_maxfreq_mode(void)
210{ 235{
236 int ret;
237 unsigned long long hwcr;
211 unsigned long min; 238 unsigned long min;
212 239
213 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) 240 if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC)
214 return NULL; 241 goto use_sysfs;
215 242
216 /* Assume min/max all the same on all cores */ 243 if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) {
244 /* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf
245 * freq.
246 * A test whether hwcr is accessable/available would be:
247 * (cpupower_cpu_info.family > 0x10 ||
248 * cpupower_cpu_info.family == 0x10 &&
249 * cpupower_cpu_info.model >= 0x2))
250 * This should be the case for all aperf/mperf
251 * capable AMD machines and is therefore safe to test here.
252 * Compare with Linus kernel git commit: acf01734b1747b1ec4
253 */
254 ret = read_msr(0, MSR_AMD_HWCR, &hwcr);
255 /*
256 * If the MSR read failed, assume a Xen system that did
257 * not explicitly provide access to it and assume TSC works
258 */
259 if (ret != 0) {
260 dprint("TSC read 0x%x failed - assume TSC working\n",
261 MSR_AMD_HWCR);
262 return 0;
263 } else if (1 & (hwcr >> 24)) {
264 max_freq_mode = MAX_FREQ_TSC_REF;
265 return 0;
266 } else { /* Use sysfs max frequency if available */ }
267 } else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) {
268 /*
269 * On Intel we assume mperf (in C0) is ticking at same
270 * rate than TSC
271 */
272 max_freq_mode = MAX_FREQ_TSC_REF;
273 return 0;
274 }
275use_sysfs:
217 if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) { 276 if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) {
218 dprint("Cannot retrieve max freq from cpufreq kernel " 277 dprint("Cannot retrieve max freq from cpufreq kernel "
219 "subsystem\n"); 278 "subsystem\n");
220 return NULL; 279 return -1;
221 } 280 }
281 max_freq_mode = MAX_FREQ_SYSFS;
282 return 0;
283}
284
285/*
286 * This monitor provides:
287 *
288 * 1) Average frequency a CPU resided in
289 * This always works if the CPU has aperf/mperf capabilities
290 *
291 * 2) C0 and Cx (any sleep state) time a CPU resided in
292 * Works if mperf timer stops ticking in sleep states which
293 * seem to be the case on all current HW.
294 * Both is directly retrieved from HW registers and is independent
295 * from kernel statistics.
296 */
297struct cpuidle_monitor mperf_monitor;
298struct cpuidle_monitor *mperf_register(void)
299{
300 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
301 return NULL;
302
303 if (init_maxfreq_mode())
304 return NULL;
222 305
223 /* Free this at program termination */ 306 /* Free this at program termination */
224 is_valid = calloc(cpu_count, sizeof(int)); 307 is_valid = calloc(cpu_count, sizeof(int));
diff --git a/tools/slub/slabinfo.c b/tools/slub/slabinfo.c
index 868cc93f7ac2..164cbcf61106 100644
--- a/tools/slub/slabinfo.c
+++ b/tools/slub/slabinfo.c
@@ -42,6 +42,7 @@ struct slabinfo {
42 unsigned long deactivate_remote_frees, order_fallback; 42 unsigned long deactivate_remote_frees, order_fallback;
43 unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail; 43 unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail;
44 unsigned long alloc_node_mismatch, deactivate_bypass; 44 unsigned long alloc_node_mismatch, deactivate_bypass;
45 unsigned long cpu_partial_alloc, cpu_partial_free;
45 int numa[MAX_NODES]; 46 int numa[MAX_NODES];
46 int numa_partial[MAX_NODES]; 47 int numa_partial[MAX_NODES];
47} slabinfo[MAX_SLABS]; 48} slabinfo[MAX_SLABS];
@@ -455,6 +456,11 @@ static void slab_stats(struct slabinfo *s)
455 s->alloc_from_partial * 100 / total_alloc, 456 s->alloc_from_partial * 100 / total_alloc,
456 s->free_remove_partial * 100 / total_free); 457 s->free_remove_partial * 100 / total_free);
457 458
459 printf("Cpu partial list %8lu %8lu %3lu %3lu\n",
460 s->cpu_partial_alloc, s->cpu_partial_free,
461 s->cpu_partial_alloc * 100 / total_alloc,
462 s->cpu_partial_free * 100 / total_free);
463
458 printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n", 464 printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
459 s->deactivate_remote_frees, s->free_frozen, 465 s->deactivate_remote_frees, s->free_frozen,
460 s->deactivate_remote_frees * 100 / total_alloc, 466 s->deactivate_remote_frees * 100 / total_alloc,
@@ -1145,7 +1151,7 @@ static void read_slab_dir(void)
1145 switch (de->d_type) { 1151 switch (de->d_type) {
1146 case DT_LNK: 1152 case DT_LNK:
1147 alias->name = strdup(de->d_name); 1153 alias->name = strdup(de->d_name);
1148 count = readlink(de->d_name, buffer, sizeof(buffer)); 1154 count = readlink(de->d_name, buffer, sizeof(buffer)-1);
1149 1155
1150 if (count < 0) 1156 if (count < 0)
1151 fatal("Cannot read symlink %s\n", de->d_name); 1157 fatal("Cannot read symlink %s\n", de->d_name);
@@ -1209,6 +1215,8 @@ static void read_slab_dir(void)
1209 slab->order_fallback = get_obj("order_fallback"); 1215 slab->order_fallback = get_obj("order_fallback");
1210 slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail"); 1216 slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail");
1211 slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail"); 1217 slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail");
1218 slab->cpu_partial_alloc = get_obj("cpu_partial_alloc");
1219 slab->cpu_partial_free = get_obj("cpu_partial_free");
1212 slab->alloc_node_mismatch = get_obj("alloc_node_mismatch"); 1220 slab->alloc_node_mismatch = get_obj("alloc_node_mismatch");
1213 slab->deactivate_bypass = get_obj("deactivate_bypass"); 1221 slab->deactivate_bypass = get_obj("deactivate_bypass");
1214 chdir(".."); 1222 chdir("..");