aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2012-01-09 02:38:23 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-01-09 02:38:23 -0500
commitda733563be5a9da26fe81d9f007262d00b846e22 (patch)
treedb28291df94a2043af2123911984c5c173da4e6f /tools
parent6ccbcf2cb41131f8d56ef0723bf3f7c1f8486076 (diff)
parentdab78d7924598ea4031663dd10db814e2e324928 (diff)
Merge branch 'next' into for-linus
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/Makefile14
-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-record.c50
-rw-r--r--tools/perf/builtin-report.c28
-rw-r--r--tools/perf/builtin-script.c6
-rw-r--r--tools/perf/builtin-stat.c210
-rw-r--r--tools/perf/builtin-test.c8
-rw-r--r--tools/perf/builtin-top.c532
-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.c20
-rw-r--r--tools/perf/util/annotate.h9
-rw-r--r--tools/perf/util/color.c2
-rw-r--r--tools/perf/util/config.c4
-rw-r--r--tools/perf/util/debug.c7
-rw-r--r--tools/perf/util/debug.h17
-rw-r--r--tools/perf/util/event.c5
-rw-r--r--tools/perf/util/event.h2
-rw-r--r--tools/perf/util/evlist.c49
-rw-r--r--tools/perf/util/evlist.h7
-rw-r--r--tools/perf/util/evsel.c101
-rw-r--r--tools/perf/util/evsel.h10
-rw-r--r--tools/perf/util/header.c1233
-rw-r--r--tools/perf/util/header.h29
-rw-r--r--tools/perf/util/hist.c446
-rw-r--r--tools/perf/util/hist.h62
-rw-r--r--tools/perf/util/map.c102
-rw-r--r--tools/perf/util/map.h42
-rw-r--r--tools/perf/util/probe-event.c4
-rw-r--r--tools/perf/util/probe-finder.c2
-rw-r--r--tools/perf/util/python.c33
-rw-r--r--tools/perf/util/session.c65
-rw-r--r--tools/perf/util/session.h5
-rw-r--r--tools/perf/util/sort.c14
-rw-r--r--tools/perf/util/sort.h2
-rw-r--r--tools/perf/util/symbol.c156
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/top.c141
-rw-r--r--tools/perf/util/top.h38
-rw-r--r--tools/perf/util/trace-event-info.c114
-rw-r--r--tools/perf/util/trace-event.h13
-rw-r--r--tools/perf/util/ui/browser.c429
-rw-r--r--tools/perf/util/ui/browser.h21
-rw-r--r--tools/perf/util/ui/browsers/annotate.c215
-rw-r--r--tools/perf/util/ui/browsers/hists.c351
-rw-r--r--tools/perf/util/ui/browsers/map.c6
-rw-r--r--tools/perf/util/ui/browsers/top.c212
-rw-r--r--tools/perf/util/ui/helpline.c16
-rw-r--r--tools/perf/util/ui/helpline.h5
-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/progress.c65
-rw-r--r--tools/perf/util/ui/progress.h7
-rw-r--r--tools/perf/util/ui/setup.c121
-rw-r--r--tools/perf/util/ui/ui.h3
-rw-r--r--tools/perf/util/ui/util.c182
-rw-r--r--tools/perf/util/ui/util.h8
-rw-r--r--tools/power/x86/turbostat/turbostat.c28
-rw-r--r--tools/slub/slabinfo.c10
-rwxr-xr-xtools/testing/ktest/ktest.pl531
-rw-r--r--tools/testing/ktest/sample.conf146
81 files changed, 5302 insertions, 1599 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 3b8f7b80376b..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)
@@ -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
@@ -722,9 +729,6 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
722$(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
723 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 730 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
724 731
725$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
726 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
727
728$(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
729 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 733 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
730 734
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-record.c b/tools/perf/builtin-record.c
index 6b0519f885e4..6ab58cc99d53 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -73,6 +73,7 @@ static off_t post_processing_offset;
73 73
74static struct perf_session *session; 74static struct perf_session *session;
75static const char *cpu_list; 75static const char *cpu_list;
76static const char *progname;
76 77
77static void advance_output(size_t size) 78static void advance_output(size_t size)
78{ 79{
@@ -137,17 +138,29 @@ static void mmap_read(struct perf_mmap *md)
137 138
138static volatile int done = 0; 139static volatile int done = 0;
139static volatile int signr = -1; 140static volatile int signr = -1;
141static volatile int child_finished = 0;
140 142
141static void sig_handler(int sig) 143static void sig_handler(int sig)
142{ 144{
145 if (sig == SIGCHLD)
146 child_finished = 1;
147
143 done = 1; 148 done = 1;
144 signr = sig; 149 signr = sig;
145} 150}
146 151
147static void sig_atexit(void) 152static void sig_atexit(void)
148{ 153{
149 if (child_pid > 0) 154 int status;
150 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 }
151 164
152 if (signr == -1 || signr == SIGUSR1) 165 if (signr == -1 || signr == SIGUSR1)
153 return; 166 return;
@@ -161,6 +174,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
161 struct perf_event_attr *attr = &evsel->attr; 174 struct perf_event_attr *attr = &evsel->attr;
162 int track = !evsel->idx; /* only the first counter needs these */ 175 int track = !evsel->idx; /* only the first counter needs these */
163 176
177 attr->disabled = 1;
164 attr->inherit = !no_inherit; 178 attr->inherit = !no_inherit;
165 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 179 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
166 PERF_FORMAT_TOTAL_TIME_RUNNING | 180 PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -248,13 +262,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
248 262
249static void open_counters(struct perf_evlist *evlist) 263static void open_counters(struct perf_evlist *evlist)
250{ 264{
251 struct perf_evsel *pos; 265 struct perf_evsel *pos, *first;
252 266
253 if (evlist->cpus->map[0] < 0) 267 if (evlist->cpus->map[0] < 0)
254 no_inherit = true; 268 no_inherit = true;
255 269
270 first = list_entry(evlist->entries.next, struct perf_evsel, node);
271
256 list_for_each_entry(pos, &evlist->entries, node) { 272 list_for_each_entry(pos, &evlist->entries, node) {
257 struct perf_event_attr *attr = &pos->attr; 273 struct perf_event_attr *attr = &pos->attr;
274 struct xyarray *group_fd = NULL;
258 /* 275 /*
259 * Check if parse_single_tracepoint_event has already asked for 276 * Check if parse_single_tracepoint_event has already asked for
260 * PERF_SAMPLE_TIME. 277 * PERF_SAMPLE_TIME.
@@ -269,15 +286,19 @@ static void open_counters(struct perf_evlist *evlist)
269 */ 286 */
270 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; 287 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
271 288
289 if (group && pos != first)
290 group_fd = first->fd;
291
272 config_attr(pos, evlist); 292 config_attr(pos, evlist);
273retry_sample_id: 293retry_sample_id:
274 attr->sample_id_all = sample_id_all_avail ? 1 : 0; 294 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
275try_again: 295try_again:
276 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) { 296 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
297 group_fd) < 0) {
277 int err = errno; 298 int err = errno;
278 299
279 if (err == EPERM || err == EACCES) { 300 if (err == EPERM || err == EACCES) {
280 ui__warning_paranoid(); 301 ui__error_paranoid();
281 exit(EXIT_FAILURE); 302 exit(EXIT_FAILURE);
282 } else if (err == ENODEV && cpu_list) { 303 } else if (err == ENODEV && cpu_list) {
283 die("No such device - did you specify" 304 die("No such device - did you specify"
@@ -445,6 +466,8 @@ static int __cmd_record(int argc, const char **argv)
445 char buf; 466 char buf;
446 struct machine *machine; 467 struct machine *machine;
447 468
469 progname = argv[0];
470
448 page_size = sysconf(_SC_PAGE_SIZE); 471 page_size = sysconf(_SC_PAGE_SIZE);
449 472
450 atexit(sig_atexit); 473 atexit(sig_atexit);
@@ -513,6 +536,19 @@ static int __cmd_record(int argc, const char **argv)
513 if (have_tracepoints(&evsel_list->entries)) 536 if (have_tracepoints(&evsel_list->entries))
514 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 537 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
515 538
539 perf_header__set_feat(&session->header, HEADER_HOSTNAME);
540 perf_header__set_feat(&session->header, HEADER_OSRELEASE);
541 perf_header__set_feat(&session->header, HEADER_ARCH);
542 perf_header__set_feat(&session->header, HEADER_CPUDESC);
543 perf_header__set_feat(&session->header, HEADER_NRCPUS);
544 perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
545 perf_header__set_feat(&session->header, HEADER_CMDLINE);
546 perf_header__set_feat(&session->header, HEADER_VERSION);
547 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
548 perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
549 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
550 perf_header__set_feat(&session->header, HEADER_CPUID);
551
516 /* 512 kiB: default amount of unprivileged mlocked memory */ 552 /* 512 kiB: default amount of unprivileged mlocked memory */
517 if (mmap_pages == UINT_MAX) 553 if (mmap_pages == UINT_MAX)
518 mmap_pages = (512 * 1024) / page_size; 554 mmap_pages = (512 * 1024) / page_size;
@@ -671,6 +707,8 @@ static int __cmd_record(int argc, const char **argv)
671 } 707 }
672 } 708 }
673 709
710 perf_evlist__enable(evsel_list);
711
674 /* 712 /*
675 * Let the child rip 713 * Let the child rip
676 */ 714 */
@@ -782,6 +820,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
782 int err = -ENOMEM; 820 int err = -ENOMEM;
783 struct perf_evsel *pos; 821 struct perf_evsel *pos;
784 822
823 perf_header__set_cmdline(argc, argv);
824
785 evsel_list = perf_evlist__new(NULL, NULL); 825 evsel_list = perf_evlist__new(NULL, NULL);
786 if (evsel_list == NULL) 826 if (evsel_list == NULL)
787 return -ENOMEM; 827 return -ENOMEM;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index d7ff277bdb78..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;
@@ -229,13 +230,10 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
229 230
230 list_for_each_entry(pos, &evlist->entries, node) { 231 list_for_each_entry(pos, &evlist->entries, node) {
231 struct hists *hists = &pos->hists; 232 struct hists *hists = &pos->hists;
232 const char *evname = NULL; 233 const char *evname = event_name(pos);
233
234 if (rb_first(&hists->entries) != rb_last(&hists->entries))
235 evname = event_name(pos);
236 234
237 hists__fprintf_nr_sample_events(hists, evname, stdout); 235 hists__fprintf_nr_sample_events(hists, evname, stdout);
238 hists__fprintf(hists, NULL, false, stdout); 236 hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
239 fprintf(stdout, "\n\n"); 237 fprintf(stdout, "\n\n");
240 } 238 }
241 239
@@ -276,6 +274,9 @@ static int __cmd_report(void)
276 goto out_delete; 274 goto out_delete;
277 } 275 }
278 276
277 if (use_browser <= 0)
278 perf_session__fprintf_info(session, stdout, show_full_info);
279
279 if (show_threads) 280 if (show_threads)
280 perf_read_values_init(&show_threads_values); 281 perf_read_values_init(&show_threads_values);
281 282
@@ -330,9 +331,10 @@ static int __cmd_report(void)
330 goto out_delete; 331 goto out_delete;
331 } 332 }
332 333
333 if (use_browser > 0) 334 if (use_browser > 0) {
334 perf_evlist__tui_browse_hists(session->evlist, help); 335 perf_evlist__tui_browse_hists(session->evlist, help,
335 else 336 NULL, NULL, 0);
337 } else
336 perf_evlist__tty_browse_hists(session->evlist, help); 338 perf_evlist__tty_browse_hists(session->evlist, help);
337 339
338out_delete: 340out_delete:
@@ -487,6 +489,16 @@ static const struct option options[] = {
487 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 489 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
488 "Look for files with symbols relative to this directory"), 490 "Look for files with symbols relative to this directory"),
489 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"),
490 OPT_END() 502 OPT_END()
491}; 503};
492 504
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 5deb17d9e795..7d98676808d8 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -194,6 +194,9 @@ static 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; 196static bool group = false;
197static const char *output_name = NULL;
198static FILE *output = NULL;
199static int output_fd;
197 200
198static volatile int done = 0; 201static volatile int done = 0;
199 202
@@ -251,8 +254,13 @@ static double avg_stats(struct stats *stats)
251 */ 254 */
252static double stddev_stats(struct stats *stats) 255static double stddev_stats(struct stats *stats)
253{ 256{
254 double variance = stats->M2 / (stats->n - 1); 257 double variance, variance_mean;
255 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;
256 264
257 return sqrt(variance_mean); 265 return sqrt(variance_mean);
258} 266}
@@ -270,9 +278,14 @@ struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
270struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 278struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
271struct stats walltime_nsecs_stats; 279struct stats walltime_nsecs_stats;
272 280
273static int create_perf_stat_counter(struct perf_evsel *evsel) 281static int create_perf_stat_counter(struct perf_evsel *evsel,
282 struct perf_evsel *first)
274{ 283{
275 struct perf_event_attr *attr = &evsel->attr; 284 struct perf_event_attr *attr = &evsel->attr;
285 struct xyarray *group_fd = NULL;
286
287 if (group && evsel != first)
288 group_fd = first->fd;
276 289
277 if (scale) 290 if (scale)
278 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 291 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -281,14 +294,15 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
281 attr->inherit = !no_inherit; 294 attr->inherit = !no_inherit;
282 295
283 if (system_wide) 296 if (system_wide)
284 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group); 297 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
285 298 group, group_fd);
286 if (target_pid == -1 && target_tid == -1) { 299 if (target_pid == -1 && target_tid == -1) {
287 attr->disabled = 1; 300 attr->disabled = 1;
288 attr->enable_on_exec = 1; 301 attr->enable_on_exec = 1;
289 } 302 }
290 303
291 return perf_evsel__open_per_thread(evsel, evsel_list->threads, group); 304 return perf_evsel__open_per_thread(evsel, evsel_list->threads,
305 group, group_fd);
292} 306}
293 307
294/* 308/*
@@ -352,7 +366,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
352 update_stats(&ps->res_stats[i], count[i]); 366 update_stats(&ps->res_stats[i], count[i]);
353 367
354 if (verbose) { 368 if (verbose) {
355 fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", 369 fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
356 event_name(counter), count[0], count[1], count[2]); 370 event_name(counter), count[0], count[1], count[2]);
357 } 371 }
358 372
@@ -388,7 +402,7 @@ static int read_counter(struct perf_evsel *counter)
388static int run_perf_stat(int argc __used, const char **argv) 402static int run_perf_stat(int argc __used, const char **argv)
389{ 403{
390 unsigned long long t0, t1; 404 unsigned long long t0, t1;
391 struct perf_evsel *counter; 405 struct perf_evsel *counter, *first;
392 int status = 0; 406 int status = 0;
393 int child_ready_pipe[2], go_pipe[2]; 407 int child_ready_pipe[2], go_pipe[2];
394 const bool forks = (argc > 0); 408 const bool forks = (argc > 0);
@@ -445,8 +459,10 @@ static int run_perf_stat(int argc __used, const char **argv)
445 close(child_ready_pipe[0]); 459 close(child_ready_pipe[0]);
446 } 460 }
447 461
462 first = list_entry(evsel_list->entries.next, struct perf_evsel, node);
463
448 list_for_each_entry(counter, &evsel_list->entries, node) { 464 list_for_each_entry(counter, &evsel_list->entries, node) {
449 if (create_perf_stat_counter(counter) < 0) { 465 if (create_perf_stat_counter(counter, first) < 0) {
450 if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) { 466 if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) {
451 if (verbose) 467 if (verbose)
452 ui__warning("%s event is not supported by the kernel.\n", 468 ui__warning("%s event is not supported by the kernel.\n",
@@ -487,6 +503,8 @@ static int run_perf_stat(int argc __used, const char **argv)
487 if (forks) { 503 if (forks) {
488 close(go_pipe[1]); 504 close(go_pipe[1]);
489 wait(&status); 505 wait(&status);
506 if (WIFSIGNALED(status))
507 psignal(WTERMSIG(status), argv[0]);
490 } else { 508 } else {
491 while(!done) sleep(1); 509 while(!done) sleep(1);
492 } 510 }
@@ -519,9 +537,9 @@ static void print_noise_pct(double total, double avg)
519 pct = 100.0*total/avg; 537 pct = 100.0*total/avg;
520 538
521 if (csv_output) 539 if (csv_output)
522 fprintf(stderr, "%s%.2f%%", csv_sep, pct); 540 fprintf(output, "%s%.2f%%", csv_sep, pct);
523 else 541 else if (pct)
524 fprintf(stderr, " ( +-%6.2f%% )", pct); 542 fprintf(output, " ( +-%6.2f%% )", pct);
525} 543}
526 544
527static void print_noise(struct perf_evsel *evsel, double avg) 545static void print_noise(struct perf_evsel *evsel, double avg)
@@ -546,16 +564,17 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
546 csv_output ? 0 : -4, 564 csv_output ? 0 : -4,
547 evsel_list->cpus->map[cpu], csv_sep); 565 evsel_list->cpus->map[cpu], csv_sep);
548 566
549 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel)); 567 fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel));
550 568
551 if (evsel->cgrp) 569 if (evsel->cgrp)
552 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); 570 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
553 571
554 if (csv_output) 572 if (csv_output)
555 return; 573 return;
556 574
557 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 575 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
558 fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats)); 576 fprintf(output, " # %8.3f CPUs utilized ",
577 avg / avg_stats(&walltime_nsecs_stats));
559} 578}
560 579
561static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) 580static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -576,9 +595,9 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us
576 else if (ratio > 10.0) 595 else if (ratio > 10.0)
577 color = PERF_COLOR_YELLOW; 596 color = PERF_COLOR_YELLOW;
578 597
579 fprintf(stderr, " # "); 598 fprintf(output, " # ");
580 color_fprintf(stderr, color, "%6.2f%%", ratio); 599 color_fprintf(output, color, "%6.2f%%", ratio);
581 fprintf(stderr, " frontend cycles idle "); 600 fprintf(output, " frontend cycles idle ");
582} 601}
583 602
584static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg) 603static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -599,9 +618,9 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use
599 else if (ratio > 20.0) 618 else if (ratio > 20.0)
600 color = PERF_COLOR_YELLOW; 619 color = PERF_COLOR_YELLOW;
601 620
602 fprintf(stderr, " # "); 621 fprintf(output, " # ");
603 color_fprintf(stderr, color, "%6.2f%%", ratio); 622 color_fprintf(output, color, "%6.2f%%", ratio);
604 fprintf(stderr, " backend cycles idle "); 623 fprintf(output, " backend cycles idle ");
605} 624}
606 625
607static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) 626static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -622,9 +641,9 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double
622 else if (ratio > 5.0) 641 else if (ratio > 5.0)
623 color = PERF_COLOR_YELLOW; 642 color = PERF_COLOR_YELLOW;
624 643
625 fprintf(stderr, " # "); 644 fprintf(output, " # ");
626 color_fprintf(stderr, color, "%6.2f%%", ratio); 645 color_fprintf(output, color, "%6.2f%%", ratio);
627 fprintf(stderr, " of all branches "); 646 fprintf(output, " of all branches ");
628} 647}
629 648
630static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 649static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -645,9 +664,9 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou
645 else if (ratio > 5.0) 664 else if (ratio > 5.0)
646 color = PERF_COLOR_YELLOW; 665 color = PERF_COLOR_YELLOW;
647 666
648 fprintf(stderr, " # "); 667 fprintf(output, " # ");
649 color_fprintf(stderr, color, "%6.2f%%", ratio); 668 color_fprintf(output, color, "%6.2f%%", ratio);
650 fprintf(stderr, " of all L1-dcache hits "); 669 fprintf(output, " of all L1-dcache hits ");
651} 670}
652 671
653static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 672static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -668,9 +687,9 @@ static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, dou
668 else if (ratio > 5.0) 687 else if (ratio > 5.0)
669 color = PERF_COLOR_YELLOW; 688 color = PERF_COLOR_YELLOW;
670 689
671 fprintf(stderr, " # "); 690 fprintf(output, " # ");
672 color_fprintf(stderr, color, "%6.2f%%", ratio); 691 color_fprintf(output, color, "%6.2f%%", ratio);
673 fprintf(stderr, " of all L1-icache hits "); 692 fprintf(output, " of all L1-icache hits ");
674} 693}
675 694
676static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 695static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -691,9 +710,9 @@ static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
691 else if (ratio > 5.0) 710 else if (ratio > 5.0)
692 color = PERF_COLOR_YELLOW; 711 color = PERF_COLOR_YELLOW;
693 712
694 fprintf(stderr, " # "); 713 fprintf(output, " # ");
695 color_fprintf(stderr, color, "%6.2f%%", ratio); 714 color_fprintf(output, color, "%6.2f%%", ratio);
696 fprintf(stderr, " of all dTLB cache hits "); 715 fprintf(output, " of all dTLB cache hits ");
697} 716}
698 717
699static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 718static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -714,9 +733,9 @@ static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
714 else if (ratio > 5.0) 733 else if (ratio > 5.0)
715 color = PERF_COLOR_YELLOW; 734 color = PERF_COLOR_YELLOW;
716 735
717 fprintf(stderr, " # "); 736 fprintf(output, " # ");
718 color_fprintf(stderr, color, "%6.2f%%", ratio); 737 color_fprintf(output, color, "%6.2f%%", ratio);
719 fprintf(stderr, " of all iTLB cache hits "); 738 fprintf(output, " of all iTLB cache hits ");
720} 739}
721 740
722static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 741static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -737,9 +756,9 @@ static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, doub
737 else if (ratio > 5.0) 756 else if (ratio > 5.0)
738 color = PERF_COLOR_YELLOW; 757 color = PERF_COLOR_YELLOW;
739 758
740 fprintf(stderr, " # "); 759 fprintf(output, " # ");
741 color_fprintf(stderr, color, "%6.2f%%", ratio); 760 color_fprintf(output, color, "%6.2f%%", ratio);
742 fprintf(stderr, " of all LL-cache hits "); 761 fprintf(output, " of all LL-cache hits ");
743} 762}
744 763
745static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) 764static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
@@ -762,10 +781,10 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
762 else 781 else
763 cpu = 0; 782 cpu = 0;
764 783
765 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel)); 784 fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel));
766 785
767 if (evsel->cgrp) 786 if (evsel->cgrp)
768 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); 787 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
769 788
770 if (csv_output) 789 if (csv_output)
771 return; 790 return;
@@ -776,14 +795,14 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
776 if (total) 795 if (total)
777 ratio = avg / total; 796 ratio = avg / total;
778 797
779 fprintf(stderr, " # %5.2f insns per cycle ", ratio); 798 fprintf(output, " # %5.2f insns per cycle ", ratio);
780 799
781 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); 800 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
782 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); 801 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
783 802
784 if (total && avg) { 803 if (total && avg) {
785 ratio = total / avg; 804 ratio = total / avg;
786 fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio); 805 fprintf(output, "\n # %5.2f stalled cycles per insn", ratio);
787 } 806 }
788 807
789 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 808 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
@@ -831,7 +850,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
831 if (total) 850 if (total)
832 ratio = avg * 100 / total; 851 ratio = avg * 100 / total;
833 852
834 fprintf(stderr, " # %8.3f %% of all cache refs ", ratio); 853 fprintf(output, " # %8.3f %% of all cache refs ", ratio);
835 854
836 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { 855 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
837 print_stalled_cycles_frontend(cpu, evsel, avg); 856 print_stalled_cycles_frontend(cpu, evsel, avg);
@@ -843,16 +862,16 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
843 if (total) 862 if (total)
844 ratio = 1.0 * avg / total; 863 ratio = 1.0 * avg / total;
845 864
846 fprintf(stderr, " # %8.3f GHz ", ratio); 865 fprintf(output, " # %8.3f GHz ", ratio);
847 } else if (runtime_nsecs_stats[cpu].n != 0) { 866 } else if (runtime_nsecs_stats[cpu].n != 0) {
848 total = avg_stats(&runtime_nsecs_stats[cpu]); 867 total = avg_stats(&runtime_nsecs_stats[cpu]);
849 868
850 if (total) 869 if (total)
851 ratio = 1000.0 * avg / total; 870 ratio = 1000.0 * avg / total;
852 871
853 fprintf(stderr, " # %8.3f M/sec ", ratio); 872 fprintf(output, " # %8.3f M/sec ", ratio);
854 } else { 873 } else {
855 fprintf(stderr, " "); 874 fprintf(output, " ");
856 } 875 }
857} 876}
858 877
@@ -867,7 +886,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
867 int scaled = counter->counts->scaled; 886 int scaled = counter->counts->scaled;
868 887
869 if (scaled == -1) { 888 if (scaled == -1) {
870 fprintf(stderr, "%*s%s%*s", 889 fprintf(output, "%*s%s%*s",
871 csv_output ? 0 : 18, 890 csv_output ? 0 : 18,
872 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 891 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
873 csv_sep, 892 csv_sep,
@@ -875,9 +894,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
875 event_name(counter)); 894 event_name(counter));
876 895
877 if (counter->cgrp) 896 if (counter->cgrp)
878 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); 897 fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
879 898
880 fputc('\n', stderr); 899 fputc('\n', output);
881 return; 900 return;
882 } 901 }
883 902
@@ -889,7 +908,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
889 print_noise(counter, avg); 908 print_noise(counter, avg);
890 909
891 if (csv_output) { 910 if (csv_output) {
892 fputc('\n', stderr); 911 fputc('\n', output);
893 return; 912 return;
894 } 913 }
895 914
@@ -899,9 +918,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
899 avg_enabled = avg_stats(&ps->res_stats[1]); 918 avg_enabled = avg_stats(&ps->res_stats[1]);
900 avg_running = avg_stats(&ps->res_stats[2]); 919 avg_running = avg_stats(&ps->res_stats[2]);
901 920
902 fprintf(stderr, " [%5.2f%%]", 100 * avg_running / avg_enabled); 921 fprintf(output, " [%5.2f%%]", 100 * avg_running / avg_enabled);
903 } 922 }
904 fprintf(stderr, "\n"); 923 fprintf(output, "\n");
905} 924}
906 925
907/* 926/*
@@ -918,7 +937,7 @@ static void print_counter(struct perf_evsel *counter)
918 ena = counter->counts->cpu[cpu].ena; 937 ena = counter->counts->cpu[cpu].ena;
919 run = counter->counts->cpu[cpu].run; 938 run = counter->counts->cpu[cpu].run;
920 if (run == 0 || ena == 0) { 939 if (run == 0 || ena == 0) {
921 fprintf(stderr, "CPU%*d%s%*s%s%*s", 940 fprintf(output, "CPU%*d%s%*s%s%*s",
922 csv_output ? 0 : -4, 941 csv_output ? 0 : -4,
923 evsel_list->cpus->map[cpu], csv_sep, 942 evsel_list->cpus->map[cpu], csv_sep,
924 csv_output ? 0 : 18, 943 csv_output ? 0 : 18,
@@ -928,9 +947,10 @@ static void print_counter(struct perf_evsel *counter)
928 event_name(counter)); 947 event_name(counter));
929 948
930 if (counter->cgrp) 949 if (counter->cgrp)
931 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); 950 fprintf(output, "%s%s",
951 csv_sep, counter->cgrp->name);
932 952
933 fputc('\n', stderr); 953 fputc('\n', output);
934 continue; 954 continue;
935 } 955 }
936 956
@@ -943,9 +963,10 @@ static void print_counter(struct perf_evsel *counter)
943 print_noise(counter, 1.0); 963 print_noise(counter, 1.0);
944 964
945 if (run != ena) 965 if (run != ena)
946 fprintf(stderr, " (%.2f%%)", 100.0 * run / ena); 966 fprintf(output, " (%.2f%%)",
967 100.0 * run / ena);
947 } 968 }
948 fputc('\n', stderr); 969 fputc('\n', output);
949 } 970 }
950} 971}
951 972
@@ -957,21 +978,21 @@ static void print_stat(int argc, const char **argv)
957 fflush(stdout); 978 fflush(stdout);
958 979
959 if (!csv_output) { 980 if (!csv_output) {
960 fprintf(stderr, "\n"); 981 fprintf(output, "\n");
961 fprintf(stderr, " Performance counter stats for "); 982 fprintf(output, " Performance counter stats for ");
962 if(target_pid == -1 && target_tid == -1) { 983 if(target_pid == -1 && target_tid == -1) {
963 fprintf(stderr, "\'%s", argv[0]); 984 fprintf(output, "\'%s", argv[0]);
964 for (i = 1; i < argc; i++) 985 for (i = 1; i < argc; i++)
965 fprintf(stderr, " %s", argv[i]); 986 fprintf(output, " %s", argv[i]);
966 } else if (target_pid != -1) 987 } else if (target_pid != -1)
967 fprintf(stderr, "process id \'%d", target_pid); 988 fprintf(output, "process id \'%d", target_pid);
968 else 989 else
969 fprintf(stderr, "thread id \'%d", target_tid); 990 fprintf(output, "thread id \'%d", target_tid);
970 991
971 fprintf(stderr, "\'"); 992 fprintf(output, "\'");
972 if (run_count > 1) 993 if (run_count > 1)
973 fprintf(stderr, " (%d runs)", run_count); 994 fprintf(output, " (%d runs)", run_count);
974 fprintf(stderr, ":\n\n"); 995 fprintf(output, ":\n\n");
975 } 996 }
976 997
977 if (no_aggr) { 998 if (no_aggr) {
@@ -984,15 +1005,15 @@ static void print_stat(int argc, const char **argv)
984 1005
985 if (!csv_output) { 1006 if (!csv_output) {
986 if (!null_run) 1007 if (!null_run)
987 fprintf(stderr, "\n"); 1008 fprintf(output, "\n");
988 fprintf(stderr, " %17.9f seconds time elapsed", 1009 fprintf(output, " %17.9f seconds time elapsed",
989 avg_stats(&walltime_nsecs_stats)/1e9); 1010 avg_stats(&walltime_nsecs_stats)/1e9);
990 if (run_count > 1) { 1011 if (run_count > 1) {
991 fprintf(stderr, " "); 1012 fprintf(output, " ");
992 print_noise_pct(stddev_stats(&walltime_nsecs_stats), 1013 print_noise_pct(stddev_stats(&walltime_nsecs_stats),
993 avg_stats(&walltime_nsecs_stats)); 1014 avg_stats(&walltime_nsecs_stats));
994 } 1015 }
995 fprintf(stderr, "\n\n"); 1016 fprintf(output, "\n\n");
996 } 1017 }
997} 1018}
998 1019
@@ -1030,6 +1051,8 @@ static int stat__set_big_num(const struct option *opt __used,
1030 return 0; 1051 return 0;
1031} 1052}
1032 1053
1054static bool append_file;
1055
1033static const struct option options[] = { 1056static const struct option options[] = {
1034 OPT_CALLBACK('e', "event", &evsel_list, "event", 1057 OPT_CALLBACK('e', "event", &evsel_list, "event",
1035 "event selector. use 'perf list' to list available events", 1058 "event selector. use 'perf list' to list available events",
@@ -1070,6 +1093,11 @@ static const struct option options[] = {
1070 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 1093 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
1071 "monitor event in cgroup name only", 1094 "monitor event in cgroup name only",
1072 parse_cgroups), 1095 parse_cgroups),
1096 OPT_STRING('o', "output", &output_name, "file",
1097 "output file name"),
1098 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
1099 OPT_INTEGER(0, "log-fd", &output_fd,
1100 "log output to fd, instead of stderr"),
1073 OPT_END() 1101 OPT_END()
1074}; 1102};
1075 1103
@@ -1141,6 +1169,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1141{ 1169{
1142 struct perf_evsel *pos; 1170 struct perf_evsel *pos;
1143 int status = -ENOMEM; 1171 int status = -ENOMEM;
1172 const char *mode;
1144 1173
1145 setlocale(LC_ALL, ""); 1174 setlocale(LC_ALL, "");
1146 1175
@@ -1151,16 +1180,46 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1151 argc = parse_options(argc, argv, options, stat_usage, 1180 argc = parse_options(argc, argv, options, stat_usage,
1152 PARSE_OPT_STOP_AT_NON_OPTION); 1181 PARSE_OPT_STOP_AT_NON_OPTION);
1153 1182
1154 if (csv_sep) 1183 output = stderr;
1184 if (output_name && strcmp(output_name, "-"))
1185 output = NULL;
1186
1187 if (output_name && output_fd) {
1188 fprintf(stderr, "cannot use both --output and --log-fd\n");
1189 usage_with_options(stat_usage, options);
1190 }
1191 if (!output) {
1192 struct timespec tm;
1193 mode = append_file ? "a" : "w";
1194
1195 output = fopen(output_name, mode);
1196 if (!output) {
1197 perror("failed to create output file");
1198 exit(-1);
1199 }
1200 clock_gettime(CLOCK_REALTIME, &tm);
1201 fprintf(output, "# started on %s\n", ctime(&tm.tv_sec));
1202 } else if (output_fd != 2) {
1203 mode = append_file ? "a" : "w";
1204 output = fdopen(output_fd, mode);
1205 if (!output) {
1206 perror("Failed opening logfd");
1207 return -errno;
1208 }
1209 }
1210
1211 if (csv_sep) {
1155 csv_output = true; 1212 csv_output = true;
1156 else 1213 if (!strcmp(csv_sep, "\\t"))
1214 csv_sep = "\t";
1215 } else
1157 csv_sep = DEFAULT_SEPARATOR; 1216 csv_sep = DEFAULT_SEPARATOR;
1158 1217
1159 /* 1218 /*
1160 * let the spreadsheet do the pretty-printing 1219 * let the spreadsheet do the pretty-printing
1161 */ 1220 */
1162 if (csv_output) { 1221 if (csv_output) {
1163 /* User explicitely passed -B? */ 1222 /* User explicitly passed -B? */
1164 if (big_num_opt == 1) { 1223 if (big_num_opt == 1) {
1165 fprintf(stderr, "-B option not supported with -x\n"); 1224 fprintf(stderr, "-B option not supported with -x\n");
1166 usage_with_options(stat_usage, options); 1225 usage_with_options(stat_usage, options);
@@ -1226,7 +1285,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1226 status = 0; 1285 status = 0;
1227 for (run_idx = 0; run_idx < run_count; run_idx++) { 1286 for (run_idx = 0; run_idx < run_count; run_idx++) {
1228 if (run_count != 1 && verbose) 1287 if (run_count != 1 && verbose)
1229 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); 1288 fprintf(output, "[ perf stat: executing run #%d ... ]\n",
1289 run_idx + 1);
1230 1290
1231 if (sync_run) 1291 if (sync_run)
1232 sync(); 1292 sync();
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 55f4c76f2821..831d1baeac37 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -291,7 +291,7 @@ static int test__open_syscall_event(void)
291 goto out_thread_map_delete; 291 goto out_thread_map_delete;
292 } 292 }
293 293
294 if (perf_evsel__open_per_thread(evsel, threads, false) < 0) { 294 if (perf_evsel__open_per_thread(evsel, threads, false, NULL) < 0) {
295 pr_debug("failed to open counter: %s, " 295 pr_debug("failed to open counter: %s, "
296 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 296 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
297 strerror(errno)); 297 strerror(errno));
@@ -366,7 +366,7 @@ static int test__open_syscall_event_on_all_cpus(void)
366 goto out_thread_map_delete; 366 goto out_thread_map_delete;
367 } 367 }
368 368
369 if (perf_evsel__open(evsel, cpus, threads, false) < 0) { 369 if (perf_evsel__open(evsel, cpus, threads, false, NULL) < 0) {
370 pr_debug("failed to open counter: %s, " 370 pr_debug("failed to open counter: %s, "
371 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 371 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
372 strerror(errno)); 372 strerror(errno));
@@ -531,7 +531,7 @@ static int test__basic_mmap(void)
531 531
532 perf_evlist__add(evlist, evsels[i]); 532 perf_evlist__add(evlist, evsels[i]);
533 533
534 if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) { 534 if (perf_evsel__open(evsels[i], cpus, threads, false, NULL) < 0) {
535 pr_debug("failed to open counter: %s, " 535 pr_debug("failed to open counter: %s, "
536 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 536 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
537 strerror(errno)); 537 strerror(errno));
@@ -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..c9cdedb58134 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,7 @@ 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; 92static bool sample_id_all_avail = true;
89static unsigned int mmap_pages = 128; 93static unsigned int mmap_pages = 128;
90 94
91static bool dump_symtab = false; 95static bool dump_symtab = false;
@@ -93,7 +97,6 @@ static bool dump_symtab = false;
93static struct winsize winsize; 97static struct winsize winsize;
94 98
95static const char *sym_filter = NULL; 99static const char *sym_filter = NULL;
96struct sym_entry *sym_filter_entry_sched = NULL;
97static int sym_pcnt_filter = 5; 100static int sym_pcnt_filter = 5;
98 101
99/* 102/*
@@ -136,18 +139,18 @@ static void sig_winch_handler(int sig __used)
136 update_print_entries(&winsize); 139 update_print_entries(&winsize);
137} 140}
138 141
139static int parse_source(struct sym_entry *syme) 142static int parse_source(struct hist_entry *he)
140{ 143{
141 struct symbol *sym; 144 struct symbol *sym;
142 struct annotation *notes; 145 struct annotation *notes;
143 struct map *map; 146 struct map *map;
144 int err = -1; 147 int err = -1;
145 148
146 if (!syme) 149 if (!he || !he->ms.sym)
147 return -1; 150 return -1;
148 151
149 sym = sym_entry__symbol(syme); 152 sym = he->ms.sym;
150 map = syme->map; 153 map = he->ms.map;
151 154
152 /* 155 /*
153 * We can't annotate with just /proc/kallsyms 156 * We can't annotate with just /proc/kallsyms
@@ -175,52 +178,63 @@ static int parse_source(struct sym_entry *syme)
175 return err; 178 return err;
176 } 179 }
177 180
178 err = symbol__annotate(sym, syme->map, 0); 181 err = symbol__annotate(sym, map, 0);
179 if (err == 0) { 182 if (err == 0) {
180out_assign: 183out_assign:
181 top.sym_filter_entry = syme; 184 top.sym_filter_entry = he;
182 } 185 }
183 186
184 pthread_mutex_unlock(&notes->lock); 187 pthread_mutex_unlock(&notes->lock);
185 return err; 188 return err;
186} 189}
187 190
188static void __zero_source_counters(struct sym_entry *syme) 191static void __zero_source_counters(struct hist_entry *he)
189{ 192{
190 struct symbol *sym = sym_entry__symbol(syme); 193 struct symbol *sym = he->ms.sym;
191 symbol__annotate_zero_histograms(sym); 194 symbol__annotate_zero_histograms(sym);
192} 195}
193 196
194static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) 197static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
195{ 198{
196 struct annotation *notes; 199 struct annotation *notes;
197 struct symbol *sym; 200 struct symbol *sym;
198 201
199 if (syme != top.sym_filter_entry) 202 if (he == NULL || he->ms.sym == NULL ||
203 ((top.sym_filter_entry == NULL ||
204 top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1))
200 return; 205 return;
201 206
202 sym = sym_entry__symbol(syme); 207 sym = he->ms.sym;
203 notes = symbol__annotation(sym); 208 notes = symbol__annotation(sym);
204 209
205 if (pthread_mutex_trylock(&notes->lock)) 210 if (pthread_mutex_trylock(&notes->lock))
206 return; 211 return;
207 212
208 ip = syme->map->map_ip(syme->map, ip); 213 if (notes->src == NULL &&
209 symbol__inc_addr_samples(sym, syme->map, counter, ip); 214 symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
215 pthread_mutex_unlock(&notes->lock);
216 pr_err("Not enough memory for annotating '%s' symbol!\n",
217 sym->name);
218 sleep(1);
219 return;
220 }
221
222 ip = he->ms.map->map_ip(he->ms.map, ip);
223 symbol__inc_addr_samples(sym, he->ms.map, counter, ip);
210 224
211 pthread_mutex_unlock(&notes->lock); 225 pthread_mutex_unlock(&notes->lock);
212} 226}
213 227
214static void show_details(struct sym_entry *syme) 228static void show_details(struct hist_entry *he)
215{ 229{
216 struct annotation *notes; 230 struct annotation *notes;
217 struct symbol *symbol; 231 struct symbol *symbol;
218 int more; 232 int more;
219 233
220 if (!syme) 234 if (!he)
221 return; 235 return;
222 236
223 symbol = sym_entry__symbol(syme); 237 symbol = he->ms.sym;
224 notes = symbol__annotation(symbol); 238 notes = symbol__annotation(symbol);
225 239
226 pthread_mutex_lock(&notes->lock); 240 pthread_mutex_lock(&notes->lock);
@@ -231,7 +245,7 @@ static void show_details(struct sym_entry *syme)
231 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); 245 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name);
232 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 246 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
233 247
234 more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx, 248 more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx,
235 0, sym_pcnt_filter, top.print_entries, 4); 249 0, sym_pcnt_filter, top.print_entries, 4);
236 if (top.zero) 250 if (top.zero)
237 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); 251 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx);
@@ -245,21 +259,28 @@ out_unlock:
245 259
246static const char CONSOLE_CLEAR[] = ""; 260static const char CONSOLE_CLEAR[] = "";
247 261
248static void __list_insert_active_sym(struct sym_entry *syme) 262static struct hist_entry *
263 perf_session__add_hist_entry(struct perf_session *session,
264 struct addr_location *al,
265 struct perf_sample *sample,
266 struct perf_evsel *evsel)
249{ 267{
250 list_add(&syme->node, &top.active_symbols); 268 struct hist_entry *he;
269
270 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period);
271 if (he == NULL)
272 return NULL;
273
274 session->hists.stats.total_period += sample->period;
275 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
276 return he;
251} 277}
252 278
253static void print_sym_table(struct perf_session *session) 279static void print_sym_table(void)
254{ 280{
255 char bf[160]; 281 char bf[160];
256 int printed = 0; 282 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; 283 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 284
264 puts(CONSOLE_CLEAR); 285 puts(CONSOLE_CLEAR);
265 286
@@ -270,10 +291,14 @@ static void print_sym_table(struct perf_session *session)
270 291
271 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 292 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
272 293
273 if (session->hists.stats.total_lost != 0) { 294 if (top.sym_evsel->hists.stats.nr_lost_warned !=
274 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); 295 top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) {
275 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", 296 top.sym_evsel->hists.stats.nr_lost_warned =
276 session->hists.stats.total_lost); 297 top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST];
298 color_fprintf(stdout, PERF_COLOR_RED,
299 "WARNING: LOST %d chunks, Check IO/CPU overload",
300 top.sym_evsel->hists.stats.nr_lost_warned);
301 ++printed;
277 } 302 }
278 303
279 if (top.sym_filter_entry) { 304 if (top.sym_filter_entry) {
@@ -281,58 +306,15 @@ static void print_sym_table(struct perf_session *session)
281 return; 306 return;
282 } 307 }
283 308
284 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width, 309 hists__collapse_resort_threaded(&top.sym_evsel->hists);
285 &sym_width); 310 hists__output_resort_threaded(&top.sym_evsel->hists);
286 311 hists__decay_entries_threaded(&top.sym_evsel->hists,
287 if (sym_width + dso_width > winsize.ws_col - 29) { 312 top.hide_user_symbols,
288 dso_width = dso_short_width; 313 top.hide_kernel_symbols);
289 if (sym_width + dso_width > winsize.ws_col - 29) 314 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'); 315 putchar('\n');
293 if (top.evlist->nr_entries == 1) 316 hists__fprintf(&top.sym_evsel->hists, NULL, false, false,
294 printf(" samples pcnt"); 317 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} 318}
337 319
338static void prompt_integer(int *target, const char *msg) 320static void prompt_integer(int *target, const char *msg)
@@ -370,10 +352,11 @@ static void prompt_percent(int *target, const char *msg)
370 *target = tmp; 352 *target = tmp;
371} 353}
372 354
373static void prompt_symbol(struct sym_entry **target, const char *msg) 355static void prompt_symbol(struct hist_entry **target, const char *msg)
374{ 356{
375 char *buf = malloc(0), *p; 357 char *buf = malloc(0), *p;
376 struct sym_entry *syme = *target, *n, *found = NULL; 358 struct hist_entry *syme = *target, *n, *found = NULL;
359 struct rb_node *next;
377 size_t dummy = 0; 360 size_t dummy = 0;
378 361
379 /* zero counters of active symbol */ 362 /* zero counters of active symbol */
@@ -390,17 +373,14 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
390 if (p) 373 if (p)
391 *p = 0; 374 *p = 0;
392 375
393 pthread_mutex_lock(&top.active_symbols_lock); 376 next = rb_first(&top.sym_evsel->hists.entries);
394 syme = list_entry(top.active_symbols.next, struct sym_entry, node); 377 while (next) {
395 pthread_mutex_unlock(&top.active_symbols_lock); 378 n = rb_entry(next, struct hist_entry, rb_node);
396 379 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
397 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) { 380 found = n;
398 struct symbol *sym = sym_entry__symbol(syme);
399
400 if (!strcmp(buf, sym->name)) {
401 found = syme;
402 break; 381 break;
403 } 382 }
383 next = rb_next(&n->rb_node);
404 } 384 }
405 385
406 if (!found) { 386 if (!found) {
@@ -419,7 +399,7 @@ static void print_mapped_keys(void)
419 char *name = NULL; 399 char *name = NULL;
420 400
421 if (top.sym_filter_entry) { 401 if (top.sym_filter_entry) {
422 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); 402 struct symbol *sym = top.sym_filter_entry->ms.sym;
423 name = sym->name; 403 name = sym->name;
424 } 404 }
425 405
@@ -436,9 +416,6 @@ static void print_mapped_keys(void)
436 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 416 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
437 fprintf(stdout, "\t[S] stop annotation.\n"); 417 fprintf(stdout, "\t[S] stop annotation.\n");
438 418
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, 419 fprintf(stdout,
443 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 420 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
444 top.hide_kernel_symbols ? "yes" : "no"); 421 top.hide_kernel_symbols ? "yes" : "no");
@@ -465,7 +442,6 @@ static int key_mapped(int c)
465 case 'S': 442 case 'S':
466 return 1; 443 return 1;
467 case 'E': 444 case 'E':
468 case 'w':
469 return top.evlist->nr_entries > 1 ? 1 : 0; 445 return top.evlist->nr_entries > 1 ? 1 : 0;
470 default: 446 default:
471 break; 447 break;
@@ -474,7 +450,7 @@ static int key_mapped(int c)
474 return 0; 450 return 0;
475} 451}
476 452
477static void handle_keypress(struct perf_session *session, int c) 453static void handle_keypress(int c)
478{ 454{
479 if (!key_mapped(c)) { 455 if (!key_mapped(c)) {
480 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 456 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -550,7 +526,7 @@ static void handle_keypress(struct perf_session *session, int c)
550 case 'Q': 526 case 'Q':
551 printf("exiting.\n"); 527 printf("exiting.\n");
552 if (dump_symtab) 528 if (dump_symtab)
553 perf_session__fprintf_dsos(session, stderr); 529 perf_session__fprintf_dsos(top.session, stderr);
554 exit(0); 530 exit(0);
555 case 's': 531 case 's':
556 prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); 532 prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
@@ -559,7 +535,7 @@ static void handle_keypress(struct perf_session *session, int c)
559 if (!top.sym_filter_entry) 535 if (!top.sym_filter_entry)
560 break; 536 break;
561 else { 537 else {
562 struct sym_entry *syme = top.sym_filter_entry; 538 struct hist_entry *syme = top.sym_filter_entry;
563 539
564 top.sym_filter_entry = NULL; 540 top.sym_filter_entry = NULL;
565 __zero_source_counters(syme); 541 __zero_source_counters(syme);
@@ -568,9 +544,6 @@ static void handle_keypress(struct perf_session *session, int c)
568 case 'U': 544 case 'U':
569 top.hide_user_symbols = !top.hide_user_symbols; 545 top.hide_user_symbols = !top.hide_user_symbols;
570 break; 546 break;
571 case 'w':
572 top.display_weighted = ~top.display_weighted;
573 break;
574 case 'z': 547 case 'z':
575 top.zero = !top.zero; 548 top.zero = !top.zero;
576 break; 549 break;
@@ -579,19 +552,30 @@ static void handle_keypress(struct perf_session *session, int c)
579 } 552 }
580} 553}
581 554
555static void perf_top__sort_new_samples(void *arg)
556{
557 struct perf_top *t = arg;
558 perf_top__reset_sample_counters(t);
559
560 if (t->evlist->selected != NULL)
561 t->sym_evsel = t->evlist->selected;
562
563 hists__collapse_resort_threaded(&t->sym_evsel->hists);
564 hists__output_resort_threaded(&t->sym_evsel->hists);
565 hists__decay_entries_threaded(&t->sym_evsel->hists,
566 top.hide_user_symbols,
567 top.hide_kernel_symbols);
568}
569
582static void *display_thread_tui(void *arg __used) 570static void *display_thread_tui(void *arg __used)
583{ 571{
584 int err = 0; 572 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
585 pthread_mutex_lock(&top.active_symbols_lock); 573
586 while (list_empty(&top.active_symbols)) { 574 perf_top__sort_new_samples(&top);
587 err = pthread_cond_wait(&top.active_symbols_cond, 575 perf_evlist__tui_browse_hists(top.evlist, help,
588 &top.active_symbols_lock); 576 perf_top__sort_new_samples,
589 if (err) 577 &top, top.delay_secs);
590 break; 578
591 }
592 pthread_mutex_unlock(&top.active_symbols_lock);
593 if (!err)
594 perf_top__tui_browser(&top);
595 exit_browser(0); 579 exit_browser(0);
596 exit(0); 580 exit(0);
597 return NULL; 581 return NULL;
@@ -602,7 +586,6 @@ static void *display_thread(void *arg __used)
602 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 586 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
603 struct termios tc, save; 587 struct termios tc, save;
604 int delay_msecs, c; 588 int delay_msecs, c;
605 struct perf_session *session = (struct perf_session *) arg;
606 589
607 tcgetattr(0, &save); 590 tcgetattr(0, &save);
608 tc = save; 591 tc = save;
@@ -610,20 +593,35 @@ static void *display_thread(void *arg __used)
610 tc.c_cc[VMIN] = 0; 593 tc.c_cc[VMIN] = 0;
611 tc.c_cc[VTIME] = 0; 594 tc.c_cc[VTIME] = 0;
612 595
596 pthread__unblock_sigwinch();
613repeat: 597repeat:
614 delay_msecs = top.delay_secs * 1000; 598 delay_msecs = top.delay_secs * 1000;
615 tcsetattr(0, TCSANOW, &tc); 599 tcsetattr(0, TCSANOW, &tc);
616 /* trash return*/ 600 /* trash return*/
617 getc(stdin); 601 getc(stdin);
618 602
619 do { 603 while (1) {
620 print_sym_table(session); 604 print_sym_table();
621 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 605 /*
622 606 * Either timeout expired or we got an EINTR due to SIGWINCH,
607 * refresh screen in both cases.
608 */
609 switch (poll(&stdin_poll, 1, delay_msecs)) {
610 case 0:
611 continue;
612 case -1:
613 if (errno == EINTR)
614 continue;
615 /* Fall trhu */
616 default:
617 goto process_hotkey;
618 }
619 }
620process_hotkey:
623 c = getc(stdin); 621 c = getc(stdin);
624 tcsetattr(0, TCSAFLUSH, &save); 622 tcsetattr(0, TCSAFLUSH, &save);
625 623
626 handle_keypress(session, c); 624 handle_keypress(c);
627 goto repeat; 625 goto repeat;
628 626
629 return NULL; 627 return NULL;
@@ -644,9 +642,8 @@ static const char *skip_symbols[] = {
644 NULL 642 NULL
645}; 643};
646 644
647static int symbol_filter(struct map *map, struct symbol *sym) 645static int symbol_filter(struct map *map __used, struct symbol *sym)
648{ 646{
649 struct sym_entry *syme;
650 const char *name = sym->name; 647 const char *name = sym->name;
651 int i; 648 int i;
652 649
@@ -666,16 +663,6 @@ static int symbol_filter(struct map *map, struct symbol *sym)
666 strstr(name, "_text_end")) 663 strstr(name, "_text_end"))
667 return 1; 664 return 1;
668 665
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++) { 666 for (i = 0; skip_symbols[i]; i++) {
680 if (!strcmp(skip_symbols[i], name)) { 667 if (!strcmp(skip_symbols[i], name)) {
681 sym->ignore = true; 668 sym->ignore = true;
@@ -687,13 +674,15 @@ static int symbol_filter(struct map *map, struct symbol *sym)
687} 674}
688 675
689static void perf_event__process_sample(const union perf_event *event, 676static void perf_event__process_sample(const union perf_event *event,
677 struct perf_evsel *evsel,
690 struct perf_sample *sample, 678 struct perf_sample *sample,
691 struct perf_session *session) 679 struct perf_session *session)
692{ 680{
681 struct symbol *parent = NULL;
693 u64 ip = event->ip.ip; 682 u64 ip = event->ip.ip;
694 struct sym_entry *syme;
695 struct addr_location al; 683 struct addr_location al;
696 struct machine *machine; 684 struct machine *machine;
685 int err;
697 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 686 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
698 687
699 ++top.samples; 688 ++top.samples;
@@ -782,51 +771,43 @@ static void perf_event__process_sample(const union perf_event *event,
782 sleep(5); 771 sleep(5);
783 vmlinux_warned = true; 772 vmlinux_warned = true;
784 } 773 }
785
786 return;
787 } 774 }
788 775
789 /* let's see, whether we need to install initial sym_filter_entry */ 776 if (al.sym == NULL || !al.sym->ignore) {
790 if (sym_filter_entry_sched) { 777 struct hist_entry *he;
791 top.sym_filter_entry = sym_filter_entry_sched; 778
792 sym_filter_entry_sched = NULL; 779 if ((sort__has_parent || symbol_conf.use_callchain) &&
793 if (parse_source(top.sym_filter_entry) < 0) { 780 sample->callchain) {
794 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); 781 err = perf_session__resolve_callchain(session, al.thread,
795 782 sample->callchain, &parent);
796 pr_err("Can't annotate %s", sym->name); 783 if (err)
797 if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) { 784 return;
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 } 785 }
804 }
805 786
806 syme = symbol__priv(al.sym); 787 he = perf_session__add_hist_entry(session, &al, sample, evsel);
807 if (!al.sym->ignore) { 788 if (he == NULL) {
808 struct perf_evsel *evsel; 789 pr_err("Problem incrementing symbol period, skipping event\n");
790 return;
791 }
809 792
810 evsel = perf_evlist__id2evsel(top.evlist, sample->id); 793 if (symbol_conf.use_callchain) {
811 assert(evsel != NULL); 794 err = callchain_append(he->callchain, &session->callchain_cursor,
812 syme->count[evsel->idx]++; 795 sample->period);
813 record_precise_ip(syme, evsel->idx, ip); 796 if (err)
814 pthread_mutex_lock(&top.active_symbols_lock); 797 return;
815 if (list_empty(&syme->node) || !syme->node.next) {
816 static bool first = true;
817 __list_insert_active_sym(syme);
818 if (first) {
819 pthread_cond_broadcast(&top.active_symbols_cond);
820 first = false;
821 }
822 } 798 }
823 pthread_mutex_unlock(&top.active_symbols_lock); 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)
828{ 808{
829 struct perf_sample sample; 809 struct perf_sample sample;
810 struct perf_evsel *evsel;
830 union perf_event *event; 811 union perf_event *event;
831 int ret; 812 int ret;
832 813
@@ -837,10 +818,16 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
837 continue; 818 continue;
838 } 819 }
839 820
821 evsel = perf_evlist__id2evsel(self->evlist, sample.id);
822 assert(evsel != NULL);
823
840 if (event->header.type == PERF_RECORD_SAMPLE) 824 if (event->header.type == PERF_RECORD_SAMPLE)
841 perf_event__process_sample(event, &sample, self); 825 perf_event__process_sample(event, evsel, &sample, self);
842 else 826 else if (event->header.type < PERF_RECORD_MAX) {
827 hists__inc_nr_events(&evsel->hists, event->header.type);
843 perf_event__process(event, &sample, self); 828 perf_event__process(event, &sample, self);
829 } else
830 ++self->hists.stats.nr_unknown_events;
844 } 831 }
845} 832}
846 833
@@ -854,10 +841,16 @@ static void perf_session__mmap_read(struct perf_session *self)
854 841
855static void start_counters(struct perf_evlist *evlist) 842static void start_counters(struct perf_evlist *evlist)
856{ 843{
857 struct perf_evsel *counter; 844 struct perf_evsel *counter, *first;
845
846 first = list_entry(evlist->entries.next, struct perf_evsel, node);
858 847
859 list_for_each_entry(counter, &evlist->entries, node) { 848 list_for_each_entry(counter, &evlist->entries, node) {
860 struct perf_event_attr *attr = &counter->attr; 849 struct perf_event_attr *attr = &counter->attr;
850 struct xyarray *group_fd = NULL;
851
852 if (group && counter != first)
853 group_fd = first->fd;
861 854
862 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 855 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
863 856
@@ -872,16 +865,29 @@ static void start_counters(struct perf_evlist *evlist)
872 attr->read_format |= PERF_FORMAT_ID; 865 attr->read_format |= PERF_FORMAT_ID;
873 } 866 }
874 867
868 if (symbol_conf.use_callchain)
869 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
870
875 attr->mmap = 1; 871 attr->mmap = 1;
872 attr->comm = 1;
876 attr->inherit = inherit; 873 attr->inherit = inherit;
874retry_sample_id:
875 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
877try_again: 876try_again:
878 if (perf_evsel__open(counter, top.evlist->cpus, 877 if (perf_evsel__open(counter, top.evlist->cpus,
879 top.evlist->threads, group) < 0) { 878 top.evlist->threads, group,
879 group_fd) < 0) {
880 int err = errno; 880 int err = errno;
881 881
882 if (err == EPERM || err == EACCES) { 882 if (err == EPERM || err == EACCES) {
883 ui__warning_paranoid(); 883 ui__error_paranoid();
884 goto out_err; 884 goto out_err;
885 } else if (err == EINVAL && sample_id_all_avail) {
886 /*
887 * Old kernel, no attr->sample_id_type_all field
888 */
889 sample_id_all_avail = false;
890 goto retry_sample_id;
885 } 891 }
886 /* 892 /*
887 * If it's cycles then fall back to hrtimer 893 * If it's cycles then fall back to hrtimer
@@ -927,35 +933,56 @@ out_err:
927 exit(0); 933 exit(0);
928} 934}
929 935
936static int setup_sample_type(void)
937{
938 if (!sort_has_symbols) {
939 if (symbol_conf.use_callchain) {
940 ui__warning("Selected -g but \"sym\" not present in --sort/-s.");
941 return -EINVAL;
942 }
943 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
944 if (callchain_register_param(&callchain_param) < 0) {
945 ui__warning("Can't register callchain params.\n");
946 return -EINVAL;
947 }
948 }
949
950 return 0;
951}
952
930static int __cmd_top(void) 953static int __cmd_top(void)
931{ 954{
932 pthread_t thread; 955 pthread_t thread;
933 int ret __used; 956 int ret;
934 /* 957 /*
935 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 958 * 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. 959 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
937 */ 960 */
938 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL); 961 top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
939 if (session == NULL) 962 if (top.session == NULL)
940 return -ENOMEM; 963 return -ENOMEM;
941 964
965 ret = setup_sample_type();
966 if (ret)
967 goto out_delete;
968
942 if (top.target_tid != -1) 969 if (top.target_tid != -1)
943 perf_event__synthesize_thread_map(top.evlist->threads, 970 perf_event__synthesize_thread_map(top.evlist->threads,
944 perf_event__process, session); 971 perf_event__process, top.session);
945 else 972 else
946 perf_event__synthesize_threads(perf_event__process, session); 973 perf_event__synthesize_threads(perf_event__process, top.session);
947 974
948 start_counters(top.evlist); 975 start_counters(top.evlist);
949 session->evlist = top.evlist; 976 top.session->evlist = top.evlist;
950 perf_session__update_sample_type(session); 977 perf_session__update_sample_type(top.session);
951 978
952 /* Wait for a minimal set of events before starting the snapshot */ 979 /* Wait for a minimal set of events before starting the snapshot */
953 poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 980 poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
954 981
955 perf_session__mmap_read(session); 982 perf_session__mmap_read(top.session);
956 983
957 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 984 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
958 display_thread), session)) { 985 display_thread), NULL)) {
959 printf("Could not create display thread.\n"); 986 printf("Could not create display thread.\n");
960 exit(-1); 987 exit(-1);
961 } 988 }
@@ -973,12 +1000,96 @@ static int __cmd_top(void)
973 while (1) { 1000 while (1) {
974 u64 hits = top.samples; 1001 u64 hits = top.samples;
975 1002
976 perf_session__mmap_read(session); 1003 perf_session__mmap_read(top.session);
977 1004
978 if (hits == top.samples) 1005 if (hits == top.samples)
979 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 1006 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
980 } 1007 }
981 1008
1009out_delete:
1010 perf_session__delete(top.session);
1011 top.session = NULL;
1012
1013 return 0;
1014}
1015
1016static int
1017parse_callchain_opt(const struct option *opt __used, const char *arg,
1018 int unset)
1019{
1020 char *tok, *tok2;
1021 char *endptr;
1022
1023 /*
1024 * --no-call-graph
1025 */
1026 if (unset) {
1027 dont_use_callchains = true;
1028 return 0;
1029 }
1030
1031 symbol_conf.use_callchain = true;
1032
1033 if (!arg)
1034 return 0;
1035
1036 tok = strtok((char *)arg, ",");
1037 if (!tok)
1038 return -1;
1039
1040 /* get the output mode */
1041 if (!strncmp(tok, "graph", strlen(arg)))
1042 callchain_param.mode = CHAIN_GRAPH_ABS;
1043
1044 else if (!strncmp(tok, "flat", strlen(arg)))
1045 callchain_param.mode = CHAIN_FLAT;
1046
1047 else if (!strncmp(tok, "fractal", strlen(arg)))
1048 callchain_param.mode = CHAIN_GRAPH_REL;
1049
1050 else if (!strncmp(tok, "none", strlen(arg))) {
1051 callchain_param.mode = CHAIN_NONE;
1052 symbol_conf.use_callchain = false;
1053
1054 return 0;
1055 }
1056
1057 else
1058 return -1;
1059
1060 /* get the min percentage */
1061 tok = strtok(NULL, ",");
1062 if (!tok)
1063 goto setup;
1064
1065 callchain_param.min_percent = strtod(tok, &endptr);
1066 if (tok == endptr)
1067 return -1;
1068
1069 /* get the print limit */
1070 tok2 = strtok(NULL, ",");
1071 if (!tok2)
1072 goto setup;
1073
1074 if (tok2[0] != 'c') {
1075 callchain_param.print_limit = strtod(tok2, &endptr);
1076 tok2 = strtok(NULL, ",");
1077 if (!tok2)
1078 goto setup;
1079 }
1080
1081 /* get the call chain order */
1082 if (!strcmp(tok2, "caller"))
1083 callchain_param.order = ORDER_CALLER;
1084 else if (!strcmp(tok2, "callee"))
1085 callchain_param.order = ORDER_CALLEE;
1086 else
1087 return -1;
1088setup:
1089 if (callchain_register_param(&callchain_param) < 0) {
1090 fprintf(stderr, "Can't register callchain params\n");
1091 return -1;
1092 }
982 return 0; 1093 return 0;
983} 1094}
984 1095
@@ -1018,7 +1129,7 @@ static const struct option options[] = {
1018 "put the counters into a counter group"), 1129 "put the counters into a counter group"),
1019 OPT_BOOLEAN('i', "inherit", &inherit, 1130 OPT_BOOLEAN('i', "inherit", &inherit,
1020 "child tasks inherit counters"), 1131 "child tasks inherit counters"),
1021 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1132 OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name",
1022 "symbol to annotate"), 1133 "symbol to annotate"),
1023 OPT_BOOLEAN('z', "zero", &top.zero, 1134 OPT_BOOLEAN('z', "zero", &top.zero,
1024 "zero history across updates"), 1135 "zero history across updates"),
@@ -1032,6 +1143,28 @@ static const struct option options[] = {
1032 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 1143 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1033 OPT_INCR('v', "verbose", &verbose, 1144 OPT_INCR('v', "verbose", &verbose,
1034 "be more verbose (show counter open errors, etc)"), 1145 "be more verbose (show counter open errors, etc)"),
1146 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1147 "sort by key(s): pid, comm, dso, symbol, parent"),
1148 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1149 "Show a column with the number of samples"),
1150 OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order",
1151 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
1152 "Default: fractal,0.5,callee", &parse_callchain_opt,
1153 callchain_default_opt),
1154 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1155 "Show a column with the sum of periods"),
1156 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1157 "only consider symbols in these dsos"),
1158 OPT_STRING(0, "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1159 "only consider symbols in these comms"),
1160 OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1161 "only consider these symbols"),
1162 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
1163 "Interleave source code with assembly code (default)"),
1164 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
1165 "Display raw encoding of assembly instructions (default)"),
1166 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1167 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1035 OPT_END() 1168 OPT_END()
1036}; 1169};
1037 1170
@@ -1044,18 +1177,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1044 if (top.evlist == NULL) 1177 if (top.evlist == NULL)
1045 return -ENOMEM; 1178 return -ENOMEM;
1046 1179
1047 page_size = sysconf(_SC_PAGE_SIZE); 1180 symbol_conf.exclude_other = false;
1048 1181
1049 argc = parse_options(argc, argv, options, top_usage, 0); 1182 argc = parse_options(argc, argv, options, top_usage, 0);
1050 if (argc) 1183 if (argc)
1051 usage_with_options(top_usage, options); 1184 usage_with_options(top_usage, options);
1052 1185
1053 /* 1186 if (sort_order == default_sort_order)
1054 * XXX For now start disabled, only using TUI if explicitely asked for. 1187 sort_order = "dso,symbol";
1055 * Change that when handle_keys equivalent gets written, live annotation 1188
1056 * done, etc. 1189 setup_sorting(top_usage, options);
1057 */
1058 use_browser = 0;
1059 1190
1060 if (use_stdio) 1191 if (use_stdio)
1061 use_browser = 0; 1192 use_browser = 0;
@@ -1118,13 +1249,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1118 1249
1119 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 1250 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1120 1251
1121 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) + 1252 symbol_conf.priv_size = sizeof(struct annotation);
1122 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1123 1253
1124 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1254 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1125 if (symbol__init() < 0) 1255 if (symbol__init() < 0)
1126 return -1; 1256 return -1;
1127 1257
1258 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
1259 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1260 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1261
1262 /*
1263 * Avoid annotation data structures overhead when symbols aren't on the
1264 * sort list.
1265 */
1266 sort_has_symbols = sort_sym.list.next != NULL;
1267
1128 get_term_dimensions(&winsize); 1268 get_term_dimensions(&winsize);
1129 if (top.print_entries == 0) { 1269 if (top.print_entries == 0) {
1130 update_print_entries(&winsize); 1270 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..119e996035c8 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);
@@ -308,9 +310,12 @@ fallback:
308 } 310 }
309 err = -ENOENT; 311 err = -ENOENT;
310 dso->annotate_warned = 1; 312 dso->annotate_warned = 1;
311 pr_err("Can't annotate %s: No vmlinux file%s was found in the " 313 pr_err("Can't annotate %s:\n\n"
312 "path.\nPlease use 'perf buildid-cache -av vmlinux' or " 314 "No vmlinux file%s\nwas found in the path.\n\n"
313 "--vmlinux vmlinux.\n", 315 "Please use:\n\n"
316 " perf buildid-cache -av vmlinux\n\n"
317 "or:\n\n"
318 " --vmlinux vmlinux",
314 sym->name, build_id_msg ?: ""); 319 sym->name, build_id_msg ?: "");
315 goto out_free_filename; 320 goto out_free_filename;
316 } 321 }
@@ -323,10 +328,15 @@ fallback:
323 dso, dso->long_name, sym, sym->name); 328 dso, dso->long_name, sym, sym->name);
324 329
325 snprintf(command, sizeof(command), 330 snprintf(command, sizeof(command),
326 "objdump --start-address=0x%016" PRIx64 331 "objdump %s%s --start-address=0x%016" PRIx64
327 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand", 332 " --stop-address=0x%016" PRIx64
333 " -d %s %s -C %s|grep -v %s|expand",
334 disassembler_style ? "-M " : "",
335 disassembler_style ? disassembler_style : "",
328 map__rip_2objdump(map, sym->start), 336 map__rip_2objdump(map, sym->start),
329 map__rip_2objdump(map, sym->end), 337 map__rip_2objdump(map, sym->end),
338 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
339 symbol_conf.annotate_src ? "-S" : "",
330 symfs_filename, filename); 340 symfs_filename, filename);
331 341
332 pr_debug("Executing: %s\n", command); 342 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 fe02903f7d0f..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
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 155749d74350..26817daa2961 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -47,19 +47,20 @@ int dump_printf(const char *fmt, ...)
47} 47}
48 48
49#ifdef NO_NEWT_SUPPORT 49#ifdef NO_NEWT_SUPPORT
50void ui__warning(const char *format, ...) 50int ui__warning(const char *format, ...)
51{ 51{
52 va_list args; 52 va_list args;
53 53
54 va_start(args, format); 54 va_start(args, format);
55 vfprintf(stderr, format, args); 55 vfprintf(stderr, format, args);
56 va_end(args); 56 va_end(args);
57 return 0;
57} 58}
58#endif 59#endif
59 60
60void ui__warning_paranoid(void) 61int ui__error_paranoid(void)
61{ 62{
62 ui__warning("Permission error - are you root?\n" 63 return ui__error("Permission error - are you root?\n"
63 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" 64 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
64 " -1 - Not paranoid at all\n" 65 " -1 - Not paranoid at all\n"
65 " 0 - Disallow raw tracepoint access for unpriv\n" 66 " 0 - Disallow raw tracepoint access for unpriv\n"
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index fd53db47e3de..f2ce88d04f54 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -19,23 +19,18 @@ static inline int ui_helpline__show_help(const char *format __used, va_list ap _
19 return 0; 19 return 0;
20} 20}
21 21
22static inline struct ui_progress *ui_progress__new(const char *title __used, 22static inline void ui_progress__update(u64 curr __used, u64 total __used,
23 u64 total __used) 23 const char *title __used) {}
24{
25 return (struct ui_progress *)1;
26}
27
28static inline void ui_progress__update(struct ui_progress *self __used,
29 u64 curr __used) {}
30 24
31static inline void ui_progress__delete(struct ui_progress *self __used) {} 25#define ui__error(format, arg...) ui__warning(format, ##arg)
32#else 26#else
33extern char ui_helpline__last_msg[]; 27extern char ui_helpline__last_msg[];
34int ui_helpline__show_help(const char *format, va_list ap); 28int ui_helpline__show_help(const char *format, va_list ap);
35#include "ui/progress.h" 29#include "ui/progress.h"
30int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
36#endif 31#endif
37 32
38void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 33int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
39void ui__warning_paranoid(void); 34int ui__error_paranoid(void);
40 35
41#endif /* __PERF_DEBUG_H */ 36#endif /* __PERF_DEBUG_H */
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 c12bd476c6f7..fbb4b4ab9cc6 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -113,6 +113,19 @@ void perf_evlist__disable(struct perf_evlist *evlist)
113 } 113 }
114} 114}
115 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 }
127}
128
116int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 129int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
117{ 130{
118 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries; 131 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
@@ -520,3 +533,39 @@ bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
520 first = list_entry(evlist->entries.next, struct perf_evsel, node); 533 first = list_entry(evlist->entries.next, struct perf_evsel, node);
521 return first->attr.sample_id_all; 534 return first->attr.sample_id_all;
522} 535}
536
537void perf_evlist__set_selected(struct perf_evlist *evlist,
538 struct perf_evsel *evsel)
539{
540 evlist->selected = evsel;
541}
542
543int perf_evlist__open(struct perf_evlist *evlist, bool group)
544{
545 struct perf_evsel *evsel, *first;
546 int err, ncpus, nthreads;
547
548 first = list_entry(evlist->entries.next, struct perf_evsel, node);
549
550 list_for_each_entry(evsel, &evlist->entries, node) {
551 struct xyarray *group_fd = NULL;
552
553 if (group && evsel != first)
554 group_fd = first->fd;
555
556 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads,
557 group, group_fd);
558 if (err < 0)
559 goto out_err;
560 }
561
562 return 0;
563out_err:
564 ncpus = evlist->cpus ? evlist->cpus->nr : 1;
565 nthreads = evlist->threads ? evlist->threads->nr : 1;
566
567 list_for_each_entry_reverse(evsel, &evlist->entries, node)
568 perf_evsel__close(evsel, ncpus, nthreads);
569
570 return err;
571}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index ce85ae9ae57a..1779ffef7828 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;
@@ -49,11 +50,17 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
49 50
50union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 51union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
51 52
53int perf_evlist__open(struct perf_evlist *evlist, bool group);
54
52int perf_evlist__alloc_mmap(struct perf_evlist *evlist); 55int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
53int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); 56int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
54void perf_evlist__munmap(struct perf_evlist *evlist); 57void perf_evlist__munmap(struct perf_evlist *evlist);
55 58
56void perf_evlist__disable(struct perf_evlist *evlist); 59void perf_evlist__disable(struct perf_evlist *evlist);
60void perf_evlist__enable(struct perf_evlist *evlist);
61
62void perf_evlist__set_selected(struct perf_evlist *evlist,
63 struct perf_evsel *evsel);
57 64
58static inline void perf_evlist__set_maps(struct perf_evlist *evlist, 65static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
59 struct cpu_map *cpus, 66 struct cpu_map *cpus,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index a03a36b7908a..e42626422587 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"
@@ -14,6 +16,7 @@
14#include "thread_map.h" 16#include "thread_map.h"
15 17
16#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 18#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
19#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
17 20
18int __perf_evsel__sample_size(u64 sample_type) 21int __perf_evsel__sample_size(u64 sample_type)
19{ 22{
@@ -37,6 +40,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
37 evsel->idx = idx; 40 evsel->idx = idx;
38 evsel->attr = *attr; 41 evsel->attr = *attr;
39 INIT_LIST_HEAD(&evsel->node); 42 INIT_LIST_HEAD(&evsel->node);
43 hists__init(&evsel->hists);
40} 44}
41 45
42struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 46struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
@@ -201,15 +205,16 @@ int __perf_evsel__read(struct perf_evsel *evsel,
201} 205}
202 206
203static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 207static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
204 struct thread_map *threads, bool group) 208 struct thread_map *threads, bool group,
209 struct xyarray *group_fds)
205{ 210{
206 int cpu, thread; 211 int cpu, thread;
207 unsigned long flags = 0; 212 unsigned long flags = 0;
208 int pid = -1; 213 int pid = -1, err;
209 214
210 if (evsel->fd == NULL && 215 if (evsel->fd == NULL &&
211 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) 216 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
212 return -1; 217 return -ENOMEM;
213 218
214 if (evsel->cgrp) { 219 if (evsel->cgrp) {
215 flags = PERF_FLAG_PID_CGROUP; 220 flags = PERF_FLAG_PID_CGROUP;
@@ -217,7 +222,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
217 } 222 }
218 223
219 for (cpu = 0; cpu < cpus->nr; cpu++) { 224 for (cpu = 0; cpu < cpus->nr; cpu++) {
220 int group_fd = -1; 225 int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1;
221 226
222 for (thread = 0; thread < threads->nr; thread++) { 227 for (thread = 0; thread < threads->nr; thread++) {
223 228
@@ -228,8 +233,10 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
228 pid, 233 pid,
229 cpus->map[cpu], 234 cpus->map[cpu],
230 group_fd, flags); 235 group_fd, flags);
231 if (FD(evsel, cpu, thread) < 0) 236 if (FD(evsel, cpu, thread) < 0) {
237 err = -errno;
232 goto out_close; 238 goto out_close;
239 }
233 240
234 if (group && group_fd == -1) 241 if (group && group_fd == -1)
235 group_fd = FD(evsel, cpu, thread); 242 group_fd = FD(evsel, cpu, thread);
@@ -246,7 +253,17 @@ out_close:
246 } 253 }
247 thread = threads->nr; 254 thread = threads->nr;
248 } while (--cpu >= 0); 255 } while (--cpu >= 0);
249 return -1; 256 return err;
257}
258
259void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads)
260{
261 if (evsel->fd == NULL)
262 return;
263
264 perf_evsel__close_fd(evsel, ncpus, nthreads);
265 perf_evsel__free_fd(evsel);
266 evsel->fd = NULL;
250} 267}
251 268
252static struct { 269static struct {
@@ -266,7 +283,8 @@ static struct {
266}; 283};
267 284
268int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 285int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
269 struct thread_map *threads, bool group) 286 struct thread_map *threads, bool group,
287 struct xyarray *group_fd)
270{ 288{
271 if (cpus == NULL) { 289 if (cpus == NULL) {
272 /* Work around old compiler warnings about strict aliasing */ 290 /* Work around old compiler warnings about strict aliasing */
@@ -276,19 +294,23 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
276 if (threads == NULL) 294 if (threads == NULL)
277 threads = &empty_thread_map.map; 295 threads = &empty_thread_map.map;
278 296
279 return __perf_evsel__open(evsel, cpus, threads, group); 297 return __perf_evsel__open(evsel, cpus, threads, group, group_fd);
280} 298}
281 299
282int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 300int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
283 struct cpu_map *cpus, bool group) 301 struct cpu_map *cpus, bool group,
302 struct xyarray *group_fd)
284{ 303{
285 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group); 304 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group,
305 group_fd);
286} 306}
287 307
288int perf_evsel__open_per_thread(struct perf_evsel *evsel, 308int perf_evsel__open_per_thread(struct perf_evsel *evsel,
289 struct thread_map *threads, bool group) 309 struct thread_map *threads, bool group,
310 struct xyarray *group_fd)
290{ 311{
291 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group); 312 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group,
313 group_fd);
292} 314}
293 315
294static int perf_event__parse_id_sample(const union perf_event *event, u64 type, 316static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
@@ -342,10 +364,20 @@ static bool sample_overlap(const union perf_event *event,
342 364
343int perf_event__parse_sample(const union perf_event *event, u64 type, 365int perf_event__parse_sample(const union perf_event *event, u64 type,
344 int sample_size, bool sample_id_all, 366 int sample_size, bool sample_id_all,
345 struct perf_sample *data) 367 struct perf_sample *data, bool swapped)
346{ 368{
347 const u64 *array; 369 const u64 *array;
348 370
371 /*
372 * used for cross-endian analysis. See git commit 65014ab3
373 * for why this goofiness is needed.
374 */
375 union {
376 u64 val64;
377 u32 val32[2];
378 } u;
379
380
349 data->cpu = data->pid = data->tid = -1; 381 data->cpu = data->pid = data->tid = -1;
350 data->stream_id = data->id = data->time = -1ULL; 382 data->stream_id = data->id = data->time = -1ULL;
351 383
@@ -366,9 +398,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
366 } 398 }
367 399
368 if (type & PERF_SAMPLE_TID) { 400 if (type & PERF_SAMPLE_TID) {
369 u32 *p = (u32 *)array; 401 u.val64 = *array;
370 data->pid = p[0]; 402 if (swapped) {
371 data->tid = p[1]; 403 /* undo swap of u64, then swap on individual u32s */
404 u.val64 = bswap_64(u.val64);
405 u.val32[0] = bswap_32(u.val32[0]);
406 u.val32[1] = bswap_32(u.val32[1]);
407 }
408
409 data->pid = u.val32[0];
410 data->tid = u.val32[1];
372 array++; 411 array++;
373 } 412 }
374 413
@@ -395,8 +434,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
395 } 434 }
396 435
397 if (type & PERF_SAMPLE_CPU) { 436 if (type & PERF_SAMPLE_CPU) {
398 u32 *p = (u32 *)array; 437
399 data->cpu = *p; 438 u.val64 = *array;
439 if (swapped) {
440 /* undo swap of u64, then swap on individual u32s */
441 u.val64 = bswap_64(u.val64);
442 u.val32[0] = bswap_32(u.val32[0]);
443 }
444
445 data->cpu = u.val32[0];
400 array++; 446 array++;
401 } 447 }
402 448
@@ -423,18 +469,27 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
423 } 469 }
424 470
425 if (type & PERF_SAMPLE_RAW) { 471 if (type & PERF_SAMPLE_RAW) {
426 u32 *p = (u32 *)array; 472 const u64 *pdata;
473
474 u.val64 = *array;
475 if (WARN_ONCE(swapped,
476 "Endianness of raw data not corrected!\n")) {
477 /* undo swap of u64, then swap on individual u32s */
478 u.val64 = bswap_64(u.val64);
479 u.val32[0] = bswap_32(u.val32[0]);
480 u.val32[1] = bswap_32(u.val32[1]);
481 }
427 482
428 if (sample_overlap(event, array, sizeof(u32))) 483 if (sample_overlap(event, array, sizeof(u32)))
429 return -EFAULT; 484 return -EFAULT;
430 485
431 data->raw_size = *p; 486 data->raw_size = u.val32[0];
432 p++; 487 pdata = (void *) array + sizeof(u32);
433 488
434 if (sample_overlap(event, p, data->raw_size)) 489 if (sample_overlap(event, pdata, data->raw_size))
435 return -EFAULT; 490 return -EFAULT;
436 491
437 data->raw_data = p; 492 data->raw_data = (void *) pdata;
438 } 493 }
439 494
440 return 0; 495 return 0;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index e9a31554e265..b1d15e6f7ae3 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -82,11 +82,15 @@ void perf_evsel__free_id(struct perf_evsel *evsel);
82void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 82void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
83 83
84int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 84int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
85 struct cpu_map *cpus, bool group); 85 struct cpu_map *cpus, bool group,
86 struct xyarray *group_fds);
86int perf_evsel__open_per_thread(struct perf_evsel *evsel, 87int perf_evsel__open_per_thread(struct perf_evsel *evsel,
87 struct thread_map *threads, bool group); 88 struct thread_map *threads, bool group,
89 struct xyarray *group_fds);
88int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 90int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
89 struct thread_map *threads, bool group); 91 struct thread_map *threads, bool group,
92 struct xyarray *group_fds);
93void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
90 94
91#define perf_evsel__match(evsel, t, c) \ 95#define perf_evsel__match(evsel, t, c) \
92 (evsel->attr.type == PERF_TYPE_##t && \ 96 (evsel->attr.type == PERF_TYPE_##t && \
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b6c1ad123ca9..bcd05d05b4f0 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,5 +1,6 @@
1#define _FILE_OFFSET_BITS 64 1#define _FILE_OFFSET_BITS 64
2 2
3#include "util.h"
3#include <sys/types.h> 4#include <sys/types.h>
4#include <byteswap.h> 5#include <byteswap.h>
5#include <unistd.h> 6#include <unistd.h>
@@ -7,22 +8,29 @@
7#include <stdlib.h> 8#include <stdlib.h>
8#include <linux/list.h> 9#include <linux/list.h>
9#include <linux/kernel.h> 10#include <linux/kernel.h>
11#include <sys/utsname.h>
10 12
11#include "evlist.h" 13#include "evlist.h"
12#include "evsel.h" 14#include "evsel.h"
13#include "util.h"
14#include "header.h" 15#include "header.h"
15#include "../perf.h" 16#include "../perf.h"
16#include "trace-event.h" 17#include "trace-event.h"
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) \
@@ -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;
@@ -796,7 +1898,7 @@ out:
796 1898
797static int perf_file_section__process(struct perf_file_section *section, 1899static int perf_file_section__process(struct perf_file_section *section,
798 struct perf_header *ph, 1900 struct perf_header *ph,
799 int feat, int fd) 1901 int feat, int fd, void *data __used)
800{ 1902{
801 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { 1903 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
802 pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 1904 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
@@ -813,6 +1915,21 @@ static int perf_file_section__process(struct perf_file_section *section,
813 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))
814 pr_debug("Failed to read buildids, continuing...\n"); 1916 pr_debug("Failed to read buildids, continuing...\n");
815 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
816 default: 1933 default:
817 pr_debug("unknown feature %d, continuing...\n", feat); 1934 pr_debug("unknown feature %d, continuing...\n", feat);
818 } 1935 }
@@ -935,7 +2052,8 @@ int perf_session__read_header(struct perf_session *session, int fd)
935 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);
936 } 2053 }
937 2054
938 perf_header__process_sections(header, fd, perf_file_section__process); 2055 perf_header__process_sections(header, fd, NULL,
2056 perf_file_section__process);
939 2057
940 lseek(fd, header->data_offset, SEEK_SET); 2058 lseek(fd, header->data_offset, SEEK_SET);
941 2059
@@ -1100,15 +2218,29 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1100 struct perf_session *session __unused) 2218 struct perf_session *session __unused)
1101{ 2219{
1102 union perf_event ev; 2220 union perf_event ev;
2221 struct tracing_data *tdata;
1103 ssize_t size = 0, aligned_size = 0, padding; 2222 ssize_t size = 0, aligned_size = 0, padding;
1104 int err __used = 0; 2223 int err __used = 0;
1105 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
1106 memset(&ev, 0, sizeof(ev)); 2240 memset(&ev, 0, sizeof(ev));
1107 2241
1108 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 2242 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1109 size = read_tracing_data_size(fd, &evlist->entries); 2243 size = tdata->size;
1110 if (size <= 0)
1111 return size;
1112 aligned_size = ALIGN(size, sizeof(u64)); 2244 aligned_size = ALIGN(size, sizeof(u64));
1113 padding = aligned_size - size; 2245 padding = aligned_size - size;
1114 ev.tracing_data.header.size = sizeof(ev.tracing_data); 2246 ev.tracing_data.header.size = sizeof(ev.tracing_data);
@@ -1116,7 +2248,12 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1116 2248
1117 process(&ev, NULL, session); 2249 process(&ev, NULL, session);
1118 2250
1119 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
1120 write_padded(fd, NULL, 0, padding); 2257 write_padded(fd, NULL, 0, padding);
1121 2258
1122 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..a36a3fa81ffb 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,68 @@ 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;
274 hists__reset_col_len(self);
275 368
276 while (next) { 369 while (next) {
277 n = rb_entry(next, struct hist_entry, rb_node); 370 n = rb_entry(next, struct hist_entry, rb_node_in);
278 next = rb_next(&n->rb_node); 371 next = rb_next(&n->rb_node_in);
279 372
280 rb_erase(&n->rb_node, &self->entries); 373 rb_erase(&n->rb_node_in, root);
281 if (hists__collapse_insert_entry(self, &tmp, n)) 374 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) {
282 hists__inc_nr_entries(self, n); 375 /*
376 * If it wasn't combined with one of the entries already
377 * collapsed, we need to apply the filters that may have
378 * been set by, say, the hist_browser.
379 */
380 hists__apply_filters(hists, n);
381 }
283 } 382 }
383}
284 384
285 self->entries = tmp; 385void hists__collapse_resort(struct hists *hists)
386{
387 return __hists__collapse_resort(hists, false);
388}
389
390void hists__collapse_resort_threaded(struct hists *hists)
391{
392 return __hists__collapse_resort(hists, true);
286} 393}
287 394
288/* 395/*
@@ -315,31 +422,44 @@ static void __hists__insert_output_entry(struct rb_root *entries,
315 rb_insert_color(&he->rb_node, entries); 422 rb_insert_color(&he->rb_node, entries);
316} 423}
317 424
318void hists__output_resort(struct hists *self) 425static void __hists__output_resort(struct hists *hists, bool threaded)
319{ 426{
320 struct rb_root tmp; 427 struct rb_root *root;
321 struct rb_node *next; 428 struct rb_node *next;
322 struct hist_entry *n; 429 struct hist_entry *n;
323 u64 min_callchain_hits; 430 u64 min_callchain_hits;
324 431
325 min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100); 432 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
433
434 if (sort__need_collapse || threaded)
435 root = &hists->entries_collapsed;
436 else
437 root = hists->entries_in;
326 438
327 tmp = RB_ROOT; 439 next = rb_first(root);
328 next = rb_first(&self->entries); 440 hists->entries = RB_ROOT;
329 441
330 self->nr_entries = 0; 442 hists->nr_entries = 0;
331 hists__reset_col_len(self); 443 hists->stats.total_period = 0;
444 hists__reset_col_len(hists);
332 445
333 while (next) { 446 while (next) {
334 n = rb_entry(next, struct hist_entry, rb_node); 447 n = rb_entry(next, struct hist_entry, rb_node_in);
335 next = rb_next(&n->rb_node); 448 next = rb_next(&n->rb_node_in);
336 449
337 rb_erase(&n->rb_node, &self->entries); 450 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
338 __hists__insert_output_entry(&tmp, n, min_callchain_hits); 451 hists__inc_nr_entries(hists, n);
339 hists__inc_nr_entries(self, n);
340 } 452 }
453}
341 454
342 self->entries = tmp; 455void hists__output_resort(struct hists *hists)
456{
457 return __hists__output_resort(hists, false);
458}
459
460void hists__output_resort_threaded(struct hists *hists)
461{
462 return __hists__output_resort(hists, true);
343} 463}
344 464
345static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 465static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -594,12 +714,27 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
594 return ret; 714 return ret;
595} 715}
596 716
597int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, 717void hists__output_recalc_col_len(struct hists *hists, int max_rows)
598 struct hists *hists, struct hists *pair_hists, 718{
599 bool show_displacement, long displacement, 719 struct rb_node *next = rb_first(&hists->entries);
600 bool color, u64 session_total) 720 struct hist_entry *n;
721 int row = 0;
722
723 hists__reset_col_len(hists);
724
725 while (next && row++ < max_rows) {
726 n = rb_entry(next, struct hist_entry, rb_node);
727 if (!n->filtered)
728 hists__calc_col_len(hists, n);
729 next = rb_next(&n->rb_node);
730 }
731}
732
733static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s,
734 size_t size, struct hists *pair_hists,
735 bool show_displacement, long displacement,
736 bool color, u64 session_total)
601{ 737{
602 struct sort_entry *se;
603 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; 738 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
604 u64 nr_events; 739 u64 nr_events;
605 const char *sep = symbol_conf.field_sep; 740 const char *sep = symbol_conf.field_sep;
@@ -664,6 +799,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); 799 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
665 } 800 }
666 801
802 if (symbol_conf.show_total_period) {
803 if (sep)
804 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
805 else
806 ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
807 }
808
667 if (pair_hists) { 809 if (pair_hists) {
668 char bf[32]; 810 char bf[32];
669 double old_percent = 0, new_percent = 0, diff; 811 double old_percent = 0, new_percent = 0, diff;
@@ -698,26 +840,42 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
698 } 840 }
699 } 841 }
700 842
843 return ret;
844}
845
846int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
847 struct hists *hists)
848{
849 const char *sep = symbol_conf.field_sep;
850 struct sort_entry *se;
851 int ret = 0;
852
701 list_for_each_entry(se, &hist_entry__sort_list, list) { 853 list_for_each_entry(se, &hist_entry__sort_list, list) {
702 if (se->elide) 854 if (se->elide)
703 continue; 855 continue;
704 856
705 ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); 857 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
706 ret += se->se_snprintf(self, s + ret, size - ret, 858 ret += se->se_snprintf(he, s + ret, size - ret,
707 hists__col_len(hists, se->se_width_idx)); 859 hists__col_len(hists, se->se_width_idx));
708 } 860 }
709 861
710 return ret; 862 return ret;
711} 863}
712 864
713int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, 865int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
714 struct hists *pair_hists, bool show_displacement, 866 struct hists *pair_hists, bool show_displacement,
715 long displacement, FILE *fp, u64 session_total) 867 long displacement, FILE *fp, u64 session_total)
716{ 868{
717 char bf[512]; 869 char bf[512];
718 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists, 870 int ret;
719 show_displacement, displacement, 871
720 true, session_total); 872 if (size == 0 || size > sizeof(bf))
873 size = sizeof(bf);
874
875 ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists,
876 show_displacement, displacement,
877 true, session_total);
878 hist_entry__snprintf(he, bf + ret, size - ret, hists);
721 return fprintf(fp, "%s\n", bf); 879 return fprintf(fp, "%s\n", bf);
722} 880}
723 881
@@ -738,8 +896,9 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
738 left_margin); 896 left_margin);
739} 897}
740 898
741size_t hists__fprintf(struct hists *self, struct hists *pair, 899size_t hists__fprintf(struct hists *hists, struct hists *pair,
742 bool show_displacement, FILE *fp) 900 bool show_displacement, bool show_header, int max_rows,
901 int max_cols, FILE *fp)
743{ 902{
744 struct sort_entry *se; 903 struct sort_entry *se;
745 struct rb_node *nd; 904 struct rb_node *nd;
@@ -749,9 +908,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
749 unsigned int width; 908 unsigned int width;
750 const char *sep = symbol_conf.field_sep; 909 const char *sep = symbol_conf.field_sep;
751 const char *col_width = symbol_conf.col_width_list_str; 910 const char *col_width = symbol_conf.col_width_list_str;
911 int nr_rows = 0;
752 912
753 init_rem_hits(); 913 init_rem_hits();
754 914
915 if (!show_header)
916 goto print_entries;
917
755 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); 918 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
756 919
757 if (symbol_conf.show_nr_samples) { 920 if (symbol_conf.show_nr_samples) {
@@ -761,6 +924,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
761 fputs(" Samples ", fp); 924 fputs(" Samples ", fp);
762 } 925 }
763 926
927 if (symbol_conf.show_total_period) {
928 if (sep)
929 ret += fprintf(fp, "%cPeriod", *sep);
930 else
931 ret += fprintf(fp, " Period ");
932 }
933
764 if (symbol_conf.show_cpu_utilization) { 934 if (symbol_conf.show_cpu_utilization) {
765 if (sep) { 935 if (sep) {
766 ret += fprintf(fp, "%csys", *sep); 936 ret += fprintf(fp, "%csys", *sep);
@@ -803,18 +973,21 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
803 width = strlen(se->se_header); 973 width = strlen(se->se_header);
804 if (symbol_conf.col_width_list_str) { 974 if (symbol_conf.col_width_list_str) {
805 if (col_width) { 975 if (col_width) {
806 hists__set_col_len(self, se->se_width_idx, 976 hists__set_col_len(hists, se->se_width_idx,
807 atoi(col_width)); 977 atoi(col_width));
808 col_width = strchr(col_width, ','); 978 col_width = strchr(col_width, ',');
809 if (col_width) 979 if (col_width)
810 ++col_width; 980 ++col_width;
811 } 981 }
812 } 982 }
813 if (!hists__new_col_len(self, se->se_width_idx, width)) 983 if (!hists__new_col_len(hists, se->se_width_idx, width))
814 width = hists__col_len(self, se->se_width_idx); 984 width = hists__col_len(hists, se->se_width_idx);
815 fprintf(fp, " %*s", width, se->se_header); 985 fprintf(fp, " %*s", width, se->se_header);
816 } 986 }
987
817 fprintf(fp, "\n"); 988 fprintf(fp, "\n");
989 if (max_rows && ++nr_rows >= max_rows)
990 goto out;
818 991
819 if (sep) 992 if (sep)
820 goto print_entries; 993 goto print_entries;
@@ -822,6 +995,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
822 fprintf(fp, "# ........"); 995 fprintf(fp, "# ........");
823 if (symbol_conf.show_nr_samples) 996 if (symbol_conf.show_nr_samples)
824 fprintf(fp, " .........."); 997 fprintf(fp, " ..........");
998 if (symbol_conf.show_total_period)
999 fprintf(fp, " ............");
825 if (pair) { 1000 if (pair) {
826 fprintf(fp, " .........."); 1001 fprintf(fp, " ..........");
827 if (show_displacement) 1002 if (show_displacement)
@@ -834,17 +1009,23 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
834 continue; 1009 continue;
835 1010
836 fprintf(fp, " "); 1011 fprintf(fp, " ");
837 width = hists__col_len(self, se->se_width_idx); 1012 width = hists__col_len(hists, se->se_width_idx);
838 if (width == 0) 1013 if (width == 0)
839 width = strlen(se->se_header); 1014 width = strlen(se->se_header);
840 for (i = 0; i < width; i++) 1015 for (i = 0; i < width; i++)
841 fprintf(fp, "."); 1016 fprintf(fp, ".");
842 } 1017 }
843 1018
844 fprintf(fp, "\n#\n"); 1019 fprintf(fp, "\n");
1020 if (max_rows && ++nr_rows >= max_rows)
1021 goto out;
1022
1023 fprintf(fp, "#\n");
1024 if (max_rows && ++nr_rows >= max_rows)
1025 goto out;
845 1026
846print_entries: 1027print_entries:
847 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1028 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
848 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1029 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
849 1030
850 if (h->filtered) 1031 if (h->filtered)
@@ -858,19 +1039,22 @@ print_entries:
858 displacement = 0; 1039 displacement = 0;
859 ++position; 1040 ++position;
860 } 1041 }
861 ret += hist_entry__fprintf(h, self, pair, show_displacement, 1042 ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
862 displacement, fp, self->stats.total_period); 1043 displacement, fp, hists->stats.total_period);
863 1044
864 if (symbol_conf.use_callchain) 1045 if (symbol_conf.use_callchain)
865 ret += hist_entry__fprintf_callchain(h, self, fp, 1046 ret += hist_entry__fprintf_callchain(h, hists, fp,
866 self->stats.total_period); 1047 hists->stats.total_period);
1048 if (max_rows && ++nr_rows >= max_rows)
1049 goto out;
1050
867 if (h->ms.map == NULL && verbose > 1) { 1051 if (h->ms.map == NULL && verbose > 1) {
868 __map_groups__fprintf_maps(&h->thread->mg, 1052 __map_groups__fprintf_maps(&h->thread->mg,
869 MAP__FUNCTION, verbose, fp); 1053 MAP__FUNCTION, verbose, fp);
870 fprintf(fp, "%.10s end\n", graph_dotted_line); 1054 fprintf(fp, "%.10s end\n", graph_dotted_line);
871 } 1055 }
872 } 1056 }
873 1057out:
874 free(rem_sq_bracket); 1058 free(rem_sq_bracket);
875 1059
876 return ret; 1060 return ret;
@@ -879,7 +1063,7 @@ print_entries:
879/* 1063/*
880 * See hists__fprintf to match the column widths 1064 * See hists__fprintf to match the column widths
881 */ 1065 */
882unsigned int hists__sort_list_width(struct hists *self) 1066unsigned int hists__sort_list_width(struct hists *hists)
883{ 1067{
884 struct sort_entry *se; 1068 struct sort_entry *se;
885 int ret = 9; /* total % */ 1069 int ret = 9; /* total % */
@@ -896,9 +1080,12 @@ unsigned int hists__sort_list_width(struct hists *self)
896 if (symbol_conf.show_nr_samples) 1080 if (symbol_conf.show_nr_samples)
897 ret += 11; 1081 ret += 11;
898 1082
1083 if (symbol_conf.show_total_period)
1084 ret += 13;
1085
899 list_for_each_entry(se, &hist_entry__sort_list, list) 1086 list_for_each_entry(se, &hist_entry__sort_list, list)
900 if (!se->elide) 1087 if (!se->elide)
901 ret += 2 + hists__col_len(self, se->se_width_idx); 1088 ret += 2 + hists__col_len(hists, se->se_width_idx);
902 1089
903 if (verbose) /* Addr + origin */ 1090 if (verbose) /* Addr + origin */
904 ret += 3 + BITS_PER_LONG / 4; 1091 ret += 3 + BITS_PER_LONG / 4;
@@ -906,63 +1093,84 @@ unsigned int hists__sort_list_width(struct hists *self)
906 return ret; 1093 return ret;
907} 1094}
908 1095
909static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h, 1096static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
910 enum hist_filter filter) 1097 enum hist_filter filter)
911{ 1098{
912 h->filtered &= ~(1 << filter); 1099 h->filtered &= ~(1 << filter);
913 if (h->filtered) 1100 if (h->filtered)
914 return; 1101 return;
915 1102
916 ++self->nr_entries; 1103 ++hists->nr_entries;
917 if (h->ms.unfolded) 1104 if (h->ms.unfolded)
918 self->nr_entries += h->nr_rows; 1105 hists->nr_entries += h->nr_rows;
919 h->row_offset = 0; 1106 h->row_offset = 0;
920 self->stats.total_period += h->period; 1107 hists->stats.total_period += h->period;
921 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; 1108 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
922 1109
923 hists__calc_col_len(self, h); 1110 hists__calc_col_len(hists, h);
924} 1111}
925 1112
926void hists__filter_by_dso(struct hists *self, const struct dso *dso) 1113
1114static bool hists__filter_entry_by_dso(struct hists *hists,
1115 struct hist_entry *he)
1116{
1117 if (hists->dso_filter != NULL &&
1118 (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) {
1119 he->filtered |= (1 << HIST_FILTER__DSO);
1120 return true;
1121 }
1122
1123 return false;
1124}
1125
1126void hists__filter_by_dso(struct hists *hists)
927{ 1127{
928 struct rb_node *nd; 1128 struct rb_node *nd;
929 1129
930 self->nr_entries = self->stats.total_period = 0; 1130 hists->nr_entries = hists->stats.total_period = 0;
931 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1131 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
932 hists__reset_col_len(self); 1132 hists__reset_col_len(hists);
933 1133
934 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1134 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
935 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1135 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
936 1136
937 if (symbol_conf.exclude_other && !h->parent) 1137 if (symbol_conf.exclude_other && !h->parent)
938 continue; 1138 continue;
939 1139
940 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) { 1140 if (hists__filter_entry_by_dso(hists, h))
941 h->filtered |= (1 << HIST_FILTER__DSO);
942 continue; 1141 continue;
943 }
944 1142
945 hists__remove_entry_filter(self, h, HIST_FILTER__DSO); 1143 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
946 } 1144 }
947} 1145}
948 1146
949void hists__filter_by_thread(struct hists *self, const struct thread *thread) 1147static bool hists__filter_entry_by_thread(struct hists *hists,
1148 struct hist_entry *he)
1149{
1150 if (hists->thread_filter != NULL &&
1151 he->thread != hists->thread_filter) {
1152 he->filtered |= (1 << HIST_FILTER__THREAD);
1153 return true;
1154 }
1155
1156 return false;
1157}
1158
1159void hists__filter_by_thread(struct hists *hists)
950{ 1160{
951 struct rb_node *nd; 1161 struct rb_node *nd;
952 1162
953 self->nr_entries = self->stats.total_period = 0; 1163 hists->nr_entries = hists->stats.total_period = 0;
954 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1164 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
955 hists__reset_col_len(self); 1165 hists__reset_col_len(hists);
956 1166
957 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 1167 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
958 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1168 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
959 1169
960 if (thread != NULL && h->thread != thread) { 1170 if (hists__filter_entry_by_thread(hists, h))
961 h->filtered |= (1 << HIST_FILTER__THREAD);
962 continue; 1171 continue;
963 }
964 1172
965 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD); 1173 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
966 } 1174 }
967} 1175}
968 1176
@@ -976,13 +1184,13 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
976 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 1184 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
977} 1185}
978 1186
979void hists__inc_nr_events(struct hists *self, u32 type) 1187void hists__inc_nr_events(struct hists *hists, u32 type)
980{ 1188{
981 ++self->stats.nr_events[0]; 1189 ++hists->stats.nr_events[0];
982 ++self->stats.nr_events[type]; 1190 ++hists->stats.nr_events[type];
983} 1191}
984 1192
985size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) 1193size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
986{ 1194{
987 int i; 1195 int i;
988 size_t ret = 0; 1196 size_t ret = 0;
@@ -990,7 +1198,7 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
990 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 1198 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
991 const char *name; 1199 const char *name;
992 1200
993 if (self->stats.nr_events[i] == 0) 1201 if (hists->stats.nr_events[i] == 0)
994 continue; 1202 continue;
995 1203
996 name = perf_event__name(i); 1204 name = perf_event__name(i);
@@ -998,8 +1206,18 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
998 continue; 1206 continue;
999 1207
1000 ret += fprintf(fp, "%16s events: %10d\n", name, 1208 ret += fprintf(fp, "%16s events: %10d\n", name,
1001 self->stats.nr_events[i]); 1209 hists->stats.nr_events[i]);
1002 } 1210 }
1003 1211
1004 return ret; 1212 return ret;
1005} 1213}
1214
1215void hists__init(struct hists *hists)
1216{
1217 memset(hists, 0, sizeof(*hists));
1218 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1219 hists->entries_in = &hists->entries_in_array[0];
1220 hists->entries_collapsed = RB_ROOT;
1221 hists->entries = RB_ROOT;
1222 pthread_mutex_init(&hists->lock, NULL);
1223}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 3beb97c4d822..c86c1d27bd1e 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;
@@ -27,6 +28,7 @@ struct events_stats {
27 u64 total_lost; 28 u64 total_lost;
28 u64 total_invalid_chains; 29 u64 total_invalid_chains;
29 u32 nr_events[PERF_RECORD_HEADER_MAX]; 30 u32 nr_events[PERF_RECORD_HEADER_MAX];
31 u32 nr_lost_warned;
30 u32 nr_unknown_events; 32 u32 nr_unknown_events;
31 u32 nr_invalid_chains; 33 u32 nr_invalid_chains;
32 u32 nr_unknown_id; 34 u32 nr_unknown_id;
@@ -42,9 +44,18 @@ enum hist_column {
42 HISTC_NR_COLS, /* Last entry */ 44 HISTC_NR_COLS, /* Last entry */
43}; 45};
44 46
47struct thread;
48struct dso;
49
45struct hists { 50struct hists {
51 struct rb_root entries_in_array[2];
52 struct rb_root *entries_in;
46 struct rb_root entries; 53 struct rb_root entries;
54 struct rb_root entries_collapsed;
47 u64 nr_entries; 55 u64 nr_entries;
56 const struct thread *thread_filter;
57 const struct dso *dso_filter;
58 pthread_mutex_t lock;
48 struct events_stats stats; 59 struct events_stats stats;
49 u64 event_stream; 60 u64 event_stream;
50 u16 col_len[HISTC_NR_COLS]; 61 u16 col_len[HISTC_NR_COLS];
@@ -52,34 +63,42 @@ struct hists {
52 struct callchain_cursor callchain_cursor; 63 struct callchain_cursor callchain_cursor;
53}; 64};
54 65
66void hists__init(struct hists *hists);
67
55struct hist_entry *__hists__add_entry(struct hists *self, 68struct hist_entry *__hists__add_entry(struct hists *self,
56 struct addr_location *al, 69 struct addr_location *al,
57 struct symbol *parent, u64 period); 70 struct symbol *parent, u64 period);
58extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 71extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
59extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 72extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
60int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, 73int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
61 struct hists *pair_hists, bool show_displacement, 74 struct hists *pair_hists, bool show_displacement,
62 long displacement, FILE *fp, u64 total); 75 long displacement, FILE *fp, u64 session_total);
63int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, 76int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
64 struct hists *hists, struct hists *pair_hists, 77 struct hists *hists);
65 bool show_displacement, long displacement,
66 bool color, u64 total);
67void hist_entry__free(struct hist_entry *); 78void hist_entry__free(struct hist_entry *);
68 79
69void hists__output_resort(struct hists *self); 80void hists__output_resort(struct hists *self);
81void hists__output_resort_threaded(struct hists *hists);
70void hists__collapse_resort(struct hists *self); 82void hists__collapse_resort(struct hists *self);
83void hists__collapse_resort_threaded(struct hists *hists);
84
85void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
86void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
87 bool zap_kernel);
88void hists__output_recalc_col_len(struct hists *hists, int max_rows);
71 89
72void hists__inc_nr_events(struct hists *self, u32 type); 90void hists__inc_nr_events(struct hists *self, u32 type);
73size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 91size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
74 92
75size_t hists__fprintf(struct hists *self, struct hists *pair, 93size_t hists__fprintf(struct hists *self, struct hists *pair,
76 bool show_displacement, FILE *fp); 94 bool show_displacement, bool show_header,
95 int max_rows, int max_cols, FILE *fp);
77 96
78int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); 97int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
79int hist_entry__annotate(struct hist_entry *self, size_t privsize); 98int hist_entry__annotate(struct hist_entry *self, size_t privsize);
80 99
81void hists__filter_by_dso(struct hists *self, const struct dso *dso); 100void hists__filter_by_dso(struct hists *hists);
82void hists__filter_by_thread(struct hists *self, const struct thread *thread); 101void hists__filter_by_thread(struct hists *hists);
83 102
84u16 hists__col_len(struct hists *self, enum hist_column col); 103u16 hists__col_len(struct hists *self, enum hist_column col);
85void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 104void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
@@ -90,26 +109,33 @@ struct perf_evlist;
90#ifdef NO_NEWT_SUPPORT 109#ifdef NO_NEWT_SUPPORT
91static inline 110static inline
92int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, 111int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
93 const char *help __used) 112 const char *help __used,
113 void(*timer)(void *arg) __used,
114 void *arg __used,
115 int refresh __used)
94{ 116{
95 return 0; 117 return 0;
96} 118}
97 119
98static inline int hist_entry__tui_annotate(struct hist_entry *self __used, 120static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
99 int evidx __used) 121 int evidx __used,
122 int nr_events __used,
123 void(*timer)(void *arg) __used,
124 void *arg __used,
125 int delay_secs __used)
100{ 126{
101 return 0; 127 return 0;
102} 128}
103#define KEY_LEFT -1 129#define K_LEFT -1
104#define KEY_RIGHT -2 130#define K_RIGHT -2
105#else 131#else
106#include <newt.h> 132#include "ui/keysyms.h"
107int hist_entry__tui_annotate(struct hist_entry *self, int evidx); 133int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
108 134 void(*timer)(void *arg), void *arg, int delay_secs);
109#define KEY_LEFT NEWT_KEY_LEFT
110#define KEY_RIGHT NEWT_KEY_RIGHT
111 135
112int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help); 136int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
137 void(*timer)(void *arg), void *arg,
138 int refresh);
113#endif 139#endif
114 140
115unsigned int hists__sort_list_width(struct hists *self); 141unsigned int hists__sort_list_width(struct hists *self);
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/probe-event.c b/tools/perf/util/probe-event.c
index 1c7bfa5fe0a8..eb25900e2211 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1956,8 +1956,10 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
1956 1956
1957 pr_debug("Writing event: %s\n", buf); 1957 pr_debug("Writing event: %s\n", buf);
1958 ret = write(fd, buf, strlen(buf)); 1958 ret = write(fd, buf, strlen(buf));
1959 if (ret < 0) 1959 if (ret < 0) {
1960 ret = -errno;
1960 goto error; 1961 goto error;
1962 }
1961 1963
1962 printf("Remove event: %s\n", ent->s); 1964 printf("Remove event: %s\n", ent->s);
1963 return 0; 1965 return 0;
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 555fc3864b90..5d732621a462 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -659,7 +659,7 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
659 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 659 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
660 ret = -ENOENT; 660 ret = -ENOENT;
661 } 661 }
662 if (ret == 0) 662 if (ret >= 0)
663 ret = convert_variable(&vr_die, pf); 663 ret = convert_variable(&vr_die, pf);
664 664
665 if (ret < 0) 665 if (ret < 0)
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index cbc8f215d4b7..9dd47a4f2596 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -623,7 +623,11 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
623 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; 623 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
624 624
625 evsel->attr.inherit = inherit; 625 evsel->attr.inherit = inherit;
626 if (perf_evsel__open(evsel, cpus, threads, group) < 0) { 626 /*
627 * This will group just the fds for this single evsel, to group
628 * multiple events, use evlist.open().
629 */
630 if (perf_evsel__open(evsel, cpus, threads, group, NULL) < 0) {
627 PyErr_SetFromErrno(PyExc_OSError); 631 PyErr_SetFromErrno(PyExc_OSError);
628 return NULL; 632 return NULL;
629 } 633 }
@@ -803,7 +807,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
803 first = list_entry(evlist->entries.next, struct perf_evsel, node); 807 first = list_entry(evlist->entries.next, struct perf_evsel, node);
804 err = perf_event__parse_sample(event, first->attr.sample_type, 808 err = perf_event__parse_sample(event, first->attr.sample_type,
805 perf_evsel__sample_size(first), 809 perf_evsel__sample_size(first),
806 sample_id_all, &pevent->sample); 810 sample_id_all, &pevent->sample, false);
807 if (err) 811 if (err)
808 return PyErr_Format(PyExc_OSError, 812 return PyErr_Format(PyExc_OSError,
809 "perf: can't parse sample, err=%d", err); 813 "perf: can't parse sample, err=%d", err);
@@ -814,6 +818,25 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
814 return Py_None; 818 return Py_None;
815} 819}
816 820
821static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
822 PyObject *args, PyObject *kwargs)
823{
824 struct perf_evlist *evlist = &pevlist->evlist;
825 int group = 0;
826 static char *kwlist[] = { "group", NULL };
827
828 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, &group))
829 return NULL;
830
831 if (perf_evlist__open(evlist, group) < 0) {
832 PyErr_SetFromErrno(PyExc_OSError);
833 return NULL;
834 }
835
836 Py_INCREF(Py_None);
837 return Py_None;
838}
839
817static PyMethodDef pyrf_evlist__methods[] = { 840static PyMethodDef pyrf_evlist__methods[] = {
818 { 841 {
819 .ml_name = "mmap", 842 .ml_name = "mmap",
@@ -822,6 +845,12 @@ static PyMethodDef pyrf_evlist__methods[] = {
822 .ml_doc = PyDoc_STR("mmap the file descriptor table.") 845 .ml_doc = PyDoc_STR("mmap the file descriptor table.")
823 }, 846 },
824 { 847 {
848 .ml_name = "open",
849 .ml_meth = (PyCFunction)pyrf_evlist__open,
850 .ml_flags = METH_VARARGS | METH_KEYWORDS,
851 .ml_doc = PyDoc_STR("open the file descriptors.")
852 },
853 {
825 .ml_name = "poll", 854 .ml_name = "poll",
826 .ml_meth = (PyCFunction)pyrf_evlist__poll, 855 .ml_meth = (PyCFunction)pyrf_evlist__poll,
827 .ml_flags = METH_VARARGS | METH_KEYWORDS, 856 .ml_flags = METH_VARARGS | METH_KEYWORDS,
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 72458d9da5b1..85c1e6b76f0a 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -502,6 +502,7 @@ static void flush_sample_queue(struct perf_session *s,
502 struct perf_sample sample; 502 struct perf_sample sample;
503 u64 limit = os->next_flush; 503 u64 limit = os->next_flush;
504 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; 504 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
505 unsigned idx = 0, progress_next = os->nr_samples / 16;
505 int ret; 506 int ret;
506 507
507 if (!ops->ordered_samples || !limit) 508 if (!ops->ordered_samples || !limit)
@@ -521,6 +522,11 @@ static void flush_sample_queue(struct perf_session *s,
521 os->last_flush = iter->timestamp; 522 os->last_flush = iter->timestamp;
522 list_del(&iter->list); 523 list_del(&iter->list);
523 list_add(&iter->list, &os->sample_cache); 524 list_add(&iter->list, &os->sample_cache);
525 if (++idx >= progress_next) {
526 progress_next += os->nr_samples / 16;
527 ui_progress__update(idx, os->nr_samples,
528 "Processing time ordered events...");
529 }
524 } 530 }
525 531
526 if (list_empty(head)) { 532 if (list_empty(head)) {
@@ -529,6 +535,8 @@ static void flush_sample_queue(struct perf_session *s,
529 os->last_sample = 535 os->last_sample =
530 list_entry(head->prev, struct sample_queue, list); 536 list_entry(head->prev, struct sample_queue, list);
531 } 537 }
538
539 os->nr_samples = 0;
532} 540}
533 541
534/* 542/*
@@ -588,6 +596,7 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s)
588 u64 timestamp = new->timestamp; 596 u64 timestamp = new->timestamp;
589 struct list_head *p; 597 struct list_head *p;
590 598
599 ++os->nr_samples;
591 os->last_sample = new; 600 os->last_sample = new;
592 601
593 if (!sample) { 602 if (!sample) {
@@ -738,10 +747,27 @@ static int perf_session_deliver_event(struct perf_session *session,
738 747
739 dump_event(session, event, file_offset, sample); 748 dump_event(session, event, file_offset, sample);
740 749
750 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
751 if (evsel != NULL && event->header.type != PERF_RECORD_SAMPLE) {
752 /*
753 * XXX We're leaving PERF_RECORD_SAMPLE unnacounted here
754 * because the tools right now may apply filters, discarding
755 * some of the samples. For consistency, in the future we
756 * should have something like nr_filtered_samples and remove
757 * the sample->period from total_sample_period, etc, KISS for
758 * now tho.
759 *
760 * Also testing against NULL allows us to handle files without
761 * attr.sample_id_all and/or without PERF_SAMPLE_ID. In the
762 * future probably it'll be a good idea to restrict event
763 * processing via perf_session to files with both set.
764 */
765 hists__inc_nr_events(&evsel->hists, event->header.type);
766 }
767
741 switch (event->header.type) { 768 switch (event->header.type) {
742 case PERF_RECORD_SAMPLE: 769 case PERF_RECORD_SAMPLE:
743 dump_sample(session, event, sample); 770 dump_sample(session, event, sample);
744 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
745 if (evsel == NULL) { 771 if (evsel == NULL) {
746 ++session->hists.stats.nr_unknown_id; 772 ++session->hists.stats.nr_unknown_id;
747 return -1; 773 return -1;
@@ -874,11 +900,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
874 const struct perf_event_ops *ops) 900 const struct perf_event_ops *ops)
875{ 901{
876 if (ops->lost == perf_event__process_lost && 902 if (ops->lost == perf_event__process_lost &&
877 session->hists.stats.total_lost != 0) { 903 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) {
878 ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64 904 ui__warning("Processed %d events and lost %d chunks!\n\n"
879 "!\n\nCheck IO/CPU overload!\n\n", 905 "Check IO/CPU overload!\n\n",
880 session->hists.stats.total_period, 906 session->hists.stats.nr_events[0],
881 session->hists.stats.total_lost); 907 session->hists.stats.nr_events[PERF_RECORD_LOST]);
882 } 908 }
883 909
884 if (session->hists.stats.nr_unknown_events != 0) { 910 if (session->hists.stats.nr_unknown_events != 0) {
@@ -1012,7 +1038,6 @@ int __perf_session__process_events(struct perf_session *session,
1012{ 1038{
1013 u64 head, page_offset, file_offset, file_pos, progress_next; 1039 u64 head, page_offset, file_offset, file_pos, progress_next;
1014 int err, mmap_prot, mmap_flags, map_idx = 0; 1040 int err, mmap_prot, mmap_flags, map_idx = 0;
1015 struct ui_progress *progress;
1016 size_t page_size, mmap_size; 1041 size_t page_size, mmap_size;
1017 char *buf, *mmaps[8]; 1042 char *buf, *mmaps[8];
1018 union perf_event *event; 1043 union perf_event *event;
@@ -1030,9 +1055,6 @@ int __perf_session__process_events(struct perf_session *session,
1030 file_size = data_offset + data_size; 1055 file_size = data_offset + data_size;
1031 1056
1032 progress_next = file_size / 16; 1057 progress_next = file_size / 16;
1033 progress = ui_progress__new("Processing events...", file_size);
1034 if (progress == NULL)
1035 return -1;
1036 1058
1037 mmap_size = session->mmap_window; 1059 mmap_size = session->mmap_window;
1038 if (mmap_size > file_size) 1060 if (mmap_size > file_size)
@@ -1095,7 +1117,8 @@ more:
1095 1117
1096 if (file_pos >= progress_next) { 1118 if (file_pos >= progress_next) {
1097 progress_next += file_size / 16; 1119 progress_next += file_size / 16;
1098 ui_progress__update(progress, file_pos); 1120 ui_progress__update(file_pos, file_size,
1121 "Processing events...");
1099 } 1122 }
1100 1123
1101 if (file_pos < file_size) 1124 if (file_pos < file_size)
@@ -1106,7 +1129,6 @@ more:
1106 session->ordered_samples.next_flush = ULLONG_MAX; 1129 session->ordered_samples.next_flush = ULLONG_MAX;
1107 flush_sample_queue(session, ops); 1130 flush_sample_queue(session, ops);
1108out_err: 1131out_err:
1109 ui_progress__delete(progress);
1110 perf_session__warn_about_errors(session, ops); 1132 perf_session__warn_about_errors(session, ops);
1111 perf_session_free_sample_buffers(session); 1133 perf_session_free_sample_buffers(session);
1112 return err; 1134 return err;
@@ -1326,3 +1348,22 @@ int perf_session__cpu_bitmap(struct perf_session *session,
1326 1348
1327 return 0; 1349 return 0;
1328} 1350}
1351
1352void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
1353 bool full)
1354{
1355 struct stat st;
1356 int ret;
1357
1358 if (session == NULL || fp == NULL)
1359 return;
1360
1361 ret = fstat(session->fd, &st);
1362 if (ret == -1)
1363 return;
1364
1365 fprintf(fp, "# ========\n");
1366 fprintf(fp, "# captured on: %s", ctime(&st.st_ctime));
1367 perf_header__fprintf_info(session, fp, full);
1368 fprintf(fp, "# ========\n#\n");
1369}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 170601e67d6b..6e393c98eb34 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -23,6 +23,7 @@ struct ordered_samples {
23 struct sample_queue *sample_buffer; 23 struct sample_queue *sample_buffer;
24 struct sample_queue *last_sample; 24 struct sample_queue *last_sample;
25 int sample_buffer_idx; 25 int sample_buffer_idx;
26 unsigned int nr_samples;
26}; 27};
27 28
28struct perf_session { 29struct perf_session {
@@ -162,7 +163,8 @@ static inline int perf_session__parse_sample(struct perf_session *session,
162{ 163{
163 return perf_event__parse_sample(event, session->sample_type, 164 return perf_event__parse_sample(event, session->sample_type,
164 session->sample_size, 165 session->sample_size,
165 session->sample_id_all, sample); 166 session->sample_id_all, sample,
167 session->header.needs_swap);
166} 168}
167 169
168struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 170struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
@@ -176,4 +178,5 @@ void perf_session__print_ip(union perf_event *event,
176int perf_session__cpu_bitmap(struct perf_session *session, 178int perf_session__cpu_bitmap(struct perf_session *session,
177 const char *cpu_list, unsigned long *cpu_bitmap); 179 const char *cpu_list, unsigned long *cpu_bitmap);
178 180
181void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full);
179#endif /* __PERF_SESSION_H */ 182#endif /* __PERF_SESSION_H */
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 469c0264ed29..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;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 4f377d92e75a..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,
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..399650967958 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,20 @@ 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;
41 int print_entries, count_filter, delay_secs; 22 int print_entries, count_filter, delay_secs;
42 int display_weighted, freq, rb_entries; 23 int freq;
43 pid_t target_pid, target_tid; 24 pid_t target_pid, target_tid;
44 bool hide_kernel_symbols, hide_user_symbols, zero; 25 bool hide_kernel_symbols, hide_user_symbols, zero;
45 const char *cpu_list; 26 const char *cpu_list;
46 struct sym_entry *sym_filter_entry; 27 struct hist_entry *sym_filter_entry;
47 struct perf_evsel *sym_evsel; 28 struct perf_evsel *sym_evsel;
29 struct perf_session *session;
48}; 30};
49 31
50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 32size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
51void perf_top__reset_sample_counters(struct perf_top *top); 33void 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 */ 34#endif /* __PERF_TOP_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 3403f814ad72..d2655f08bcc0 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -80,7 +80,7 @@ static void die(const char *fmt, ...)
80 int ret = errno; 80 int ret = errno;
81 81
82 if (errno) 82 if (errno)
83 perror("trace-cmd"); 83 perror("perf");
84 else 84 else
85 ret = -1; 85 ret = -1;
86 86
@@ -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..556829124b02 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,5 +1,10 @@
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"
7#include "util.h"
3#include <linux/compiler.h> 8#include <linux/compiler.h>
4#include <linux/list.h> 9#include <linux/list.h>
5#include <linux/rbtree.h> 10#include <linux/rbtree.h>
@@ -7,13 +12,13 @@
7#include <sys/ttydefaults.h> 12#include <sys/ttydefaults.h>
8#include "browser.h" 13#include "browser.h"
9#include "helpline.h" 14#include "helpline.h"
15#include "keysyms.h"
10#include "../color.h" 16#include "../color.h"
11#include "../util.h"
12#include <stdio.h>
13 17
14static int ui_browser__percent_color(double percent, bool current) 18static int ui_browser__percent_color(struct ui_browser *browser,
19 double percent, bool current)
15{ 20{
16 if (current) 21 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
17 return HE_COLORSET_SELECTED; 22 return HE_COLORSET_SELECTED;
18 if (percent >= MIN_RED) 23 if (percent >= MIN_RED)
19 return HE_COLORSET_TOP; 24 return HE_COLORSET_TOP;
@@ -30,7 +35,7 @@ void ui_browser__set_color(struct ui_browser *self __used, int color)
30void ui_browser__set_percent_color(struct ui_browser *self, 35void ui_browser__set_percent_color(struct ui_browser *self,
31 double percent, bool current) 36 double percent, bool current)
32{ 37{
33 int color = ui_browser__percent_color(percent, current); 38 int color = ui_browser__percent_color(self, percent, current);
34 ui_browser__set_color(self, color); 39 ui_browser__set_color(self, color);
35} 40}
36 41
@@ -39,31 +44,62 @@ void ui_browser__gotorc(struct ui_browser *self, int y, int x)
39 SLsmg_gotorc(self->y + y, self->x + x); 44 SLsmg_gotorc(self->y + y, self->x + x);
40} 45}
41 46
47static struct list_head *
48ui_browser__list_head_filter_entries(struct ui_browser *browser,
49 struct list_head *pos)
50{
51 do {
52 if (!browser->filter || !browser->filter(browser, pos))
53 return pos;
54 pos = pos->next;
55 } while (pos != browser->entries);
56
57 return NULL;
58}
59
60static struct list_head *
61ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
62 struct list_head *pos)
63{
64 do {
65 if (!browser->filter || !browser->filter(browser, pos))
66 return pos;
67 pos = pos->prev;
68 } while (pos != browser->entries);
69
70 return NULL;
71}
72
42void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) 73void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
43{ 74{
44 struct list_head *head = self->entries; 75 struct list_head *head = self->entries;
45 struct list_head *pos; 76 struct list_head *pos;
46 77
78 if (self->nr_entries == 0)
79 return;
80
47 switch (whence) { 81 switch (whence) {
48 case SEEK_SET: 82 case SEEK_SET:
49 pos = head->next; 83 pos = ui_browser__list_head_filter_entries(self, head->next);
50 break; 84 break;
51 case SEEK_CUR: 85 case SEEK_CUR:
52 pos = self->top; 86 pos = self->top;
53 break; 87 break;
54 case SEEK_END: 88 case SEEK_END:
55 pos = head->prev; 89 pos = ui_browser__list_head_filter_prev_entries(self, head->prev);
56 break; 90 break;
57 default: 91 default:
58 return; 92 return;
59 } 93 }
60 94
95 assert(pos != NULL);
96
61 if (offset > 0) { 97 if (offset > 0) {
62 while (offset-- != 0) 98 while (offset-- != 0)
63 pos = pos->next; 99 pos = ui_browser__list_head_filter_entries(self, pos->next);
64 } else { 100 } else {
65 while (offset++ != 0) 101 while (offset++ != 0)
66 pos = pos->prev; 102 pos = ui_browser__list_head_filter_prev_entries(self, pos->prev);
67 } 103 }
68 104
69 self->top = pos; 105 self->top = pos;
@@ -127,41 +163,76 @@ bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
127 163
128void ui_browser__refresh_dimensions(struct ui_browser *self) 164void ui_browser__refresh_dimensions(struct ui_browser *self)
129{ 165{
130 int cols, rows; 166 self->width = SLtt_Screen_Cols - 1;
131 newtGetScreenSize(&cols, &rows); 167 self->height = SLtt_Screen_Rows - 2;
132
133 self->width = cols - 1;
134 self->height = rows - 2;
135 self->y = 1; 168 self->y = 1;
136 self->x = 0; 169 self->x = 0;
137} 170}
138 171
139void ui_browser__reset_index(struct ui_browser *self) 172void ui_browser__handle_resize(struct ui_browser *browser)
140{ 173{
141 self->index = self->top_idx = 0; 174 ui__refresh_dimensions(false);
142 self->seek(self, 0, SEEK_SET); 175 ui_browser__show(browser, browser->title, ui_helpline__current);
176 ui_browser__refresh(browser);
143} 177}
144 178
145void ui_browser__add_exit_key(struct ui_browser *self, int key) 179int ui_browser__warning(struct ui_browser *browser, int timeout,
180 const char *format, ...)
146{ 181{
147 newtFormAddHotKey(self->form, key); 182 va_list args;
183 char *text;
184 int key = 0, err;
185
186 va_start(args, format);
187 err = vasprintf(&text, format, args);
188 va_end(args);
189
190 if (err < 0) {
191 va_start(args, format);
192 ui_helpline__vpush(format, args);
193 va_end(args);
194 } else {
195 while ((key == ui__question_window("Warning!", text,
196 "Press any key...",
197 timeout)) == K_RESIZE)
198 ui_browser__handle_resize(browser);
199 free(text);
200 }
201
202 return key;
148} 203}
149 204
150void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]) 205int ui_browser__help_window(struct ui_browser *browser, const char *text)
151{ 206{
152 int i = 0; 207 int key;
153 208
154 while (keys[i] && i < 64) { 209 while ((key = ui__help_window(text)) == K_RESIZE)
155 ui_browser__add_exit_key(self, keys[i]); 210 ui_browser__handle_resize(browser);
156 ++i; 211
157 } 212 return key;
213}
214
215bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
216{
217 int key;
218
219 while ((key = ui__dialog_yesno(text)) == K_RESIZE)
220 ui_browser__handle_resize(browser);
221
222 return key == K_ENTER || toupper(key) == 'Y';
223}
224
225void ui_browser__reset_index(struct ui_browser *self)
226{
227 self->index = self->top_idx = 0;
228 self->seek(self, 0, SEEK_SET);
158} 229}
159 230
160void __ui_browser__show_title(struct ui_browser *browser, const char *title) 231void __ui_browser__show_title(struct ui_browser *browser, const char *title)
161{ 232{
162 SLsmg_gotorc(0, 0); 233 SLsmg_gotorc(0, 0);
163 ui_browser__set_color(browser, NEWT_COLORSET_ROOT); 234 ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
164 slsmg_write_nstring(title, browser->width); 235 slsmg_write_nstring(title, browser->width + 1);
165} 236}
166 237
167void ui_browser__show_title(struct ui_browser *browser, const char *title) 238void ui_browser__show_title(struct ui_browser *browser, const char *title)
@@ -174,78 +245,145 @@ void ui_browser__show_title(struct ui_browser *browser, const char *title)
174int ui_browser__show(struct ui_browser *self, const char *title, 245int ui_browser__show(struct ui_browser *self, const char *title,
175 const char *helpline, ...) 246 const char *helpline, ...)
176{ 247{
248 int err;
177 va_list ap; 249 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 250
185 ui_browser__refresh_dimensions(self); 251 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 252
196 pthread_mutex_lock(&ui__lock); 253 pthread_mutex_lock(&ui__lock);
197 __ui_browser__show_title(self, title); 254 __ui_browser__show_title(self, title);
198 255
199 ui_browser__add_exit_keys(self, keys); 256 self->title = title;
200 newtFormAddComponent(self->form, self->sb); 257 free(self->helpline);
258 self->helpline = NULL;
201 259
202 va_start(ap, helpline); 260 va_start(ap, helpline);
203 ui_helpline__vpush(helpline, ap); 261 err = vasprintf(&self->helpline, helpline, ap);
204 va_end(ap); 262 va_end(ap);
263 if (err > 0)
264 ui_helpline__push(self->helpline);
205 pthread_mutex_unlock(&ui__lock); 265 pthread_mutex_unlock(&ui__lock);
206 return 0; 266 return err ? 0 : -1;
207} 267}
208 268
209void ui_browser__hide(struct ui_browser *self) 269void ui_browser__hide(struct ui_browser *browser __used)
210{ 270{
211 pthread_mutex_lock(&ui__lock); 271 pthread_mutex_lock(&ui__lock);
212 newtFormDestroy(self->form);
213 self->form = NULL;
214 ui_helpline__pop(); 272 ui_helpline__pop();
215 pthread_mutex_unlock(&ui__lock); 273 pthread_mutex_unlock(&ui__lock);
216} 274}
217 275
218int ui_browser__refresh(struct ui_browser *self) 276static void ui_browser__scrollbar_set(struct ui_browser *browser)
277{
278 int height = browser->height, h = 0, pct = 0,
279 col = browser->width,
280 row = browser->y - 1;
281
282 if (browser->nr_entries > 1) {
283 pct = ((browser->index * (browser->height - 1)) /
284 (browser->nr_entries - 1));
285 }
286
287 SLsmg_set_char_set(1);
288
289 while (h < height) {
290 ui_browser__gotorc(browser, row++, col);
291 SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
292 ++h;
293 }
294
295 SLsmg_set_char_set(0);
296}
297
298static int __ui_browser__refresh(struct ui_browser *browser)
219{ 299{
220 int row; 300 int row;
301 int width = browser->width;
302
303 row = browser->refresh(browser);
304 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
305
306 if (!browser->use_navkeypressed || browser->navkeypressed)
307 ui_browser__scrollbar_set(browser);
308 else
309 width += 1;
310
311 SLsmg_fill_region(browser->y + row, browser->x,
312 browser->height - row, width, ' ');
313
314 return 0;
315}
221 316
317int ui_browser__refresh(struct ui_browser *browser)
318{
222 pthread_mutex_lock(&ui__lock); 319 pthread_mutex_lock(&ui__lock);
223 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); 320 __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); 321 pthread_mutex_unlock(&ui__lock);
229 322
230 return 0; 323 return 0;
231} 324}
232 325
233int ui_browser__run(struct ui_browser *self) 326/*
327 * Here we're updating nr_entries _after_ we started browsing, i.e. we have to
328 * forget about any reference to any entry in the underlying data structure,
329 * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
330 * after an output_resort and hist decay.
331 */
332void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
234{ 333{
235 struct newtExitStruct es; 334 off_t offset = nr_entries - browser->nr_entries;
335
336 browser->nr_entries = nr_entries;
236 337
237 if (ui_browser__refresh(self) < 0) 338 if (offset < 0) {
238 return -1; 339 if (browser->top_idx < (u64)-offset)
340 offset = -browser->top_idx;
341
342 browser->index += offset;
343 browser->top_idx += offset;
344 }
345
346 browser->top = NULL;
347 browser->seek(browser, browser->top_idx, SEEK_SET);
348}
349
350int ui_browser__run(struct ui_browser *self, int delay_secs)
351{
352 int err, key;
239 353
240 while (1) { 354 while (1) {
241 off_t offset; 355 off_t offset;
242 356
243 newtFormRun(self->form, &es); 357 pthread_mutex_lock(&ui__lock);
244 358 err = __ui_browser__refresh(self);
245 if (es.reason != NEWT_EXIT_HOTKEY) 359 SLsmg_refresh();
360 pthread_mutex_unlock(&ui__lock);
361 if (err < 0)
246 break; 362 break;
247 switch (es.u.key) { 363
248 case NEWT_KEY_DOWN: 364 key = ui__getch(delay_secs);
365
366 if (key == K_RESIZE) {
367 ui__refresh_dimensions(false);
368 ui_browser__refresh_dimensions(self);
369 __ui_browser__show_title(self, self->title);
370 ui_helpline__puts(self->helpline);
371 continue;
372 }
373
374 if (self->use_navkeypressed && !self->navkeypressed) {
375 if (key == K_DOWN || key == K_UP ||
376 key == K_PGDN || key == K_PGUP ||
377 key == K_HOME || key == K_END ||
378 key == ' ') {
379 self->navkeypressed = true;
380 continue;
381 } else
382 return key;
383 }
384
385 switch (key) {
386 case K_DOWN:
249 if (self->index == self->nr_entries - 1) 387 if (self->index == self->nr_entries - 1)
250 break; 388 break;
251 ++self->index; 389 ++self->index;
@@ -254,7 +392,7 @@ int ui_browser__run(struct ui_browser *self)
254 self->seek(self, +1, SEEK_CUR); 392 self->seek(self, +1, SEEK_CUR);
255 } 393 }
256 break; 394 break;
257 case NEWT_KEY_UP: 395 case K_UP:
258 if (self->index == 0) 396 if (self->index == 0)
259 break; 397 break;
260 --self->index; 398 --self->index;
@@ -263,7 +401,7 @@ int ui_browser__run(struct ui_browser *self)
263 self->seek(self, -1, SEEK_CUR); 401 self->seek(self, -1, SEEK_CUR);
264 } 402 }
265 break; 403 break;
266 case NEWT_KEY_PGDN: 404 case K_PGDN:
267 case ' ': 405 case ' ':
268 if (self->top_idx + self->height > self->nr_entries - 1) 406 if (self->top_idx + self->height > self->nr_entries - 1)
269 break; 407 break;
@@ -275,7 +413,7 @@ int ui_browser__run(struct ui_browser *self)
275 self->top_idx += offset; 413 self->top_idx += offset;
276 self->seek(self, +offset, SEEK_CUR); 414 self->seek(self, +offset, SEEK_CUR);
277 break; 415 break;
278 case NEWT_KEY_PGUP: 416 case K_PGUP:
279 if (self->top_idx == 0) 417 if (self->top_idx == 0)
280 break; 418 break;
281 419
@@ -288,10 +426,10 @@ int ui_browser__run(struct ui_browser *self)
288 self->top_idx -= offset; 426 self->top_idx -= offset;
289 self->seek(self, -offset, SEEK_CUR); 427 self->seek(self, -offset, SEEK_CUR);
290 break; 428 break;
291 case NEWT_KEY_HOME: 429 case K_HOME:
292 ui_browser__reset_index(self); 430 ui_browser__reset_index(self);
293 break; 431 break;
294 case NEWT_KEY_END: 432 case K_END:
295 offset = self->height - 1; 433 offset = self->height - 1;
296 if (offset >= self->nr_entries) 434 if (offset >= self->nr_entries)
297 offset = self->nr_entries - 1; 435 offset = self->nr_entries - 1;
@@ -301,10 +439,8 @@ int ui_browser__run(struct ui_browser *self)
301 self->seek(self, -offset, SEEK_END); 439 self->seek(self, -offset, SEEK_END);
302 break; 440 break;
303 default: 441 default:
304 return es.u.key; 442 return key;
305 } 443 }
306 if (ui_browser__refresh(self) < 0)
307 return -1;
308 } 444 }
309 return -1; 445 return -1;
310} 446}
@@ -316,41 +452,146 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
316 int row = 0; 452 int row = 0;
317 453
318 if (self->top == NULL || self->top == self->entries) 454 if (self->top == NULL || self->top == self->entries)
319 self->top = head->next; 455 self->top = ui_browser__list_head_filter_entries(self, head->next);
320 456
321 pos = self->top; 457 pos = self->top;
322 458
323 list_for_each_from(pos, head) { 459 list_for_each_from(pos, head) {
324 ui_browser__gotorc(self, row, 0); 460 if (!self->filter || !self->filter(self, pos)) {
325 self->write(self, pos, row); 461 ui_browser__gotorc(self, row, 0);
326 if (++row == self->height) 462 self->write(self, pos, row);
327 break; 463 if (++row == self->height)
464 break;
465 }
328 } 466 }
329 467
330 return row; 468 return row;
331} 469}
332 470
333static struct newtPercentTreeColors { 471static struct ui_browser__colorset {
334 const char *topColorFg, *topColorBg; 472 const char *name, *fg, *bg;
335 const char *mediumColorFg, *mediumColorBg; 473 int colorset;
336 const char *normalColorFg, *normalColorBg; 474} ui_browser__colorsets[] = {
337 const char *selColorFg, *selColorBg; 475 {
338 const char *codeColorFg, *codeColorBg; 476 .colorset = HE_COLORSET_TOP,
339} defaultPercentTreeColors = { 477 .name = "top",
340 "red", "lightgray", 478 .fg = "red",
341 "green", "lightgray", 479 .bg = "default",
342 "black", "lightgray", 480 },
343 "lightgray", "magenta", 481 {
344 "blue", "lightgray", 482 .colorset = HE_COLORSET_MEDIUM,
483 .name = "medium",
484 .fg = "green",
485 .bg = "default",
486 },
487 {
488 .colorset = HE_COLORSET_NORMAL,
489 .name = "normal",
490 .fg = "default",
491 .bg = "default",
492 },
493 {
494 .colorset = HE_COLORSET_SELECTED,
495 .name = "selected",
496 .fg = "black",
497 .bg = "lightgray",
498 },
499 {
500 .colorset = HE_COLORSET_CODE,
501 .name = "code",
502 .fg = "blue",
503 .bg = "default",
504 },
505 {
506 .name = NULL,
507 }
345}; 508};
346 509
510
511static int ui_browser__color_config(const char *var, const char *value,
512 void *data __used)
513{
514 char *fg = NULL, *bg;
515 int i;
516
517 /* same dir for all commands */
518 if (prefixcmp(var, "colors.") != 0)
519 return 0;
520
521 for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
522 const char *name = var + 7;
523
524 if (strcmp(ui_browser__colorsets[i].name, name) != 0)
525 continue;
526
527 fg = strdup(value);
528 if (fg == NULL)
529 break;
530
531 bg = strchr(fg, ',');
532 if (bg == NULL)
533 break;
534
535 *bg = '\0';
536 while (isspace(*++bg));
537 ui_browser__colorsets[i].bg = bg;
538 ui_browser__colorsets[i].fg = fg;
539 return 0;
540 }
541
542 free(fg);
543 return -1;
544}
545
546void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
547{
548 switch (whence) {
549 case SEEK_SET:
550 browser->top = browser->entries;
551 break;
552 case SEEK_CUR:
553 browser->top = browser->top + browser->top_idx + offset;
554 break;
555 case SEEK_END:
556 browser->top = browser->top + browser->nr_entries + offset;
557 break;
558 default:
559 return;
560 }
561}
562
563unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
564{
565 unsigned int row = 0, idx = browser->top_idx;
566 char **pos;
567
568 if (browser->top == NULL)
569 browser->top = browser->entries;
570
571 pos = (char **)browser->top;
572 while (idx < browser->nr_entries) {
573 if (!browser->filter || !browser->filter(browser, *pos)) {
574 ui_browser__gotorc(browser, row, 0);
575 browser->write(browser, pos, row);
576 if (++row == browser->height)
577 break;
578 }
579
580 ++idx;
581 ++pos;
582 }
583
584 return row;
585}
586
347void ui_browser__init(void) 587void ui_browser__init(void)
348{ 588{
349 struct newtPercentTreeColors *c = &defaultPercentTreeColors; 589 int i = 0;
590
591 perf_config(ui_browser__color_config, NULL);
350 592
351 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); 593 while (ui_browser__colorsets[i].name) {
352 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); 594 struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
353 sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg); 595 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
354 sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg); 596 }
355 sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg);
356} 597}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index fc63dda10910..84d761b730c1 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,23 @@ 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);
46void ui_browser__handle_resize(struct ui_browser *browser);
47
48int ui_browser__warning(struct ui_browser *browser, int timeout,
49 const char *format, ...);
50int ui_browser__help_window(struct ui_browser *browser, const char *text);
51bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
52
53void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
54unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
44 55
45void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); 56void 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); 57unsigned 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..0575905d1205 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -1,31 +1,31 @@
1#include "../../util.h"
1#include "../browser.h" 2#include "../browser.h"
2#include "../helpline.h" 3#include "../helpline.h"
3#include "../libslang.h" 4#include "../libslang.h"
5#include "../ui.h"
6#include "../util.h"
4#include "../../annotate.h" 7#include "../../annotate.h"
5#include "../../hist.h" 8#include "../../hist.h"
6#include "../../sort.h" 9#include "../../sort.h"
7#include "../../symbol.h" 10#include "../../symbol.h"
8#include <pthread.h> 11#include <pthread.h>
9 12#include <newt.h>
10static void ui__error_window(const char *fmt, ...)
11{
12 va_list ap;
13
14 va_start(ap, fmt);
15 newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap);
16 va_end(ap);
17}
18 13
19struct annotate_browser { 14struct annotate_browser {
20 struct ui_browser b; 15 struct ui_browser b;
21 struct rb_root entries; 16 struct rb_root entries;
22 struct rb_node *curr_hot; 17 struct rb_node *curr_hot;
18 struct objdump_line *selection;
19 int nr_asm_entries;
20 int nr_entries;
21 bool hide_src_code;
23}; 22};
24 23
25struct objdump_line_rb_node { 24struct objdump_line_rb_node {
26 struct rb_node rb_node; 25 struct rb_node rb_node;
27 double percent; 26 double percent;
28 u32 idx; 27 u32 idx;
28 int idx_asm;
29}; 29};
30 30
31static inline 31static inline
@@ -34,9 +34,22 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
34 return (struct objdump_line_rb_node *)(self + 1); 34 return (struct objdump_line_rb_node *)(self + 1);
35} 35}
36 36
37static bool objdump_line__filter(struct ui_browser *browser, void *entry)
38{
39 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
40
41 if (ab->hide_src_code) {
42 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
43 return ol->offset == -1;
44 }
45
46 return false;
47}
48
37static void annotate_browser__write(struct ui_browser *self, void *entry, int row) 49static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
38{ 50{
39 struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); 51 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
52 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
40 bool current_entry = ui_browser__is_current_entry(self, row); 53 bool current_entry = ui_browser__is_current_entry(self, row);
41 int width = self->width; 54 int width = self->width;
42 55
@@ -51,6 +64,11 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
51 64
52 SLsmg_write_char(':'); 65 SLsmg_write_char(':');
53 slsmg_write_nstring(" ", 8); 66 slsmg_write_nstring(" ", 8);
67
68 /* The scroll bar isn't being used */
69 if (!self->navkeypressed)
70 width += 1;
71
54 if (!*ol->line) 72 if (!*ol->line)
55 slsmg_write_nstring(" ", width - 18); 73 slsmg_write_nstring(" ", width - 18);
56 else 74 else
@@ -58,6 +76,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
58 76
59 if (!current_entry) 77 if (!current_entry)
60 ui_browser__set_color(self, HE_COLORSET_CODE); 78 ui_browser__set_color(self, HE_COLORSET_CODE);
79 else
80 ab->selection = ol;
61} 81}
62 82
63static double objdump_line__calc_percent(struct objdump_line *self, 83static double objdump_line__calc_percent(struct objdump_line *self,
@@ -141,7 +161,8 @@ static void annotate_browser__set_top(struct annotate_browser *self,
141static void annotate_browser__calc_percent(struct annotate_browser *browser, 161static void annotate_browser__calc_percent(struct annotate_browser *browser,
142 int evidx) 162 int evidx)
143{ 163{
144 struct symbol *sym = browser->b.priv; 164 struct map_symbol *ms = browser->b.priv;
165 struct symbol *sym = ms->sym;
145 struct annotation *notes = symbol__annotation(sym); 166 struct annotation *notes = symbol__annotation(sym);
146 struct objdump_line *pos; 167 struct objdump_line *pos;
147 168
@@ -163,25 +184,60 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
163 browser->curr_hot = rb_last(&browser->entries); 184 browser->curr_hot = rb_last(&browser->entries);
164} 185}
165 186
187static bool annotate_browser__toggle_source(struct annotate_browser *browser)
188{
189 struct objdump_line *ol;
190 struct objdump_line_rb_node *olrb;
191 off_t offset = browser->b.index - browser->b.top_idx;
192
193 browser->b.seek(&browser->b, offset, SEEK_CUR);
194 ol = list_entry(browser->b.top, struct objdump_line, node);
195 olrb = objdump_line__rb(ol);
196
197 if (browser->hide_src_code) {
198 if (olrb->idx_asm < offset)
199 offset = olrb->idx;
200
201 browser->b.nr_entries = browser->nr_entries;
202 browser->hide_src_code = false;
203 browser->b.seek(&browser->b, -offset, SEEK_CUR);
204 browser->b.top_idx = olrb->idx - offset;
205 browser->b.index = olrb->idx;
206 } else {
207 if (olrb->idx_asm < 0) {
208 ui_helpline__puts("Only available for assembly lines.");
209 browser->b.seek(&browser->b, -offset, SEEK_CUR);
210 return false;
211 }
212
213 if (olrb->idx_asm < offset)
214 offset = olrb->idx_asm;
215
216 browser->b.nr_entries = browser->nr_asm_entries;
217 browser->hide_src_code = true;
218 browser->b.seek(&browser->b, -offset, SEEK_CUR);
219 browser->b.top_idx = olrb->idx_asm - offset;
220 browser->b.index = olrb->idx_asm;
221 }
222
223 return true;
224}
225
166static int annotate_browser__run(struct annotate_browser *self, int evidx, 226static int annotate_browser__run(struct annotate_browser *self, int evidx,
167 int refresh) 227 int nr_events, void(*timer)(void *arg),
228 void *arg, int delay_secs)
168{ 229{
169 struct rb_node *nd = NULL; 230 struct rb_node *nd = NULL;
170 struct symbol *sym = self->b.priv; 231 struct map_symbol *ms = self->b.priv;
171 /* 232 struct symbol *sym = ms->sym;
172 * RIGHT To allow builtin-annotate to cycle thru multiple symbols by 233 const char *help = "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, "
173 * examining the exit key for this function. 234 "H: Hottest, -> Line action, S -> Toggle source "
174 */ 235 "code view";
175 int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
176 NEWT_KEY_RIGHT, 0 };
177 int key; 236 int key;
178 237
179 if (ui_browser__show(&self->b, sym->name, 238 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; 239 return -1;
183 240
184 ui_browser__add_exit_keys(&self->b, exit_keys);
185 annotate_browser__calc_percent(self, evidx); 241 annotate_browser__calc_percent(self, evidx);
186 242
187 if (self->curr_hot) 243 if (self->curr_hot)
@@ -189,13 +245,10 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
189 245
190 nd = self->curr_hot; 246 nd = self->curr_hot;
191 247
192 if (refresh != 0)
193 newtFormSetTimer(self->b.form, refresh);
194
195 while (1) { 248 while (1) {
196 key = ui_browser__run(&self->b); 249 key = ui_browser__run(&self->b, delay_secs);
197 250
198 if (refresh != 0) { 251 if (delay_secs != 0) {
199 annotate_browser__calc_percent(self, evidx); 252 annotate_browser__calc_percent(self, evidx);
200 /* 253 /*
201 * Current line focus got out of the list of most active 254 * Current line focus got out of the list of most active
@@ -207,15 +260,14 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
207 } 260 }
208 261
209 switch (key) { 262 switch (key) {
210 case -1: 263 case K_TIMER:
211 /* 264 if (timer != NULL)
212 * FIXME we need to check if it was 265 timer(arg);
213 * es.reason == NEWT_EXIT_TIMER 266
214 */ 267 if (delay_secs != 0)
215 if (refresh != 0)
216 symbol__annotate_decay_histogram(sym, evidx); 268 symbol__annotate_decay_histogram(sym, evidx);
217 continue; 269 continue;
218 case NEWT_KEY_TAB: 270 case K_TAB:
219 if (nd != NULL) { 271 if (nd != NULL) {
220 nd = rb_prev(nd); 272 nd = rb_prev(nd);
221 if (nd == NULL) 273 if (nd == NULL)
@@ -223,7 +275,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
223 } else 275 } else
224 nd = self->curr_hot; 276 nd = self->curr_hot;
225 break; 277 break;
226 case NEWT_KEY_UNTAB: 278 case K_UNTAB:
227 if (nd != NULL) 279 if (nd != NULL)
228 nd = rb_next(nd); 280 nd = rb_next(nd);
229 if (nd == NULL) 281 if (nd == NULL)
@@ -234,8 +286,68 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
234 case 'H': 286 case 'H':
235 nd = self->curr_hot; 287 nd = self->curr_hot;
236 break; 288 break;
237 default: 289 case 'S':
290 if (annotate_browser__toggle_source(self))
291 ui_helpline__puts(help);
292 continue;
293 case K_ENTER:
294 case K_RIGHT:
295 if (self->selection == NULL) {
296 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
297 continue;
298 }
299
300 if (self->selection->offset == -1) {
301 ui_helpline__puts("Actions are only available for assembly lines.");
302 continue;
303 } else {
304 char *s = strstr(self->selection->line, "callq ");
305 struct annotation *notes;
306 struct symbol *target;
307 u64 ip;
308
309 if (s == NULL) {
310 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
311 continue;
312 }
313
314 s = strchr(s, ' ');
315 if (s++ == NULL) {
316 ui_helpline__puts("Invallid callq instruction.");
317 continue;
318 }
319
320 ip = strtoull(s, NULL, 16);
321 ip = ms->map->map_ip(ms->map, ip);
322 target = map__find_symbol(ms->map, ip, NULL);
323 if (target == NULL) {
324 ui_helpline__puts("The called function was not found.");
325 continue;
326 }
327
328 notes = symbol__annotation(target);
329 pthread_mutex_lock(&notes->lock);
330
331 if (notes->src == NULL &&
332 symbol__alloc_hist(target, nr_events) < 0) {
333 pthread_mutex_unlock(&notes->lock);
334 ui__warning("Not enough memory for annotating '%s' symbol!\n",
335 target->name);
336 continue;
337 }
338
339 pthread_mutex_unlock(&notes->lock);
340 symbol__tui_annotate(target, ms->map, evidx, nr_events,
341 timer, arg, delay_secs);
342 }
343 continue;
344 case K_LEFT:
345 case K_ESC:
346 case 'q':
347 case CTRL('c'):
238 goto out; 348 goto out;
349 default:
350 continue;
239 } 351 }
240 352
241 if (nd != NULL) 353 if (nd != NULL)
@@ -246,22 +358,31 @@ out:
246 return key; 358 return key;
247} 359}
248 360
249int hist_entry__tui_annotate(struct hist_entry *he, int evidx) 361int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
362 void(*timer)(void *arg), void *arg, int delay_secs)
250{ 363{
251 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0); 364 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events,
365 timer, arg, delay_secs);
252} 366}
253 367
254int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 368int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
255 int refresh) 369 int nr_events, void(*timer)(void *arg), void *arg,
370 int delay_secs)
256{ 371{
257 struct objdump_line *pos, *n; 372 struct objdump_line *pos, *n;
258 struct annotation *notes; 373 struct annotation *notes;
374 struct map_symbol ms = {
375 .map = map,
376 .sym = sym,
377 };
259 struct annotate_browser browser = { 378 struct annotate_browser browser = {
260 .b = { 379 .b = {
261 .refresh = ui_browser__list_head_refresh, 380 .refresh = ui_browser__list_head_refresh,
262 .seek = ui_browser__list_head_seek, 381 .seek = ui_browser__list_head_seek,
263 .write = annotate_browser__write, 382 .write = annotate_browser__write,
264 .priv = sym, 383 .filter = objdump_line__filter,
384 .priv = &ms,
385 .use_navkeypressed = true,
265 }, 386 },
266 }; 387 };
267 int ret; 388 int ret;
@@ -273,7 +394,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
273 return -1; 394 return -1;
274 395
275 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { 396 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
276 ui__error_window(ui_helpline__last_msg); 397 ui__error("%s", ui_helpline__last_msg);
277 return -1; 398 return -1;
278 } 399 }
279 400
@@ -288,12 +409,18 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
288 if (browser.b.width < line_len) 409 if (browser.b.width < line_len)
289 browser.b.width = line_len; 410 browser.b.width = line_len;
290 rbpos = objdump_line__rb(pos); 411 rbpos = objdump_line__rb(pos);
291 rbpos->idx = browser.b.nr_entries++; 412 rbpos->idx = browser.nr_entries++;
413 if (pos->offset != -1)
414 rbpos->idx_asm = browser.nr_asm_entries++;
415 else
416 rbpos->idx_asm = -1;
292 } 417 }
293 418
419 browser.b.nr_entries = browser.nr_entries;
294 browser.b.entries = &notes->src->source, 420 browser.b.entries = &notes->src->source,
295 browser.b.width += 18; /* Percentage */ 421 browser.b.width += 18; /* Percentage */
296 ret = annotate_browser__run(&browser, evidx, refresh); 422 ret = annotate_browser__run(&browser, evidx, nr_events,
423 timer, arg, delay_secs);
297 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 424 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
298 list_del(&pos->node); 425 list_del(&pos->node);
299 objdump_line__free(pos); 426 objdump_line__free(pos);
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 5d767c622dfc..d0c94b459685 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -17,6 +17,7 @@
17#include "../browser.h" 17#include "../browser.h"
18#include "../helpline.h" 18#include "../helpline.h"
19#include "../util.h" 19#include "../util.h"
20#include "../ui.h"
20#include "map.h" 21#include "map.h"
21 22
22struct hist_browser { 23struct hist_browser {
@@ -24,8 +25,12 @@ struct hist_browser {
24 struct hists *hists; 25 struct hists *hists;
25 struct hist_entry *he_selection; 26 struct hist_entry *he_selection;
26 struct map_symbol *selection; 27 struct map_symbol *selection;
28 bool has_symbols;
27}; 29};
28 30
31static int hists__browser_title(struct hists *self, char *bf, size_t size,
32 const char *ev_name);
33
29static void hist_browser__refresh_dimensions(struct hist_browser *self) 34static void hist_browser__refresh_dimensions(struct hist_browser *self)
30{ 35{
31 /* 3 == +/- toggle symbol before actual hist_entry rendering */ 36 /* 3 == +/- toggle symbol before actual hist_entry rendering */
@@ -290,28 +295,49 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
290 ui_browser__reset_index(&self->b); 295 ui_browser__reset_index(&self->b);
291} 296}
292 297
293static int hist_browser__run(struct hist_browser *self, const char *title) 298static void ui_browser__warn_lost_events(struct ui_browser *browser)
299{
300 ui_browser__warning(browser, 4,
301 "Events are being lost, check IO/CPU overload!\n\n"
302 "You may want to run 'perf' using a RT scheduler policy:\n\n"
303 " perf top -r 80\n\n"
304 "Or reduce the sampling frequency.");
305}
306
307static int hist_browser__run(struct hist_browser *self, const char *ev_name,
308 void(*timer)(void *arg), void *arg, int delay_secs)
294{ 309{
295 int key; 310 int key;
296 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', 311 char title[160];
297 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT,
298 NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, };
299 312
300 self->b.entries = &self->hists->entries; 313 self->b.entries = &self->hists->entries;
301 self->b.nr_entries = self->hists->nr_entries; 314 self->b.nr_entries = self->hists->nr_entries;
302 315
303 hist_browser__refresh_dimensions(self); 316 hist_browser__refresh_dimensions(self);
317 hists__browser_title(self->hists, title, sizeof(title), ev_name);
304 318
305 if (ui_browser__show(&self->b, title, 319 if (ui_browser__show(&self->b, title,
306 "Press '?' for help on key bindings") < 0) 320 "Press '?' for help on key bindings") < 0)
307 return -1; 321 return -1;
308 322
309 ui_browser__add_exit_keys(&self->b, exit_keys);
310
311 while (1) { 323 while (1) {
312 key = ui_browser__run(&self->b); 324 key = ui_browser__run(&self->b, delay_secs);
313 325
314 switch (key) { 326 switch (key) {
327 case K_TIMER:
328 timer(arg);
329 ui_browser__update_nr_entries(&self->b, self->hists->nr_entries);
330
331 if (self->hists->stats.nr_lost_warned !=
332 self->hists->stats.nr_events[PERF_RECORD_LOST]) {
333 self->hists->stats.nr_lost_warned =
334 self->hists->stats.nr_events[PERF_RECORD_LOST];
335 ui_browser__warn_lost_events(&self->b);
336 }
337
338 hists__browser_title(self->hists, title, sizeof(title), ev_name);
339 ui_browser__show_title(&self->b, title);
340 continue;
315 case 'D': { /* Debug */ 341 case 'D': { /* Debug */
316 static int seq; 342 static int seq;
317 struct hist_entry *h = rb_entry(self->b.top, 343 struct hist_entry *h = rb_entry(self->b.top,
@@ -334,7 +360,7 @@ static int hist_browser__run(struct hist_browser *self, const char *title)
334 /* Expand the whole world. */ 360 /* Expand the whole world. */
335 hist_browser__set_folding(self, true); 361 hist_browser__set_folding(self, true);
336 break; 362 break;
337 case NEWT_KEY_ENTER: 363 case K_ENTER:
338 if (hist_browser__toggle_fold(self)) 364 if (hist_browser__toggle_fold(self))
339 break; 365 break;
340 /* fall thru */ 366 /* fall thru */
@@ -532,7 +558,7 @@ static int hist_browser__show_entry(struct hist_browser *self,
532 char s[256]; 558 char s[256];
533 double percent; 559 double percent;
534 int printed = 0; 560 int printed = 0;
535 int color, width = self->b.width; 561 int width = self->b.width - 6; /* The percentage */
536 char folded_sign = ' '; 562 char folded_sign = ' ';
537 bool current_entry = ui_browser__is_current_entry(&self->b, row); 563 bool current_entry = ui_browser__is_current_entry(&self->b, row);
538 off_t row_offset = entry->row_offset; 564 off_t row_offset = entry->row_offset;
@@ -548,26 +574,35 @@ static int hist_browser__show_entry(struct hist_browser *self,
548 } 574 }
549 575
550 if (row_offset == 0) { 576 if (row_offset == 0) {
551 hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false, 577 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; 578 percent = (entry->period * 100.0) / self->hists->stats.total_period;
554 579
555 color = HE_COLORSET_SELECTED; 580 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); 581 ui_browser__gotorc(&self->b, row, 0);
567 if (symbol_conf.use_callchain) { 582 if (symbol_conf.use_callchain) {
568 slsmg_printf("%c ", folded_sign); 583 slsmg_printf("%c ", folded_sign);
569 width -= 2; 584 width -= 2;
570 } 585 }
586
587 slsmg_printf(" %5.2f%%", percent);
588
589 /* The scroll bar isn't being used */
590 if (!self->b.navkeypressed)
591 width += 1;
592
593 if (!current_entry || !self->b.navkeypressed)
594 ui_browser__set_color(&self->b, HE_COLORSET_NORMAL);
595
596 if (symbol_conf.show_nr_samples) {
597 slsmg_printf(" %11u", entry->nr_events);
598 width -= 12;
599 }
600
601 if (symbol_conf.show_total_period) {
602 slsmg_printf(" %12" PRIu64, entry->period);
603 width -= 13;
604 }
605
571 slsmg_write_nstring(s, width); 606 slsmg_write_nstring(s, width);
572 ++row; 607 ++row;
573 ++printed; 608 ++printed;
@@ -585,14 +620,23 @@ static int hist_browser__show_entry(struct hist_browser *self,
585 return printed; 620 return printed;
586} 621}
587 622
623static void ui_browser__hists_init_top(struct ui_browser *browser)
624{
625 if (browser->top == NULL) {
626 struct hist_browser *hb;
627
628 hb = container_of(browser, struct hist_browser, b);
629 browser->top = rb_first(&hb->hists->entries);
630 }
631}
632
588static unsigned int hist_browser__refresh(struct ui_browser *self) 633static unsigned int hist_browser__refresh(struct ui_browser *self)
589{ 634{
590 unsigned row = 0; 635 unsigned row = 0;
591 struct rb_node *nd; 636 struct rb_node *nd;
592 struct hist_browser *hb = container_of(self, struct hist_browser, b); 637 struct hist_browser *hb = container_of(self, struct hist_browser, b);
593 638
594 if (self->top == NULL) 639 ui_browser__hists_init_top(self);
595 self->top = rb_first(&hb->hists->entries);
596 640
597 for (nd = self->top; nd; nd = rb_next(nd)) { 641 for (nd = self->top; nd; nd = rb_next(nd)) {
598 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 642 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -644,6 +688,8 @@ static void ui_browser__hists_seek(struct ui_browser *self,
644 if (self->nr_entries == 0) 688 if (self->nr_entries == 0)
645 return; 689 return;
646 690
691 ui_browser__hists_init_top(self);
692
647 switch (whence) { 693 switch (whence) {
648 case SEEK_SET: 694 case SEEK_SET:
649 nd = hists__filter_entries(rb_first(self->entries)); 695 nd = hists__filter_entries(rb_first(self->entries));
@@ -761,6 +807,8 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
761 self->hists = hists; 807 self->hists = hists;
762 self->b.refresh = hist_browser__refresh; 808 self->b.refresh = hist_browser__refresh;
763 self->b.seek = ui_browser__hists_seek; 809 self->b.seek = ui_browser__hists_seek;
810 self->b.use_navkeypressed = true,
811 self->has_symbols = sort_sym.list.next != NULL;
764 } 812 }
765 813
766 return self; 814 return self;
@@ -782,11 +830,12 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self)
782} 830}
783 831
784static int hists__browser_title(struct hists *self, char *bf, size_t size, 832static int hists__browser_title(struct hists *self, char *bf, size_t size,
785 const char *ev_name, const struct dso *dso, 833 const char *ev_name)
786 const struct thread *thread)
787{ 834{
788 char unit; 835 char unit;
789 int printed; 836 int printed;
837 const struct dso *dso = self->dso_filter;
838 const struct thread *thread = self->thread_filter;
790 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; 839 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
791 840
792 nr_events = convert_unit(nr_events, &unit); 841 nr_events = convert_unit(nr_events, &unit);
@@ -803,16 +852,15 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
803 return printed; 852 return printed;
804} 853}
805 854
806static int perf_evsel__hists_browse(struct perf_evsel *evsel, 855static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
807 const char *helpline, const char *ev_name, 856 const char *helpline, const char *ev_name,
808 bool left_exits) 857 bool left_exits,
858 void(*timer)(void *arg), void *arg,
859 int delay_secs)
809{ 860{
810 struct hists *self = &evsel->hists; 861 struct hists *self = &evsel->hists;
811 struct hist_browser *browser = hist_browser__new(self); 862 struct hist_browser *browser = hist_browser__new(self);
812 struct pstack *fstack; 863 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; 864 int key = -1;
817 865
818 if (browser == NULL) 866 if (browser == NULL)
@@ -824,8 +872,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
824 872
825 ui_helpline__push(helpline); 873 ui_helpline__push(helpline);
826 874
827 hists__browser_title(self, msg, sizeof(msg), ev_name,
828 dso_filter, thread_filter);
829 while (1) { 875 while (1) {
830 const struct thread *thread = NULL; 876 const struct thread *thread = NULL;
831 const struct dso *dso = NULL; 877 const struct dso *dso = NULL;
@@ -834,7 +880,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
834 annotate = -2, zoom_dso = -2, zoom_thread = -2, 880 annotate = -2, zoom_dso = -2, zoom_thread = -2,
835 browse_map = -2; 881 browse_map = -2;
836 882
837 key = hist_browser__run(browser, msg); 883 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
838 884
839 if (browser->he_selection != NULL) { 885 if (browser->he_selection != NULL) {
840 thread = hist_browser__selected_thread(browser); 886 thread = hist_browser__selected_thread(browser);
@@ -842,14 +888,23 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
842 } 888 }
843 889
844 switch (key) { 890 switch (key) {
845 case NEWT_KEY_TAB: 891 case K_TAB:
846 case NEWT_KEY_UNTAB: 892 case K_UNTAB:
893 if (nr_events == 1)
894 continue;
847 /* 895 /*
848 * Exit the browser, let hists__browser_tree 896 * Exit the browser, let hists__browser_tree
849 * go to the next or previous 897 * go to the next or previous
850 */ 898 */
851 goto out_free_stack; 899 goto out_free_stack;
852 case 'a': 900 case 'a':
901 if (!browser->has_symbols) {
902 ui_browser__warning(&browser->b, delay_secs * 2,
903 "Annotation is only available for symbolic views, "
904 "include \"sym\" in --sort to use it.");
905 continue;
906 }
907
853 if (browser->selection == NULL || 908 if (browser->selection == NULL ||
854 browser->selection->sym == NULL || 909 browser->selection->sym == NULL ||
855 browser->selection->map->dso->annotate_warned) 910 browser->selection->map->dso->annotate_warned)
@@ -859,25 +914,30 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
859 goto zoom_dso; 914 goto zoom_dso;
860 case 't': 915 case 't':
861 goto zoom_thread; 916 goto zoom_thread;
862 case NEWT_KEY_F1: 917 case K_F1:
863 case 'h': 918 case 'h':
864 case '?': 919 case '?':
865 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n" 920 ui_browser__help_window(&browser->b,
866 "<- Zoom out\n" 921 "h/?/F1 Show this window\n"
867 "a Annotate current symbol\n" 922 "UP/DOWN/PGUP\n"
868 "h/?/F1 Show this window\n" 923 "PGDN/SPACE Navigate\n"
869 "C Collapse all callchains\n" 924 "q/ESC/CTRL+C Exit browser\n\n"
870 "E Expand all callchains\n" 925 "For multiple event sessions:\n\n"
871 "d Zoom into current DSO\n" 926 "TAB/UNTAB Switch events\n\n"
872 "t Zoom into current Thread\n" 927 "For symbolic views (--sort has sym):\n\n"
873 "TAB/UNTAB Switch events\n" 928 "-> Zoom into DSO/Threads & Annotate current symbol\n"
874 "q/CTRL+C Exit browser"); 929 "<- Zoom out\n"
930 "a Annotate current symbol\n"
931 "C Collapse all callchains\n"
932 "E Expand all callchains\n"
933 "d Zoom into current DSO\n"
934 "t Zoom into current Thread");
875 continue; 935 continue;
876 case NEWT_KEY_ENTER: 936 case K_ENTER:
877 case NEWT_KEY_RIGHT: 937 case K_RIGHT:
878 /* menu */ 938 /* menu */
879 break; 939 break;
880 case NEWT_KEY_LEFT: { 940 case K_LEFT: {
881 const void *top; 941 const void *top;
882 942
883 if (pstack__empty(fstack)) { 943 if (pstack__empty(fstack)) {
@@ -889,21 +949,28 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
889 continue; 949 continue;
890 } 950 }
891 top = pstack__pop(fstack); 951 top = pstack__pop(fstack);
892 if (top == &dso_filter) 952 if (top == &browser->hists->dso_filter)
893 goto zoom_out_dso; 953 goto zoom_out_dso;
894 if (top == &thread_filter) 954 if (top == &browser->hists->thread_filter)
895 goto zoom_out_thread; 955 goto zoom_out_thread;
896 continue; 956 continue;
897 } 957 }
898 case NEWT_KEY_ESCAPE: 958 case K_ESC:
899 if (!left_exits && 959 if (!left_exits &&
900 !ui__dialog_yesno("Do you really want to exit?")) 960 !ui_browser__dialog_yesno(&browser->b,
961 "Do you really want to exit?"))
901 continue; 962 continue;
902 /* Fall thru */ 963 /* Fall thru */
903 default: 964 case 'q':
965 case CTRL('c'):
904 goto out_free_stack; 966 goto out_free_stack;
967 default:
968 continue;
905 } 969 }
906 970
971 if (!browser->has_symbols)
972 goto add_exit_option;
973
907 if (browser->selection != NULL && 974 if (browser->selection != NULL &&
908 browser->selection->sym != NULL && 975 browser->selection->sym != NULL &&
909 !browser->selection->map->dso->annotate_warned && 976 !browser->selection->map->dso->annotate_warned &&
@@ -913,14 +980,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
913 980
914 if (thread != NULL && 981 if (thread != NULL &&
915 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 982 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
916 (thread_filter ? "out of" : "into"), 983 (browser->hists->thread_filter ? "out of" : "into"),
917 (thread->comm_set ? thread->comm : ""), 984 (thread->comm_set ? thread->comm : ""),
918 thread->pid) > 0) 985 thread->pid) > 0)
919 zoom_thread = nr_options++; 986 zoom_thread = nr_options++;
920 987
921 if (dso != NULL && 988 if (dso != NULL &&
922 asprintf(&options[nr_options], "Zoom %s %s DSO", 989 asprintf(&options[nr_options], "Zoom %s %s DSO",
923 (dso_filter ? "out of" : "into"), 990 (browser->hists->dso_filter ? "out of" : "into"),
924 (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 991 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
925 zoom_dso = nr_options++; 992 zoom_dso = nr_options++;
926 993
@@ -928,7 +995,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
928 browser->selection->map != NULL && 995 browser->selection->map != NULL &&
929 asprintf(&options[nr_options], "Browse map details") > 0) 996 asprintf(&options[nr_options], "Browse map details") > 0)
930 browse_map = nr_options++; 997 browse_map = nr_options++;
931 998add_exit_option:
932 options[nr_options++] = (char *)"Exit"; 999 options[nr_options++] = (char *)"Exit";
933 1000
934 choice = ui__popup_menu(nr_options, options); 1001 choice = ui__popup_menu(nr_options, options);
@@ -944,50 +1011,59 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
944 1011
945 if (choice == annotate) { 1012 if (choice == annotate) {
946 struct hist_entry *he; 1013 struct hist_entry *he;
1014 int err;
947do_annotate: 1015do_annotate:
948 he = hist_browser__selected_entry(browser); 1016 he = hist_browser__selected_entry(browser);
949 if (he == NULL) 1017 if (he == NULL)
950 continue; 1018 continue;
951 1019 /*
952 hist_entry__tui_annotate(he, evsel->idx); 1020 * Don't let this be freed, say, by hists__decay_entry.
1021 */
1022 he->used = true;
1023 err = hist_entry__tui_annotate(he, evsel->idx, nr_events,
1024 timer, arg, delay_secs);
1025 he->used = false;
1026 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1027 if (err)
1028 ui_browser__handle_resize(&browser->b);
953 } else if (choice == browse_map) 1029 } else if (choice == browse_map)
954 map__browse(browser->selection->map); 1030 map__browse(browser->selection->map);
955 else if (choice == zoom_dso) { 1031 else if (choice == zoom_dso) {
956zoom_dso: 1032zoom_dso:
957 if (dso_filter) { 1033 if (browser->hists->dso_filter) {
958 pstack__remove(fstack, &dso_filter); 1034 pstack__remove(fstack, &browser->hists->dso_filter);
959zoom_out_dso: 1035zoom_out_dso:
960 ui_helpline__pop(); 1036 ui_helpline__pop();
961 dso_filter = NULL; 1037 browser->hists->dso_filter = NULL;
1038 sort_dso.elide = false;
962 } else { 1039 } else {
963 if (dso == NULL) 1040 if (dso == NULL)
964 continue; 1041 continue;
965 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1042 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
966 dso->kernel ? "the Kernel" : dso->short_name); 1043 dso->kernel ? "the Kernel" : dso->short_name);
967 dso_filter = dso; 1044 browser->hists->dso_filter = dso;
968 pstack__push(fstack, &dso_filter); 1045 sort_dso.elide = true;
1046 pstack__push(fstack, &browser->hists->dso_filter);
969 } 1047 }
970 hists__filter_by_dso(self, dso_filter); 1048 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); 1049 hist_browser__reset(browser);
974 } else if (choice == zoom_thread) { 1050 } else if (choice == zoom_thread) {
975zoom_thread: 1051zoom_thread:
976 if (thread_filter) { 1052 if (browser->hists->thread_filter) {
977 pstack__remove(fstack, &thread_filter); 1053 pstack__remove(fstack, &browser->hists->thread_filter);
978zoom_out_thread: 1054zoom_out_thread:
979 ui_helpline__pop(); 1055 ui_helpline__pop();
980 thread_filter = NULL; 1056 browser->hists->thread_filter = NULL;
1057 sort_thread.elide = false;
981 } else { 1058 } else {
982 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1059 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
983 thread->comm_set ? thread->comm : "", 1060 thread->comm_set ? thread->comm : "",
984 thread->pid); 1061 thread->pid);
985 thread_filter = thread; 1062 browser->hists->thread_filter = thread;
986 pstack__push(fstack, &thread_filter); 1063 sort_thread.elide = true;
1064 pstack__push(fstack, &browser->hists->thread_filter);
987 } 1065 }
988 hists__filter_by_thread(self, thread_filter); 1066 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); 1067 hist_browser__reset(browser);
992 } 1068 }
993 } 1069 }
@@ -1001,6 +1077,7 @@ out:
1001struct perf_evsel_menu { 1077struct perf_evsel_menu {
1002 struct ui_browser b; 1078 struct ui_browser b;
1003 struct perf_evsel *selection; 1079 struct perf_evsel *selection;
1080 bool lost_events, lost_events_warned;
1004}; 1081};
1005 1082
1006static void perf_evsel_menu__write(struct ui_browser *browser, 1083static void perf_evsel_menu__write(struct ui_browser *browser,
@@ -1013,22 +1090,38 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1013 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1090 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1014 const char *ev_name = event_name(evsel); 1091 const char *ev_name = event_name(evsel);
1015 char bf[256], unit; 1092 char bf[256], unit;
1093 const char *warn = " ";
1094 size_t printed;
1016 1095
1017 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1096 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1018 HE_COLORSET_NORMAL); 1097 HE_COLORSET_NORMAL);
1019 1098
1020 nr_events = convert_unit(nr_events, &unit); 1099 nr_events = convert_unit(nr_events, &unit);
1021 snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1100 printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1022 unit, unit == ' ' ? "" : " ", ev_name); 1101 unit, unit == ' ' ? "" : " ", ev_name);
1023 slsmg_write_nstring(bf, browser->width); 1102 slsmg_printf("%s", bf);
1103
1104 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1105 if (nr_events != 0) {
1106 menu->lost_events = true;
1107 if (!current_entry)
1108 ui_browser__set_color(browser, HE_COLORSET_TOP);
1109 nr_events = convert_unit(nr_events, &unit);
1110 snprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", nr_events,
1111 unit, unit == ' ' ? "" : " ");
1112 warn = bf;
1113 }
1114
1115 slsmg_write_nstring(warn, browser->width - printed);
1024 1116
1025 if (current_entry) 1117 if (current_entry)
1026 menu->selection = evsel; 1118 menu->selection = evsel;
1027} 1119}
1028 1120
1029static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) 1121static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1122 int nr_events, const char *help,
1123 void(*timer)(void *arg), void *arg, int delay_secs)
1030{ 1124{
1031 int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
1032 struct perf_evlist *evlist = menu->b.priv; 1125 struct perf_evlist *evlist = menu->b.priv;
1033 struct perf_evsel *pos; 1126 struct perf_evsel *pos;
1034 const char *ev_name, *title = "Available samples"; 1127 const char *ev_name, *title = "Available samples";
@@ -1038,50 +1131,72 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
1038 "ESC: exit, ENTER|->: Browse histograms") < 0) 1131 "ESC: exit, ENTER|->: Browse histograms") < 0)
1039 return -1; 1132 return -1;
1040 1133
1041 ui_browser__add_exit_keys(&menu->b, exit_keys);
1042
1043 while (1) { 1134 while (1) {
1044 key = ui_browser__run(&menu->b); 1135 key = ui_browser__run(&menu->b, delay_secs);
1045 1136
1046 switch (key) { 1137 switch (key) {
1047 case NEWT_KEY_RIGHT: 1138 case K_TIMER:
1048 case NEWT_KEY_ENTER: 1139 timer(arg);
1140
1141 if (!menu->lost_events_warned && menu->lost_events) {
1142 ui_browser__warn_lost_events(&menu->b);
1143 menu->lost_events_warned = true;
1144 }
1145 continue;
1146 case K_RIGHT:
1147 case K_ENTER:
1049 if (!menu->selection) 1148 if (!menu->selection)
1050 continue; 1149 continue;
1051 pos = menu->selection; 1150 pos = menu->selection;
1052browse_hists: 1151browse_hists:
1152 perf_evlist__set_selected(evlist, pos);
1153 /*
1154 * Give the calling tool a chance to populate the non
1155 * default evsel resorted hists tree.
1156 */
1157 if (timer)
1158 timer(arg);
1053 ev_name = event_name(pos); 1159 ev_name = event_name(pos);
1054 key = perf_evsel__hists_browse(pos, help, ev_name, true); 1160 key = perf_evsel__hists_browse(pos, nr_events, help,
1161 ev_name, true, timer,
1162 arg, delay_secs);
1055 ui_browser__show_title(&menu->b, title); 1163 ui_browser__show_title(&menu->b, title);
1056 break; 1164 switch (key) {
1057 case NEWT_KEY_LEFT: 1165 case K_TAB:
1166 if (pos->node.next == &evlist->entries)
1167 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1168 else
1169 pos = list_entry(pos->node.next, struct perf_evsel, node);
1170 goto browse_hists;
1171 case K_UNTAB:
1172 if (pos->node.prev == &evlist->entries)
1173 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1174 else
1175 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1176 goto browse_hists;
1177 case K_ESC:
1178 if (!ui_browser__dialog_yesno(&menu->b,
1179 "Do you really want to exit?"))
1180 continue;
1181 /* Fall thru */
1182 case 'q':
1183 case CTRL('c'):
1184 goto out;
1185 default:
1186 continue;
1187 }
1188 case K_LEFT:
1058 continue; 1189 continue;
1059 case NEWT_KEY_ESCAPE: 1190 case K_ESC:
1060 if (!ui__dialog_yesno("Do you really want to exit?")) 1191 if (!ui_browser__dialog_yesno(&menu->b,
1192 "Do you really want to exit?"))
1061 continue; 1193 continue;
1062 /* Fall thru */ 1194 /* 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': 1195 case 'q':
1081 case CTRL('c'): 1196 case CTRL('c'):
1082 goto out; 1197 goto out;
1083 default: 1198 default:
1084 break; 1199 continue;
1085 } 1200 }
1086 } 1201 }
1087 1202
@@ -1091,7 +1206,9 @@ out:
1091} 1206}
1092 1207
1093static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1208static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1094 const char *help) 1209 const char *help,
1210 void(*timer)(void *arg), void *arg,
1211 int delay_secs)
1095{ 1212{
1096 struct perf_evsel *pos; 1213 struct perf_evsel *pos;
1097 struct perf_evsel_menu menu = { 1214 struct perf_evsel_menu menu = {
@@ -1121,18 +1238,24 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1121 pos->name = strdup(ev_name); 1238 pos->name = strdup(ev_name);
1122 } 1239 }
1123 1240
1124 return perf_evsel_menu__run(&menu, help); 1241 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
1242 arg, delay_secs);
1125} 1243}
1126 1244
1127int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help) 1245int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1246 void(*timer)(void *arg), void *arg,
1247 int delay_secs)
1128{ 1248{
1129 1249
1130 if (evlist->nr_entries == 1) { 1250 if (evlist->nr_entries == 1) {
1131 struct perf_evsel *first = list_entry(evlist->entries.next, 1251 struct perf_evsel *first = list_entry(evlist->entries.next,
1132 struct perf_evsel, node); 1252 struct perf_evsel, node);
1133 const char *ev_name = event_name(first); 1253 const char *ev_name = event_name(first);
1134 return perf_evsel__hists_browse(first, help, ev_name, false); 1254 return perf_evsel__hists_browse(first, evlist->nr_entries, help,
1255 ev_name, false, timer, arg,
1256 delay_secs);
1135 } 1257 }
1136 1258
1137 return __perf_evlist__tui_browse_hists(evlist, help); 1259 return __perf_evlist__tui_browse_hists(evlist, help,
1260 timer, arg, delay_secs);
1138} 1261}
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 88403cf8396a..000000000000
--- a/tools/perf/util/ui/browsers/top.c
+++ /dev/null
@@ -1,212 +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 return perf_top_browser__run(&browser);
212}
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
index f36d2ff509ed..6ef3c5691762 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/util/ui/helpline.c
@@ -1,20 +1,28 @@
1#define _GNU_SOURCE 1#define _GNU_SOURCE
2#include <stdio.h> 2#include <stdio.h>
3#include <stdlib.h> 3#include <stdlib.h>
4#include <newt.h> 4#include <string.h>
5 5
6#include "../debug.h" 6#include "../debug.h"
7#include "helpline.h" 7#include "helpline.h"
8#include "ui.h" 8#include "ui.h"
9#include "libslang.h"
9 10
10void ui_helpline__pop(void) 11void ui_helpline__pop(void)
11{ 12{
12 newtPopHelpLine();
13} 13}
14 14
15char ui_helpline__current[512];
16
15void ui_helpline__push(const char *msg) 17void ui_helpline__push(const char *msg)
16{ 18{
17 newtPushHelpLine(msg); 19 const size_t sz = sizeof(ui_helpline__current);
20
21 SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
22 SLsmg_set_color(0);
23 SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols);
24 SLsmg_refresh();
25 strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
18} 26}
19 27
20void ui_helpline__vpush(const char *fmt, va_list ap) 28void ui_helpline__vpush(const char *fmt, va_list ap)
@@ -63,7 +71,7 @@ int ui_helpline__show_help(const char *format, va_list ap)
63 71
64 if (ui_helpline__last_msg[backlog - 1] == '\n') { 72 if (ui_helpline__last_msg[backlog - 1] == '\n') {
65 ui_helpline__puts(ui_helpline__last_msg); 73 ui_helpline__puts(ui_helpline__last_msg);
66 newtRefresh(); 74 SLsmg_refresh();
67 backlog = 0; 75 backlog = 0;
68 } 76 }
69 pthread_mutex_unlock(&ui__lock); 77 pthread_mutex_unlock(&ui__lock);
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h
index ab6028d0c401..7bab6b34e35e 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);
@@ -8,4 +11,6 @@ void ui_helpline__vpush(const char *fmt, va_list ap);
8void ui_helpline__fpush(const char *fmt, ...); 11void ui_helpline__fpush(const char *fmt, ...);
9void ui_helpline__puts(const char *msg); 12void ui_helpline__puts(const char *msg);
10 13
14extern char ui_helpline__current[];
15
11#endif /* _PERF_UI_HELPLINE_H_ */ 16#endif /* _PERF_UI_HELPLINE_H_ */
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/progress.c b/tools/perf/util/ui/progress.c
index d7fc399d36b3..295e366b6311 100644
--- a/tools/perf/util/ui/progress.c
+++ b/tools/perf/util/ui/progress.c
@@ -1,60 +1,29 @@
1#include <stdlib.h>
2#include <newt.h>
3#include "../cache.h" 1#include "../cache.h"
4#include "progress.h" 2#include "progress.h"
3#include "libslang.h"
4#include "ui.h"
5#include "browser.h"
5 6
6struct ui_progress { 7void ui_progress__update(u64 curr, u64 total, const char *title)
7 newtComponent form, scale;
8};
9
10struct ui_progress *ui_progress__new(const char *title, u64 total)
11{
12 struct ui_progress *self = malloc(sizeof(*self));
13
14 if (self != NULL) {
15 int cols;
16
17 if (use_browser <= 0)
18 return self;
19 newtGetScreenSize(&cols, NULL);
20 cols -= 4;
21 newtCenteredWindow(cols, 1, title);
22 self->form = newtForm(NULL, NULL, 0);
23 if (self->form == NULL)
24 goto out_free_self;
25 self->scale = newtScale(0, 0, cols, total);
26 if (self->scale == NULL)
27 goto out_free_form;
28 newtFormAddComponent(self->form, self->scale);
29 newtRefresh();
30 }
31
32 return self;
33
34out_free_form:
35 newtFormDestroy(self->form);
36out_free_self:
37 free(self);
38 return NULL;
39}
40
41void ui_progress__update(struct ui_progress *self, u64 curr)
42{ 8{
9 int bar, y;
43 /* 10 /*
44 * FIXME: We should have a per UI backend way of showing progress, 11 * FIXME: We should have a per UI backend way of showing progress,
45 * stdio will just show a percentage as NN%, etc. 12 * stdio will just show a percentage as NN%, etc.
46 */ 13 */
47 if (use_browser <= 0) 14 if (use_browser <= 0)
48 return; 15 return;
49 newtScaleSet(self->scale, curr);
50 newtRefresh();
51}
52 16
53void ui_progress__delete(struct ui_progress *self) 17 ui__refresh_dimensions(true);
54{ 18 pthread_mutex_lock(&ui__lock);
55 if (use_browser > 0) { 19 y = SLtt_Screen_Rows / 2 - 2;
56 newtFormDestroy(self->form); 20 SLsmg_set_color(0);
57 newtPopWindow(); 21 SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);
58 } 22 SLsmg_gotorc(y++, 1);
59 free(self); 23 SLsmg_write_string((char *)title);
24 SLsmg_set_color(HE_COLORSET_SELECTED);
25 bar = ((SLtt_Screen_Cols - 2) * curr) / total;
26 SLsmg_fill_region(y, 1, 1, bar, ' ');
27 SLsmg_refresh();
28 pthread_mutex_unlock(&ui__lock);
60} 29}
diff --git a/tools/perf/util/ui/progress.h b/tools/perf/util/ui/progress.h
index a3820a0beb5b..d9c205b59aa1 100644
--- a/tools/perf/util/ui/progress.h
+++ b/tools/perf/util/ui/progress.h
@@ -1,11 +1,8 @@
1#ifndef _PERF_UI_PROGRESS_H_ 1#ifndef _PERF_UI_PROGRESS_H_
2#define _PERF_UI_PROGRESS_H_ 1 2#define _PERF_UI_PROGRESS_H_ 1
3 3
4struct ui_progress; 4#include <../types.h>
5 5
6struct ui_progress *ui_progress__new(const char *title, u64 total); 6void ui_progress__update(u64 curr, u64 total, const char *title);
7void ui_progress__delete(struct ui_progress *self);
8
9void ui_progress__update(struct ui_progress *self, u64 curr);
10 7
11#endif 8#endif
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c
index ee46d671db59..85a69faa09aa 100644
--- a/tools/perf/util/ui/setup.c
+++ b/tools/perf/util/ui/setup.c
@@ -7,9 +7,85 @@
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 "util.h"
11#include "libslang.h"
12#include "keysyms.h"
10 13
11pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; 14pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
12 15
16static volatile int ui__need_resize;
17
18void ui__refresh_dimensions(bool force)
19{
20 if (force || ui__need_resize) {
21 ui__need_resize = 0;
22 pthread_mutex_lock(&ui__lock);
23 SLtt_get_screen_size();
24 SLsmg_reinit_smg();
25 pthread_mutex_unlock(&ui__lock);
26 }
27}
28
29static void ui__sigwinch(int sig __used)
30{
31 ui__need_resize = 1;
32}
33
34static void ui__setup_sigwinch(void)
35{
36 static bool done;
37
38 if (done)
39 return;
40
41 done = true;
42 pthread__unblock_sigwinch();
43 signal(SIGWINCH, ui__sigwinch);
44}
45
46int ui__getch(int delay_secs)
47{
48 struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
49 fd_set read_set;
50 int err, key;
51
52 ui__setup_sigwinch();
53
54 FD_ZERO(&read_set);
55 FD_SET(0, &read_set);
56
57 if (delay_secs) {
58 timeout.tv_sec = delay_secs;
59 timeout.tv_usec = 0;
60 }
61
62 err = select(1, &read_set, NULL, NULL, ptimeout);
63
64 if (err == 0)
65 return K_TIMER;
66
67 if (err == -1) {
68 if (errno == EINTR)
69 return K_RESIZE;
70 return K_ERROR;
71 }
72
73 key = SLang_getkey();
74 if (key != K_ESC)
75 return key;
76
77 FD_ZERO(&read_set);
78 FD_SET(0, &read_set);
79 timeout.tv_sec = 0;
80 timeout.tv_usec = 20;
81 err = select(1, &read_set, NULL, NULL, &timeout);
82 if (err == 0)
83 return K_ESC;
84
85 SLang_ungetkey(key);
86 return SLkp_getkey();
87}
88
13static void newt_suspend(void *d __used) 89static void newt_suspend(void *d __used)
14{ 90{
15 newtSuspend(); 91 newtSuspend();
@@ -17,6 +93,33 @@ static void newt_suspend(void *d __used)
17 newtResume(); 93 newtResume();
18} 94}
19 95
96static int ui__init(void)
97{
98 int err = SLkp_init();
99
100 if (err < 0)
101 goto out;
102
103 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
104out:
105 return err;
106}
107
108static void ui__exit(void)
109{
110 SLtt_set_cursor_visibility(1);
111 SLsmg_refresh();
112 SLsmg_reset_smg();
113 SLang_reset_tty();
114}
115
116static void ui__signal(int sig)
117{
118 ui__exit();
119 psignal(sig, "perf");
120 exit(0);
121}
122
20void setup_browser(bool fallback_to_pager) 123void setup_browser(bool fallback_to_pager)
21{ 124{
22 if (!isatty(1) || !use_browser || dump_trace) { 125 if (!isatty(1) || !use_browser || dump_trace) {
@@ -28,19 +131,25 @@ void setup_browser(bool fallback_to_pager)
28 131
29 use_browser = 1; 132 use_browser = 1;
30 newtInit(); 133 newtInit();
31 newtCls(); 134 ui__init();
32 newtSetSuspendCallback(newt_suspend, NULL); 135 newtSetSuspendCallback(newt_suspend, NULL);
33 ui_helpline__init(); 136 ui_helpline__init();
34 ui_browser__init(); 137 ui_browser__init();
138
139 signal(SIGSEGV, ui__signal);
140 signal(SIGFPE, ui__signal);
141 signal(SIGINT, ui__signal);
142 signal(SIGQUIT, ui__signal);
143 signal(SIGTERM, ui__signal);
35} 144}
36 145
37void exit_browser(bool wait_for_ok) 146void exit_browser(bool wait_for_ok)
38{ 147{
39 if (use_browser > 0) { 148 if (use_browser > 0) {
40 if (wait_for_ok) { 149 if (wait_for_ok)
41 char title[] = "Fatal Error", ok[] = "Ok"; 150 ui__question_window("Fatal Error",
42 newtWinMessage(title, ok, ui_helpline__last_msg); 151 ui_helpline__last_msg,
43 } 152 "Press any key...", 0);
44 newtFinished(); 153 ui__exit();
45 } 154 }
46} 155}
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/util/ui/ui.h
index d264e059c829..7b67045479f6 100644
--- a/tools/perf/util/ui/ui.h
+++ b/tools/perf/util/ui/ui.h
@@ -2,7 +2,10 @@
2#define _PERF_UI_H_ 1 2#define _PERF_UI_H_ 1
3 3
4#include <pthread.h> 4#include <pthread.h>
5#include <stdbool.h>
5 6
6extern pthread_mutex_t ui__lock; 7extern pthread_mutex_t ui__lock;
7 8
9void ui__refresh_dimensions(bool force);
10
8#endif /* _PERF_UI_H_ */ 11#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
index fdf1fc8f08bc..45daa7c41dad 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/util/ui/util.c
@@ -1,6 +1,5 @@
1#include <newt.h> 1#include "../util.h"
2#include <signal.h> 2#include <signal.h>
3#include <stdio.h>
4#include <stdbool.h> 3#include <stdbool.h>
5#include <string.h> 4#include <string.h>
6#include <sys/ttydefaults.h> 5#include <sys/ttydefaults.h>
@@ -8,72 +7,75 @@
8#include "../cache.h" 7#include "../cache.h"
9#include "../debug.h" 8#include "../debug.h"
10#include "browser.h" 9#include "browser.h"
10#include "keysyms.h"
11#include "helpline.h" 11#include "helpline.h"
12#include "ui.h" 12#include "ui.h"
13#include "util.h" 13#include "util.h"
14#include "libslang.h"
14 15
15static void newt_form__set_exit_keys(newtComponent self) 16static void ui_browser__argv_write(struct ui_browser *browser,
17 void *entry, int row)
16{ 18{
17 newtFormAddHotKey(self, NEWT_KEY_LEFT); 19 char **arg = entry;
18 newtFormAddHotKey(self, NEWT_KEY_ESCAPE); 20 bool current_entry = ui_browser__is_current_entry(browser, row);
19 newtFormAddHotKey(self, 'Q');
20 newtFormAddHotKey(self, 'q');
21 newtFormAddHotKey(self, CTRL('c'));
22}
23 21
24static newtComponent newt_form__new(void) 22 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
25{ 23 HE_COLORSET_NORMAL);
26 newtComponent self = newtForm(NULL, NULL, 0); 24 slsmg_write_nstring(*arg, browser->width);
27 if (self)
28 newt_form__set_exit_keys(self);
29 return self;
30} 25}
31 26
32int ui__popup_menu(int argc, char * const argv[]) 27static int popup_menu__run(struct ui_browser *menu)
33{ 28{
34 struct newtExitStruct es; 29 int key;
35 int i, rc = -1, max_len = 5;
36 newtComponent listbox, form = newt_form__new();
37 30
38 if (form == NULL) 31 if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
39 return -1; 32 return -1;
40 33
41 listbox = newtListbox(0, 0, argc, NEWT_FLAG_RETURNEXIT); 34 while (1) {
42 if (listbox == NULL) 35 key = ui_browser__run(menu, 0);
43 goto out_destroy_form;
44 36
45 newtFormAddComponent(form, listbox); 37 switch (key) {
38 case K_RIGHT:
39 case K_ENTER:
40 key = menu->index;
41 break;
42 case K_LEFT:
43 case K_ESC:
44 case 'q':
45 case CTRL('c'):
46 key = -1;
47 break;
48 default:
49 continue;
50 }
46 51
47 for (i = 0; i < argc; ++i) { 52 break;
48 int len = strlen(argv[i]);
49 if (len > max_len)
50 max_len = len;
51 if (newtListboxAddEntry(listbox, argv[i], (void *)(long)i))
52 goto out_destroy_form;
53 } 53 }
54 54
55 newtCenteredWindow(max_len, argc, NULL); 55 ui_browser__hide(menu);
56 newtFormRun(form, &es); 56 return key;
57 rc = newtListboxGetCurrent(listbox) - NULL;
58 if (es.reason == NEWT_EXIT_HOTKEY)
59 rc = -1;
60 newtPopWindow();
61out_destroy_form:
62 newtFormDestroy(form);
63 return rc;
64} 57}
65 58
66int ui__help_window(const char *text) 59int ui__popup_menu(int argc, char * const argv[])
67{ 60{
68 struct newtExitStruct es; 61 struct ui_browser menu = {
69 newtComponent tb, form = newt_form__new(); 62 .entries = (void *)argv,
70 int rc = -1; 63 .refresh = ui_browser__argv_refresh,
64 .seek = ui_browser__argv_seek,
65 .write = ui_browser__argv_write,
66 .nr_entries = argc,
67 };
68
69 return popup_menu__run(&menu);
70}
71
72int ui__question_window(const char *title, const char *text,
73 const char *exit_msg, int delay_secs)
74{
75 int x, y;
71 int max_len = 0, nr_lines = 0; 76 int max_len = 0, nr_lines = 0;
72 const char *t; 77 const char *t;
73 78
74 if (form == NULL)
75 return -1;
76
77 t = text; 79 t = text;
78 while (1) { 80 while (1) {
79 const char *sep = strchr(t, '\n'); 81 const char *sep = strchr(t, '\n');
@@ -90,41 +92,77 @@ int ui__help_window(const char *text)
90 t = sep + 1; 92 t = sep + 1;
91 } 93 }
92 94
93 tb = newtTextbox(0, 0, max_len, nr_lines, 0); 95 max_len += 2;
94 if (tb == NULL) 96 nr_lines += 4;
95 goto out_destroy_form; 97 y = SLtt_Screen_Rows / 2 - nr_lines / 2,
96 98 x = SLtt_Screen_Cols / 2 - max_len / 2;
97 newtTextboxSetText(tb, text); 99
98 newtFormAddComponent(form, tb); 100 SLsmg_set_color(0);
99 newtCenteredWindow(max_len, nr_lines, NULL); 101 SLsmg_draw_box(y, x++, nr_lines, max_len);
100 newtFormRun(form, &es); 102 if (title) {
101 newtPopWindow(); 103 SLsmg_gotorc(y, x + 1);
102 rc = 0; 104 SLsmg_write_string((char *)title);
103out_destroy_form: 105 }
104 newtFormDestroy(form); 106 SLsmg_gotorc(++y, x);
105 return rc; 107 nr_lines -= 2;
108 max_len -= 2;
109 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
110 nr_lines, max_len, 1);
111 SLsmg_gotorc(y + nr_lines - 2, x);
112 SLsmg_write_nstring((char *)" ", max_len);
113 SLsmg_gotorc(y + nr_lines - 1, x);
114 SLsmg_write_nstring((char *)exit_msg, max_len);
115 SLsmg_refresh();
116 return ui__getch(delay_secs);
106} 117}
107 118
108static const char yes[] = "Yes", no[] = "No", 119int ui__help_window(const char *text)
109 warning_str[] = "Warning!", ok[] = "Ok"; 120{
121 return ui__question_window("Help", text, "Press any key...", 0);
122}
110 123
111bool ui__dialog_yesno(const char *msg) 124int ui__dialog_yesno(const char *msg)
112{ 125{
113 /* newtWinChoice should really be accepting const char pointers... */ 126 return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
114 return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1;
115} 127}
116 128
117void ui__warning(const char *format, ...) 129int __ui__warning(const char *title, const char *format, va_list args)
118{ 130{
119 va_list args; 131 char *s;
132
133 if (use_browser > 0 && vasprintf(&s, format, args) > 0) {
134 int key;
120 135
121 va_start(args, format);
122 if (use_browser > 0) {
123 pthread_mutex_lock(&ui__lock); 136 pthread_mutex_lock(&ui__lock);
124 newtWinMessagev((char *)warning_str, (char *)ok, 137 key = ui__question_window(title, s, "Press any key...", 0);
125 (char *)format, args);
126 pthread_mutex_unlock(&ui__lock); 138 pthread_mutex_unlock(&ui__lock);
127 } else 139 free(s);
128 vfprintf(stderr, format, args); 140 return key;
141 }
142
143 fprintf(stderr, "%s:\n", title);
144 vfprintf(stderr, format, args);
145 return K_ESC;
146}
147
148int ui__warning(const char *format, ...)
149{
150 int key;
151 va_list args;
152
153 va_start(args, format);
154 key = __ui__warning("Warning", format, args);
155 va_end(args);
156 return key;
157}
158
159int ui__error(const char *format, ...)
160{
161 int key;
162 va_list args;
163
164 va_start(args, format);
165 key = __ui__warning("Error", format, args);
129 va_end(args); 166 va_end(args);
167 return key;
130} 168}
diff --git a/tools/perf/util/ui/util.h b/tools/perf/util/ui/util.h
index afcbc1d99531..2d1738bd71c8 100644
--- a/tools/perf/util/ui/util.h
+++ b/tools/perf/util/ui/util.h
@@ -1,10 +1,14 @@
1#ifndef _PERF_UI_UTIL_H_ 1#ifndef _PERF_UI_UTIL_H_
2#define _PERF_UI_UTIL_H_ 1 2#define _PERF_UI_UTIL_H_ 1
3 3
4#include <stdbool.h> 4#include <stdarg.h>
5 5
6int ui__getch(int delay_secs);
6int ui__popup_menu(int argc, char * const argv[]); 7int ui__popup_menu(int argc, char * const argv[]);
7int ui__help_window(const char *text); 8int ui__help_window(const char *text);
8bool ui__dialog_yesno(const char *msg); 9int ui__dialog_yesno(const char *msg);
10int ui__question_window(const char *title, const char *text,
11 const char *exit_msg, int delay_secs);
12int __ui__warning(const char *title, const char *format, va_list args);
9 13
10#endif /* _PERF_UI_UTIL_H_ */ 14#endif /* _PERF_UI_UTIL_H_ */
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 8b2d37b59c9e..3c6f7808efae 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -162,19 +162,21 @@ void print_header(void)
162 162
163void dump_cnt(struct counters *cnt) 163void dump_cnt(struct counters *cnt)
164{ 164{
165 fprintf(stderr, "package: %d ", cnt->pkg); 165 if (!cnt)
166 fprintf(stderr, "core:: %d ", cnt->core); 166 return;
167 fprintf(stderr, "CPU: %d ", cnt->cpu); 167 if (cnt->pkg) fprintf(stderr, "package: %d ", cnt->pkg);
168 fprintf(stderr, "TSC: %016llX\n", cnt->tsc); 168 if (cnt->core) fprintf(stderr, "core:: %d ", cnt->core);
169 fprintf(stderr, "c3: %016llX\n", cnt->c3); 169 if (cnt->cpu) fprintf(stderr, "CPU: %d ", cnt->cpu);
170 fprintf(stderr, "c6: %016llX\n", cnt->c6); 170 if (cnt->tsc) fprintf(stderr, "TSC: %016llX\n", cnt->tsc);
171 fprintf(stderr, "c7: %016llX\n", cnt->c7); 171 if (cnt->c3) fprintf(stderr, "c3: %016llX\n", cnt->c3);
172 fprintf(stderr, "aperf: %016llX\n", cnt->aperf); 172 if (cnt->c6) fprintf(stderr, "c6: %016llX\n", cnt->c6);
173 fprintf(stderr, "pc2: %016llX\n", cnt->pc2); 173 if (cnt->c7) fprintf(stderr, "c7: %016llX\n", cnt->c7);
174 fprintf(stderr, "pc3: %016llX\n", cnt->pc3); 174 if (cnt->aperf) fprintf(stderr, "aperf: %016llX\n", cnt->aperf);
175 fprintf(stderr, "pc6: %016llX\n", cnt->pc6); 175 if (cnt->pc2) fprintf(stderr, "pc2: %016llX\n", cnt->pc2);
176 fprintf(stderr, "pc7: %016llX\n", cnt->pc7); 176 if (cnt->pc3) fprintf(stderr, "pc3: %016llX\n", cnt->pc3);
177 fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr); 177 if (cnt->pc6) fprintf(stderr, "pc6: %016llX\n", cnt->pc6);
178 if (cnt->pc7) fprintf(stderr, "pc7: %016llX\n", cnt->pc7);
179 if (cnt->extra_msr) fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr);
178} 180}
179 181
180void dump_list(struct counters *cnt) 182void dump_list(struct counters *cnt)
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("..");
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 8d02ccb10c59..8b4c2535b266 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -42,6 +42,7 @@ $default{"BISECT_MANUAL"} = 0;
42$default{"BISECT_SKIP"} = 1; 42$default{"BISECT_SKIP"} = 1;
43$default{"SUCCESS_LINE"} = "login:"; 43$default{"SUCCESS_LINE"} = "login:";
44$default{"DETECT_TRIPLE_FAULT"} = 1; 44$default{"DETECT_TRIPLE_FAULT"} = 1;
45$default{"NO_INSTALL"} = 0;
45$default{"BOOTED_TIMEOUT"} = 1; 46$default{"BOOTED_TIMEOUT"} = 1;
46$default{"DIE_ON_FAILURE"} = 1; 47$default{"DIE_ON_FAILURE"} = 1;
47$default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND"; 48$default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND";
@@ -84,6 +85,7 @@ my $grub_number;
84my $target; 85my $target;
85my $make; 86my $make;
86my $post_install; 87my $post_install;
88my $no_install;
87my $noclean; 89my $noclean;
88my $minconfig; 90my $minconfig;
89my $start_minconfig; 91my $start_minconfig;
@@ -115,6 +117,7 @@ my $timeout;
115my $booted_timeout; 117my $booted_timeout;
116my $detect_triplefault; 118my $detect_triplefault;
117my $console; 119my $console;
120my $reboot_success_line;
118my $success_line; 121my $success_line;
119my $stop_after_success; 122my $stop_after_success;
120my $stop_after_failure; 123my $stop_after_failure;
@@ -130,6 +133,12 @@ my %config_help;
130my %variable; 133my %variable;
131my %force_config; 134my %force_config;
132 135
136# do not force reboots on config problems
137my $no_reboot = 1;
138
139# default variables that can be used
140chomp ($variable{"PWD"} = `pwd`);
141
133$config_help{"MACHINE"} = << "EOF" 142$config_help{"MACHINE"} = << "EOF"
134 The machine hostname that you will test. 143 The machine hostname that you will test.
135EOF 144EOF
@@ -241,6 +250,7 @@ sub read_yn {
241 250
242sub get_ktest_config { 251sub get_ktest_config {
243 my ($config) = @_; 252 my ($config) = @_;
253 my $ans;
244 254
245 return if (defined($opt{$config})); 255 return if (defined($opt{$config}));
246 256
@@ -254,16 +264,17 @@ sub get_ktest_config {
254 if (defined($default{$config})) { 264 if (defined($default{$config})) {
255 print "\[$default{$config}\] "; 265 print "\[$default{$config}\] ";
256 } 266 }
257 $entered_configs{$config} = <STDIN>; 267 $ans = <STDIN>;
258 $entered_configs{$config} =~ s/^\s*(.*\S)\s*$/$1/; 268 $ans =~ s/^\s*(.*\S)\s*$/$1/;
259 if ($entered_configs{$config} =~ /^\s*$/) { 269 if ($ans =~ /^\s*$/) {
260 if ($default{$config}) { 270 if ($default{$config}) {
261 $entered_configs{$config} = $default{$config}; 271 $ans = $default{$config};
262 } else { 272 } else {
263 print "Your answer can not be blank\n"; 273 print "Your answer can not be blank\n";
264 next; 274 next;
265 } 275 }
266 } 276 }
277 $entered_configs{$config} = process_variables($ans);
267 last; 278 last;
268 } 279 }
269} 280}
@@ -298,7 +309,7 @@ sub get_ktest_configs {
298} 309}
299 310
300sub process_variables { 311sub process_variables {
301 my ($value) = @_; 312 my ($value, $remove_undef) = @_;
302 my $retval = ""; 313 my $retval = "";
303 314
304 # We want to check for '\', and it is just easier 315 # We want to check for '\', and it is just easier
@@ -316,6 +327,10 @@ sub process_variables {
316 $retval = "$retval$begin"; 327 $retval = "$retval$begin";
317 if (defined($variable{$var})) { 328 if (defined($variable{$var})) {
318 $retval = "$retval$variable{$var}"; 329 $retval = "$retval$variable{$var}";
330 } elsif (defined($remove_undef) && $remove_undef) {
331 # for if statements, any variable that is not defined,
332 # we simple convert to 0
333 $retval = "${retval}0";
319 } else { 334 } else {
320 # put back the origin piece. 335 # put back the origin piece.
321 $retval = "$retval\$\{$var\}"; 336 $retval = "$retval\$\{$var\}";
@@ -331,10 +346,17 @@ sub process_variables {
331} 346}
332 347
333sub set_value { 348sub set_value {
334 my ($lvalue, $rvalue) = @_; 349 my ($lvalue, $rvalue, $override, $overrides, $name) = @_;
335 350
336 if (defined($opt{$lvalue})) { 351 if (defined($opt{$lvalue})) {
337 die "Error: Option $lvalue defined more than once!\n"; 352 if (!$override || defined(${$overrides}{$lvalue})) {
353 my $extra = "";
354 if ($override) {
355 $extra = "In the same override section!\n";
356 }
357 die "$name: $.: Option $lvalue defined more than once!\n$extra";
358 }
359 ${$overrides}{$lvalue} = $rvalue;
338 } 360 }
339 if ($rvalue =~ /^\s*$/) { 361 if ($rvalue =~ /^\s*$/) {
340 delete $opt{$lvalue}; 362 delete $opt{$lvalue};
@@ -355,86 +377,274 @@ sub set_variable {
355 } 377 }
356} 378}
357 379
358sub read_config { 380sub process_compare {
359 my ($config) = @_; 381 my ($lval, $cmp, $rval) = @_;
382
383 # remove whitespace
384
385 $lval =~ s/^\s*//;
386 $lval =~ s/\s*$//;
387
388 $rval =~ s/^\s*//;
389 $rval =~ s/\s*$//;
390
391 if ($cmp eq "==") {
392 return $lval eq $rval;
393 } elsif ($cmp eq "!=") {
394 return $lval ne $rval;
395 }
396
397 my $statement = "$lval $cmp $rval";
398 my $ret = eval $statement;
399
400 # $@ stores error of eval
401 if ($@) {
402 return -1;
403 }
404
405 return $ret;
406}
407
408sub value_defined {
409 my ($val) = @_;
410
411 return defined($variable{$2}) ||
412 defined($opt{$2});
413}
414
415my $d = 0;
416sub process_expression {
417 my ($name, $val) = @_;
418
419 my $c = $d++;
420
421 while ($val =~ s/\(([^\(]*?)\)/\&\&\&\&VAL\&\&\&\&/) {
422 my $express = $1;
423
424 if (process_expression($name, $express)) {
425 $val =~ s/\&\&\&\&VAL\&\&\&\&/ 1 /;
426 } else {
427 $val =~ s/\&\&\&\&VAL\&\&\&\&/ 0 /;
428 }
429 }
430
431 $d--;
432 my $OR = "\\|\\|";
433 my $AND = "\\&\\&";
434
435 while ($val =~ s/^(.*?)($OR|$AND)//) {
436 my $express = $1;
437 my $op = $2;
438
439 if (process_expression($name, $express)) {
440 if ($op eq "||") {
441 return 1;
442 }
443 } else {
444 if ($op eq "&&") {
445 return 0;
446 }
447 }
448 }
449
450 if ($val =~ /(.*)(==|\!=|>=|<=|>|<)(.*)/) {
451 my $ret = process_compare($1, $2, $3);
452 if ($ret < 0) {
453 die "$name: $.: Unable to process comparison\n";
454 }
455 return $ret;
456 }
457
458 if ($val =~ /^\s*(NOT\s*)?DEFINED\s+(\S+)\s*$/) {
459 if (defined $1) {
460 return !value_defined($2);
461 } else {
462 return value_defined($2);
463 }
464 }
465
466 if ($val =~ /^\s*0\s*$/) {
467 return 0;
468 } elsif ($val =~ /^\s*\d+\s*$/) {
469 return 1;
470 }
471
472 die ("$name: $.: Undefined content $val in if statement\n");
473}
474
475sub process_if {
476 my ($name, $value) = @_;
360 477
361 open(IN, $config) || die "can't read file $config"; 478 # Convert variables and replace undefined ones with 0
479 my $val = process_variables($value, 1);
480 my $ret = process_expression $name, $val;
481
482 return $ret;
483}
484
485sub __read_config {
486 my ($config, $current_test_num) = @_;
487
488 my $in;
489 open($in, $config) || die "can't read file $config";
362 490
363 my $name = $config; 491 my $name = $config;
364 $name =~ s,.*/(.*),$1,; 492 $name =~ s,.*/(.*),$1,;
365 493
366 my $test_num = 0; 494 my $test_num = $$current_test_num;
367 my $default = 1; 495 my $default = 1;
368 my $repeat = 1; 496 my $repeat = 1;
369 my $num_tests_set = 0; 497 my $num_tests_set = 0;
370 my $skip = 0; 498 my $skip = 0;
371 my $rest; 499 my $rest;
500 my $line;
372 my $test_case = 0; 501 my $test_case = 0;
502 my $if = 0;
503 my $if_set = 0;
504 my $override = 0;
373 505
374 while (<IN>) { 506 my %overrides;
507
508 while (<$in>) {
375 509
376 # ignore blank lines and comments 510 # ignore blank lines and comments
377 next if (/^\s*$/ || /\s*\#/); 511 next if (/^\s*$/ || /\s*\#/);
378 512
379 if (/^\s*TEST_START(.*)/) { 513 if (/^\s*(TEST_START|DEFAULTS)\b(.*)/) {
380 514
381 $rest = $1; 515 my $type = $1;
516 $rest = $2;
517 $line = $2;
382 518
383 if ($num_tests_set) { 519 my $old_test_num;
384 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n"; 520 my $old_repeat;
385 } 521 $override = 0;
522
523 if ($type eq "TEST_START") {
386 524
387 my $old_test_num = $test_num; 525 if ($num_tests_set) {
388 my $old_repeat = $repeat; 526 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
527 }
389 528
390 $test_num += $repeat; 529 $old_test_num = $test_num;
391 $default = 0; 530 $old_repeat = $repeat;
392 $repeat = 1;
393 531
394 if ($rest =~ /\s+SKIP(.*)/) { 532 $test_num += $repeat;
395 $rest = $1; 533 $default = 0;
534 $repeat = 1;
535 } else {
536 $default = 1;
537 }
538
539 # If SKIP is anywhere in the line, the command will be skipped
540 if ($rest =~ s/\s+SKIP\b//) {
396 $skip = 1; 541 $skip = 1;
397 } else { 542 } else {
398 $test_case = 1; 543 $test_case = 1;
399 $skip = 0; 544 $skip = 0;
400 } 545 }
401 546
402 if ($rest =~ /\s+ITERATE\s+(\d+)(.*)$/) { 547 if ($rest =~ s/\sELSE\b//) {
403 $repeat = $1; 548 if (!$if) {
404 $rest = $2; 549 die "$name: $.: ELSE found with out matching IF section\n$_";
405 $repeat_tests{"$test_num"} = $repeat; 550 }
551 $if = 0;
552
553 if ($if_set) {
554 $skip = 1;
555 } else {
556 $skip = 0;
557 }
406 } 558 }
407 559
408 if ($rest =~ /\s+SKIP(.*)/) { 560 if ($rest =~ s/\sIF\s+(.*)//) {
409 $rest = $1; 561 if (process_if($name, $1)) {
410 $skip = 1; 562 $if_set = 1;
563 } else {
564 $skip = 1;
565 }
566 $if = 1;
567 } else {
568 $if = 0;
569 $if_set = 0;
411 } 570 }
412 571
413 if ($rest !~ /^\s*$/) { 572 if (!$skip) {
414 die "$name: $.: Gargbage found after TEST_START\n$_"; 573 if ($type eq "TEST_START") {
574 if ($rest =~ s/\s+ITERATE\s+(\d+)//) {
575 $repeat = $1;
576 $repeat_tests{"$test_num"} = $repeat;
577 }
578 } elsif ($rest =~ s/\sOVERRIDE\b//) {
579 # DEFAULT only
580 $override = 1;
581 # Clear previous overrides
582 %overrides = ();
583 }
584 }
585
586 if (!$skip && $rest !~ /^\s*$/) {
587 die "$name: $.: Gargbage found after $type\n$_";
415 } 588 }
416 589
417 if ($skip) { 590 if ($skip && $type eq "TEST_START") {
418 $test_num = $old_test_num; 591 $test_num = $old_test_num;
419 $repeat = $old_repeat; 592 $repeat = $old_repeat;
420 } 593 }
421 594
422 } elsif (/^\s*DEFAULTS(.*)$/) { 595 } elsif (/^\s*ELSE\b(.*)$/) {
423 $default = 1; 596 if (!$if) {
424 597 die "$name: $.: ELSE found with out matching IF section\n$_";
598 }
425 $rest = $1; 599 $rest = $1;
426 600 if ($if_set) {
427 if ($rest =~ /\s+SKIP(.*)/) {
428 $rest = $1;
429 $skip = 1; 601 $skip = 1;
602 $rest = "";
430 } else { 603 } else {
431 $skip = 0; 604 $skip = 0;
605
606 if ($rest =~ /\sIF\s+(.*)/) {
607 # May be a ELSE IF section.
608 if (!process_if($name, $1)) {
609 $skip = 1;
610 }
611 $rest = "";
612 } else {
613 $if = 0;
614 }
432 } 615 }
433 616
434 if ($rest !~ /^\s*$/) { 617 if ($rest !~ /^\s*$/) {
435 die "$name: $.: Gargbage found after DEFAULTS\n$_"; 618 die "$name: $.: Gargbage found after DEFAULTS\n$_";
436 } 619 }
437 620
621 } elsif (/^\s*INCLUDE\s+(\S+)/) {
622
623 next if ($skip);
624
625 if (!$default) {
626 die "$name: $.: INCLUDE can only be done in default sections\n$_";
627 }
628
629 my $file = process_variables($1);
630
631 if ($file !~ m,^/,) {
632 # check the path of the config file first
633 if ($config =~ m,(.*)/,) {
634 if (-f "$1/$file") {
635 $file = "$1/$file";
636 }
637 }
638 }
639
640 if ( ! -r $file ) {
641 die "$name: $.: Can't read file $file\n$_";
642 }
643
644 if (__read_config($file, \$test_num)) {
645 $test_case = 1;
646 }
647
438 } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) { 648 } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) {
439 649
440 next if ($skip); 650 next if ($skip);
@@ -460,10 +670,10 @@ sub read_config {
460 } 670 }
461 671
462 if ($default || $lvalue =~ /\[\d+\]$/) { 672 if ($default || $lvalue =~ /\[\d+\]$/) {
463 set_value($lvalue, $rvalue); 673 set_value($lvalue, $rvalue, $override, \%overrides, $name);
464 } else { 674 } else {
465 my $val = "$lvalue\[$test_num\]"; 675 my $val = "$lvalue\[$test_num\]";
466 set_value($val, $rvalue); 676 set_value($val, $rvalue, $override, \%overrides, $name);
467 677
468 if ($repeat > 1) { 678 if ($repeat > 1) {
469 $repeats{$val} = $repeat; 679 $repeats{$val} = $repeat;
@@ -490,13 +700,26 @@ sub read_config {
490 } 700 }
491 } 701 }
492 702
493 close(IN);
494
495 if ($test_num) { 703 if ($test_num) {
496 $test_num += $repeat - 1; 704 $test_num += $repeat - 1;
497 $opt{"NUM_TESTS"} = $test_num; 705 $opt{"NUM_TESTS"} = $test_num;
498 } 706 }
499 707
708 close($in);
709
710 $$current_test_num = $test_num;
711
712 return $test_case;
713}
714
715sub read_config {
716 my ($config) = @_;
717
718 my $test_case;
719 my $test_num = 0;
720
721 $test_case = __read_config $config, \$test_num;
722
500 # make sure we have all mandatory configs 723 # make sure we have all mandatory configs
501 get_ktest_configs; 724 get_ktest_configs;
502 725
@@ -524,6 +747,18 @@ sub __eval_option {
524 # Add space to evaluate the character before $ 747 # Add space to evaluate the character before $
525 $option = " $option"; 748 $option = " $option";
526 my $retval = ""; 749 my $retval = "";
750 my $repeated = 0;
751 my $parent = 0;
752
753 foreach my $test (keys %repeat_tests) {
754 if ($i >= $test &&
755 $i < $test + $repeat_tests{$test}) {
756
757 $repeated = 1;
758 $parent = $test;
759 last;
760 }
761 }
527 762
528 while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { 763 while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) {
529 my $start = $1; 764 my $start = $1;
@@ -537,10 +772,14 @@ sub __eval_option {
537 # otherwise see if the default OPT (without [$i]) exists. 772 # otherwise see if the default OPT (without [$i]) exists.
538 773
539 my $o = "$var\[$i\]"; 774 my $o = "$var\[$i\]";
775 my $parento = "$var\[$parent\]";
540 776
541 if (defined($opt{$o})) { 777 if (defined($opt{$o})) {
542 $o = $opt{$o}; 778 $o = $opt{$o};
543 $retval = "$retval$o"; 779 $retval = "$retval$o";
780 } elsif ($repeated && defined($opt{$parento})) {
781 $o = $opt{$parento};
782 $retval = "$retval$o";
544 } elsif (defined($opt{$var})) { 783 } elsif (defined($opt{$var})) {
545 $o = $opt{$var}; 784 $o = $opt{$var};
546 $retval = "$retval$o"; 785 $retval = "$retval$o";
@@ -603,8 +842,20 @@ sub doprint {
603} 842}
604 843
605sub run_command; 844sub run_command;
845sub start_monitor;
846sub end_monitor;
847sub wait_for_monitor;
606 848
607sub reboot { 849sub reboot {
850 my ($time) = @_;
851
852 if (defined($time)) {
853 start_monitor;
854 # flush out current monitor
855 # May contain the reboot success line
856 wait_for_monitor 1;
857 }
858
608 # try to reboot normally 859 # try to reboot normally
609 if (run_command $reboot) { 860 if (run_command $reboot) {
610 if (defined($powercycle_after_reboot)) { 861 if (defined($powercycle_after_reboot)) {
@@ -615,12 +866,17 @@ sub reboot {
615 # nope? power cycle it. 866 # nope? power cycle it.
616 run_command "$power_cycle"; 867 run_command "$power_cycle";
617 } 868 }
869
870 if (defined($time)) {
871 wait_for_monitor($time, $reboot_success_line);
872 end_monitor;
873 }
618} 874}
619 875
620sub do_not_reboot { 876sub do_not_reboot {
621 my $i = $iteration; 877 my $i = $iteration;
622 878
623 return $test_type eq "build" || 879 return $test_type eq "build" || $no_reboot ||
624 ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") || 880 ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") ||
625 ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build"); 881 ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build");
626} 882}
@@ -693,16 +949,29 @@ sub end_monitor {
693} 949}
694 950
695sub wait_for_monitor { 951sub wait_for_monitor {
696 my ($time) = @_; 952 my ($time, $stop) = @_;
953 my $full_line = "";
697 my $line; 954 my $line;
955 my $booted = 0;
698 956
699 doprint "** Wait for monitor to settle down **\n"; 957 doprint "** Wait for monitor to settle down **\n";
700 958
701 # read the monitor and wait for the system to calm down 959 # read the monitor and wait for the system to calm down
702 do { 960 while (!$booted) {
703 $line = wait_for_input($monitor_fp, $time); 961 $line = wait_for_input($monitor_fp, $time);
704 print "$line" if (defined($line)); 962 last if (!defined($line));
705 } while (defined($line)); 963 print "$line";
964 $full_line .= $line;
965
966 if (defined($stop) && $full_line =~ /$stop/) {
967 doprint "wait for monitor detected $stop\n";
968 $booted = 1;
969 }
970
971 if ($line =~ /\n/) {
972 $full_line = "";
973 }
974 }
706 print "** Monitor flushed **\n"; 975 print "** Monitor flushed **\n";
707} 976}
708 977
@@ -719,10 +988,7 @@ sub fail {
719 # no need to reboot for just building. 988 # no need to reboot for just building.
720 if (!do_not_reboot) { 989 if (!do_not_reboot) {
721 doprint "REBOOTING\n"; 990 doprint "REBOOTING\n";
722 reboot; 991 reboot $sleep_time;
723 start_monitor;
724 wait_for_monitor $sleep_time;
725 end_monitor;
726 } 992 }
727 993
728 my $name = ""; 994 my $name = "";
@@ -854,9 +1120,12 @@ sub get_grub_index {
854 open(IN, "$ssh_grub |") 1120 open(IN, "$ssh_grub |")
855 or die "unable to get menu.lst"; 1121 or die "unable to get menu.lst";
856 1122
1123 my $found = 0;
1124
857 while (<IN>) { 1125 while (<IN>) {
858 if (/^\s*title\s+$grub_menu\s*$/) { 1126 if (/^\s*title\s+$grub_menu\s*$/) {
859 $grub_number++; 1127 $grub_number++;
1128 $found = 1;
860 last; 1129 last;
861 } elsif (/^\s*title\s/) { 1130 } elsif (/^\s*title\s/) {
862 $grub_number++; 1131 $grub_number++;
@@ -865,7 +1134,7 @@ sub get_grub_index {
865 close(IN); 1134 close(IN);
866 1135
867 die "Could not find '$grub_menu' in /boot/grub/menu on $machine" 1136 die "Could not find '$grub_menu' in /boot/grub/menu on $machine"
868 if ($grub_number < 0); 1137 if (!$found);
869 doprint "$grub_number\n"; 1138 doprint "$grub_number\n";
870} 1139}
871 1140
@@ -902,7 +1171,8 @@ sub wait_for_input
902 1171
903sub reboot_to { 1172sub reboot_to {
904 if ($reboot_type eq "grub") { 1173 if ($reboot_type eq "grub") {
905 run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch && reboot)'"; 1174 run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'";
1175 reboot;
906 return; 1176 return;
907 } 1177 }
908 1178
@@ -1083,6 +1353,8 @@ sub do_post_install {
1083 1353
1084sub install { 1354sub install {
1085 1355
1356 return if ($no_install);
1357
1086 run_scp "$outputdir/$build_target", "$target_image" or 1358 run_scp "$outputdir/$build_target", "$target_image" or
1087 dodie "failed to copy image"; 1359 dodie "failed to copy image";
1088 1360
@@ -1140,6 +1412,11 @@ sub get_version {
1140} 1412}
1141 1413
1142sub start_monitor_and_boot { 1414sub start_monitor_and_boot {
1415 # Make sure the stable kernel has finished booting
1416 start_monitor;
1417 wait_for_monitor 5;
1418 end_monitor;
1419
1143 get_grub_index; 1420 get_grub_index;
1144 get_version; 1421 get_version;
1145 install; 1422 install;
@@ -1250,6 +1527,10 @@ sub build {
1250 1527
1251 unlink $buildlog; 1528 unlink $buildlog;
1252 1529
1530 # Failed builds should not reboot the target
1531 my $save_no_reboot = $no_reboot;
1532 $no_reboot = 1;
1533
1253 if (defined($pre_build)) { 1534 if (defined($pre_build)) {
1254 my $ret = run_command $pre_build; 1535 my $ret = run_command $pre_build;
1255 if (!$ret && defined($pre_build_die) && 1536 if (!$ret && defined($pre_build_die) &&
@@ -1272,15 +1553,15 @@ sub build {
1272 # allow for empty configs 1553 # allow for empty configs
1273 run_command "touch $output_config"; 1554 run_command "touch $output_config";
1274 1555
1275 run_command "mv $output_config $outputdir/config_temp" or 1556 if (!$noclean) {
1276 dodie "moving .config"; 1557 run_command "mv $output_config $outputdir/config_temp" or
1558 dodie "moving .config";
1277 1559
1278 if (!$noclean && !run_command "$make mrproper") { 1560 run_command "$make mrproper" or dodie "make mrproper";
1279 dodie "make mrproper";
1280 }
1281 1561
1282 run_command "mv $outputdir/config_temp $output_config" or 1562 run_command "mv $outputdir/config_temp $output_config" or
1283 dodie "moving config_temp"; 1563 dodie "moving config_temp";
1564 }
1284 1565
1285 } elsif (!$noclean) { 1566 } elsif (!$noclean) {
1286 unlink "$output_config"; 1567 unlink "$output_config";
@@ -1318,10 +1599,15 @@ sub build {
1318 1599
1319 if (!$build_ret) { 1600 if (!$build_ret) {
1320 # bisect may need this to pass 1601 # bisect may need this to pass
1321 return 0 if ($in_bisect); 1602 if ($in_bisect) {
1603 $no_reboot = $save_no_reboot;
1604 return 0;
1605 }
1322 fail "failed build" and return 0; 1606 fail "failed build" and return 0;
1323 } 1607 }
1324 1608
1609 $no_reboot = $save_no_reboot;
1610
1325 return 1; 1611 return 1;
1326} 1612}
1327 1613
@@ -1356,10 +1642,7 @@ sub success {
1356 1642
1357 if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) { 1643 if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) {
1358 doprint "Reboot and wait $sleep_time seconds\n"; 1644 doprint "Reboot and wait $sleep_time seconds\n";
1359 reboot; 1645 reboot $sleep_time;
1360 start_monitor;
1361 wait_for_monitor $sleep_time;
1362 end_monitor;
1363 } 1646 }
1364} 1647}
1365 1648
@@ -1500,10 +1783,7 @@ sub run_git_bisect {
1500 1783
1501sub bisect_reboot { 1784sub bisect_reboot {
1502 doprint "Reboot and sleep $bisect_sleep_time seconds\n"; 1785 doprint "Reboot and sleep $bisect_sleep_time seconds\n";
1503 reboot; 1786 reboot $bisect_sleep_time;
1504 start_monitor;
1505 wait_for_monitor $bisect_sleep_time;
1506 end_monitor;
1507} 1787}
1508 1788
1509# returns 1 on success, 0 on failure, -1 on skip 1789# returns 1 on success, 0 on failure, -1 on skip
@@ -2066,10 +2346,7 @@ sub config_bisect {
2066 2346
2067sub patchcheck_reboot { 2347sub patchcheck_reboot {
2068 doprint "Reboot and sleep $patchcheck_sleep_time seconds\n"; 2348 doprint "Reboot and sleep $patchcheck_sleep_time seconds\n";
2069 reboot; 2349 reboot $patchcheck_sleep_time;
2070 start_monitor;
2071 wait_for_monitor $patchcheck_sleep_time;
2072 end_monitor;
2073} 2350}
2074 2351
2075sub patchcheck { 2352sub patchcheck {
@@ -2178,12 +2455,31 @@ sub patchcheck {
2178} 2455}
2179 2456
2180my %depends; 2457my %depends;
2458my %depcount;
2181my $iflevel = 0; 2459my $iflevel = 0;
2182my @ifdeps; 2460my @ifdeps;
2183 2461
2184# prevent recursion 2462# prevent recursion
2185my %read_kconfigs; 2463my %read_kconfigs;
2186 2464
2465sub add_dep {
2466 # $config depends on $dep
2467 my ($config, $dep) = @_;
2468
2469 if (defined($depends{$config})) {
2470 $depends{$config} .= " " . $dep;
2471 } else {
2472 $depends{$config} = $dep;
2473 }
2474
2475 # record the number of configs depending on $dep
2476 if (defined $depcount{$dep}) {
2477 $depcount{$dep}++;
2478 } else {
2479 $depcount{$dep} = 1;
2480 }
2481}
2482
2187# taken from streamline_config.pl 2483# taken from streamline_config.pl
2188sub read_kconfig { 2484sub read_kconfig {
2189 my ($kconfig) = @_; 2485 my ($kconfig) = @_;
@@ -2230,30 +2526,19 @@ sub read_kconfig {
2230 $config = $2; 2526 $config = $2;
2231 2527
2232 for (my $i = 0; $i < $iflevel; $i++) { 2528 for (my $i = 0; $i < $iflevel; $i++) {
2233 if ($i) { 2529 add_dep $config, $ifdeps[$i];
2234 $depends{$config} .= " " . $ifdeps[$i];
2235 } else {
2236 $depends{$config} = $ifdeps[$i];
2237 }
2238 $state = "DEP";
2239 } 2530 }
2240 2531
2241 # collect the depends for the config 2532 # collect the depends for the config
2242 } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) { 2533 } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) {
2243 2534
2244 if (defined($depends{$1})) { 2535 add_dep $config, $1;
2245 $depends{$config} .= " " . $1;
2246 } else {
2247 $depends{$config} = $1;
2248 }
2249 2536
2250 # Get the configs that select this config 2537 # Get the configs that select this config
2251 } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) { 2538 } elsif ($state eq "NEW" && /^\s*select\s+(\S+)/) {
2252 if (defined($depends{$1})) { 2539
2253 $depends{$1} .= " " . $config; 2540 # selected by depends on config
2254 } else { 2541 add_dep $1, $config;
2255 $depends{$1} = $config;
2256 }
2257 2542
2258 # Check for if statements 2543 # Check for if statements
2259 } elsif (/^if\s+(.*\S)\s*$/) { 2544 } elsif (/^if\s+(.*\S)\s*$/) {
@@ -2365,11 +2650,18 @@ sub make_new_config {
2365 close OUT; 2650 close OUT;
2366} 2651}
2367 2652
2653sub chomp_config {
2654 my ($config) = @_;
2655
2656 $config =~ s/CONFIG_//;
2657
2658 return $config;
2659}
2660
2368sub get_depends { 2661sub get_depends {
2369 my ($dep) = @_; 2662 my ($dep) = @_;
2370 2663
2371 my $kconfig = $dep; 2664 my $kconfig = chomp_config $dep;
2372 $kconfig =~ s/CONFIG_//;
2373 2665
2374 $dep = $depends{"$kconfig"}; 2666 $dep = $depends{"$kconfig"};
2375 2667
@@ -2419,8 +2711,7 @@ sub test_this_config {
2419 return undef; 2711 return undef;
2420 } 2712 }
2421 2713
2422 my $kconfig = $config; 2714 my $kconfig = chomp_config $config;
2423 $kconfig =~ s/CONFIG_//;
2424 2715
2425 # Test dependencies first 2716 # Test dependencies first
2426 if (defined($depends{"$kconfig"})) { 2717 if (defined($depends{"$kconfig"})) {
@@ -2510,6 +2801,14 @@ sub make_min_config {
2510 2801
2511 my @config_keys = keys %min_configs; 2802 my @config_keys = keys %min_configs;
2512 2803
2804 # All configs need a depcount
2805 foreach my $config (@config_keys) {
2806 my $kconfig = chomp_config $config;
2807 if (!defined $depcount{$kconfig}) {
2808 $depcount{$kconfig} = 0;
2809 }
2810 }
2811
2513 # Remove anything that was set by the make allnoconfig 2812 # Remove anything that was set by the make allnoconfig
2514 # we shouldn't need them as they get set for us anyway. 2813 # we shouldn't need them as they get set for us anyway.
2515 foreach my $config (@config_keys) { 2814 foreach my $config (@config_keys) {
@@ -2548,8 +2847,13 @@ sub make_min_config {
2548 # Now disable each config one by one and do a make oldconfig 2847 # Now disable each config one by one and do a make oldconfig
2549 # till we find a config that changes our list. 2848 # till we find a config that changes our list.
2550 2849
2551 # Put configs that did not modify the config at the end.
2552 my @test_configs = keys %min_configs; 2850 my @test_configs = keys %min_configs;
2851
2852 # Sort keys by who is most dependent on
2853 @test_configs = sort { $depcount{chomp_config($b)} <=> $depcount{chomp_config($a)} }
2854 @test_configs ;
2855
2856 # Put configs that did not modify the config at the end.
2553 my $reset = 1; 2857 my $reset = 1;
2554 for (my $i = 0; $i < $#test_configs; $i++) { 2858 for (my $i = 0; $i < $#test_configs; $i++) {
2555 if (!defined($nochange_config{$test_configs[0]})) { 2859 if (!defined($nochange_config{$test_configs[0]})) {
@@ -2659,10 +2963,7 @@ sub make_min_config {
2659 } 2963 }
2660 2964
2661 doprint "Reboot and wait $sleep_time seconds\n"; 2965 doprint "Reboot and wait $sleep_time seconds\n";
2662 reboot; 2966 reboot $sleep_time;
2663 start_monitor;
2664 wait_for_monitor $sleep_time;
2665 end_monitor;
2666 } 2967 }
2667 2968
2668 success $i; 2969 success $i;
@@ -2783,6 +3084,9 @@ sub set_test_option {
2783# First we need to do is the builds 3084# First we need to do is the builds
2784for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { 3085for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
2785 3086
3087 # Do not reboot on failing test options
3088 $no_reboot = 1;
3089
2786 $iteration = $i; 3090 $iteration = $i;
2787 3091
2788 my $makecmd = set_test_option("MAKE_CMD", $i); 3092 my $makecmd = set_test_option("MAKE_CMD", $i);
@@ -2811,6 +3115,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
2811 $reboot_type = set_test_option("REBOOT_TYPE", $i); 3115 $reboot_type = set_test_option("REBOOT_TYPE", $i);
2812 $grub_menu = set_test_option("GRUB_MENU", $i); 3116 $grub_menu = set_test_option("GRUB_MENU", $i);
2813 $post_install = set_test_option("POST_INSTALL", $i); 3117 $post_install = set_test_option("POST_INSTALL", $i);
3118 $no_install = set_test_option("NO_INSTALL", $i);
2814 $reboot_script = set_test_option("REBOOT_SCRIPT", $i); 3119 $reboot_script = set_test_option("REBOOT_SCRIPT", $i);
2815 $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i); 3120 $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i);
2816 $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i); 3121 $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i);
@@ -2832,6 +3137,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
2832 $console = set_test_option("CONSOLE", $i); 3137 $console = set_test_option("CONSOLE", $i);
2833 $detect_triplefault = set_test_option("DETECT_TRIPLE_FAULT", $i); 3138 $detect_triplefault = set_test_option("DETECT_TRIPLE_FAULT", $i);
2834 $success_line = set_test_option("SUCCESS_LINE", $i); 3139 $success_line = set_test_option("SUCCESS_LINE", $i);
3140 $reboot_success_line = set_test_option("REBOOT_SUCCESS_LINE", $i);
2835 $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i); 3141 $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i);
2836 $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i); 3142 $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i);
2837 $stop_test_after = set_test_option("STOP_TEST_AFTER", $i); 3143 $stop_test_after = set_test_option("STOP_TEST_AFTER", $i);
@@ -2850,9 +3156,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
2850 3156
2851 chdir $builddir || die "can't change directory to $builddir"; 3157 chdir $builddir || die "can't change directory to $builddir";
2852 3158
2853 if (!-d $tmpdir) { 3159 foreach my $dir ($tmpdir, $outputdir) {
2854 mkpath($tmpdir) or 3160 if (!-d $dir) {
2855 die "can't create $tmpdir"; 3161 mkpath($dir) or
3162 die "can't create $dir";
3163 }
2856 } 3164 }
2857 3165
2858 $ENV{"SSH_USER"} = $ssh_user; 3166 $ENV{"SSH_USER"} = $ssh_user;
@@ -2889,8 +3197,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
2889 $run_type = "ERROR"; 3197 $run_type = "ERROR";
2890 } 3198 }
2891 3199
3200 my $installme = "";
3201 $installme = " no_install" if ($no_install);
3202
2892 doprint "\n\n"; 3203 doprint "\n\n";
2893 doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n"; 3204 doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type$installme\n\n";
2894 3205
2895 unlink $dmesg; 3206 unlink $dmesg;
2896 unlink $buildlog; 3207 unlink $buildlog;
@@ -2911,6 +3222,9 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
2911 die "failed to checkout $checkout"; 3222 die "failed to checkout $checkout";
2912 } 3223 }
2913 3224
3225 $no_reboot = 0;
3226
3227
2914 if ($test_type eq "bisect") { 3228 if ($test_type eq "bisect") {
2915 bisect $i; 3229 bisect $i;
2916 next; 3230 next;
@@ -2929,6 +3243,13 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
2929 build $build_type or next; 3243 build $build_type or next;
2930 } 3244 }
2931 3245
3246 if ($test_type eq "install") {
3247 get_version;
3248 install;
3249 success $i;
3250 next;
3251 }
3252
2932 if ($test_type ne "build") { 3253 if ($test_type ne "build") {
2933 my $failed = 0; 3254 my $failed = 0;
2934 start_monitor_and_boot or $failed = 1; 3255 start_monitor_and_boot or $failed = 1;
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index b8bcd14b5a4d..dbedfa196727 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -72,6 +72,128 @@
72# the same option name under the same test or as default 72# the same option name under the same test or as default
73# ktest will fail to execute, and no tests will run. 73# ktest will fail to execute, and no tests will run.
74# 74#
75# DEFAULTS OVERRIDE
76#
77# Options defined in the DEFAULTS section can not be duplicated
78# even if they are defined in two different DEFAULT sections.
79# This is done to catch mistakes where an option is added but
80# the previous option was forgotten about and not commented.
81#
82# The OVERRIDE keyword can be added to a section to allow this
83# section to override other DEFAULT sections values that have
84# been defined previously. It will only override options that
85# have been defined before its use. Options defined later
86# in a non override section will still error. The same option
87# can not be defined in the same section even if that section
88# is marked OVERRIDE.
89#
90#
91#
92# Both TEST_START and DEFAULTS sections can also have the IF keyword
93# The value after the IF must evaluate into a 0 or non 0 positive
94# integer, and can use the config variables (explained below).
95#
96# DEFAULTS IF ${IS_X86_32}
97#
98# The above will process the DEFAULTS section if the config
99# variable IS_X86_32 evaluates to a non zero positive integer
100# otherwise if it evaluates to zero, it will act the same
101# as if the SKIP keyword was used.
102#
103# The ELSE keyword can be used directly after a section with
104# a IF statement.
105#
106# TEST_START IF ${RUN_NET_TESTS}
107# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network
108#
109# ELSE
110#
111# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-normal
112#
113#
114# The ELSE keyword can also contain an IF statement to allow multiple
115# if then else sections. But all the sections must be either
116# DEFAULT or TEST_START, they can not be a mixture.
117#
118# TEST_START IF ${RUN_NET_TESTS}
119# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network
120#
121# ELSE IF ${RUN_DISK_TESTS}
122# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-tests
123#
124# ELSE IF ${RUN_CPU_TESTS}
125# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-cpu
126#
127# ELSE
128# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network
129#
130# The if statement may also have comparisons that will and for
131# == and !=, strings may be used for both sides.
132#
133# BOX_TYPE := x86_32
134#
135# DEFAULTS IF ${BOX_TYPE} == x86_32
136# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-32
137# ELSE
138# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-64
139#
140# The DEFINED keyword can be used by the IF statements too.
141# It returns true if the given config variable or option has been defined
142# or false otherwise.
143#
144#
145# DEFAULTS IF DEFINED USE_CC
146# CC := ${USE_CC}
147# ELSE
148# CC := gcc
149#
150#
151# As well as NOT DEFINED.
152#
153# DEFAULTS IF NOT DEFINED MAKE_CMD
154# MAKE_CMD := make ARCH=x86
155#
156#
157# And/or ops (&&,||) may also be used to make complex conditionals.
158#
159# TEST_START IF (DEFINED ALL_TESTS || ${MYTEST} == boottest) && ${MACHINE} == gandalf
160#
161# Notice the use of paranthesis. Without any paranthesis the above would be
162# processed the same as:
163#
164# TEST_START IF DEFINED ALL_TESTS || (${MYTEST} == boottest && ${MACHINE} == gandalf)
165#
166#
167#
168# INCLUDE file
169#
170# The INCLUDE keyword may be used in DEFAULT sections. This will
171# read another config file and process that file as well. The included
172# file can include other files, add new test cases or default
173# statements. Config variables will be passed to these files and changes
174# to config variables will be seen by top level config files. Including
175# a file is processed just like the contents of the file was cut and pasted
176# into the top level file, except, that include files that end with
177# TEST_START sections will have that section ended at the end of
178# the include file. That is, an included file is included followed
179# by another DEFAULT keyword.
180#
181# Unlike other files referenced in this config, the file path does not need
182# to be absolute. If the file does not start with '/', then the directory
183# that the current config file was located in is used. If no config by the
184# given name is found there, then the current directory is searched.
185#
186# INCLUDE myfile
187# DEFAULT
188#
189# is the same as:
190#
191# INCLUDE myfile
192#
193# Note, if the include file does not contain a full path, the file is
194# searched first by the location of the original include file, and then
195# by the location that ktest.pl was executed in.
196#
75 197
76#### Config variables #### 198#### Config variables ####
77# 199#
@@ -253,9 +375,10 @@
253 375
254# The default test type (default test) 376# The default test type (default test)
255# The test types may be: 377# The test types may be:
256# build - only build the kernel, do nothing else 378# build - only build the kernel, do nothing else
257# boot - build and boot the kernel 379# install - build and install, but do nothing else (does not reboot)
258# test - build, boot and if TEST is set, run the test script 380# boot - build, install, and boot the kernel
381# test - build, boot and if TEST is set, run the test script
259# (If TEST is not set, it defaults back to boot) 382# (If TEST is not set, it defaults back to boot)
260# bisect - Perform a bisect on the kernel (see BISECT_TYPE below) 383# bisect - Perform a bisect on the kernel (see BISECT_TYPE below)
261# patchcheck - Do a test on a series of commits in git (see PATCHCHECK below) 384# patchcheck - Do a test on a series of commits in git (see PATCHCHECK below)
@@ -293,6 +416,13 @@
293# or on some systems: 416# or on some systems:
294#POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION 417#POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
295 418
419# If for some reason you just want to boot the kernel and you do not
420# want the test to install anything new. For example, you may just want
421# to boot test the same kernel over and over and do not want to go through
422# the hassle of installing anything, you can set this option to 1
423# (default 0)
424#NO_INSTALL = 1
425
296# If there is a script that you require to run before the build is done 426# If there is a script that you require to run before the build is done
297# you can specify it with PRE_BUILD. 427# you can specify it with PRE_BUILD.
298# 428#
@@ -415,6 +545,14 @@
415# (default "login:") 545# (default "login:")
416#SUCCESS_LINE = login: 546#SUCCESS_LINE = login:
417 547
548# To speed up between reboots, defining a line that the
549# default kernel produces that represents that the default
550# kernel has successfully booted and can be used to pass
551# a new test kernel to it. Otherwise ktest.pl will wait till
552# SLEEP_TIME to continue.
553# (default undefined)
554#REBOOT_SUCCESS_LINE = login:
555
418# In case the console constantly fills the screen, having 556# In case the console constantly fills the screen, having
419# a specified time to stop the test after success is recommended. 557# a specified time to stop the test after success is recommended.
420# (in seconds) 558# (in seconds)
@@ -480,6 +618,8 @@
480# another test. If a reboot to the reliable kernel happens, 618# another test. If a reboot to the reliable kernel happens,
481# we wait SLEEP_TIME for the console to stop producing output 619# we wait SLEEP_TIME for the console to stop producing output
482# before starting the next test. 620# before starting the next test.
621#
622# You can speed up reboot times even more by setting REBOOT_SUCCESS_LINE.
483# (default 60) 623# (default 60)
484#SLEEP_TIME = 60 624#SLEEP_TIME = 60
485 625