aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/callchain.c45
-rw-r--r--tools/perf/util/callchain.h11
-rw-r--r--tools/perf/util/dso.c279
-rw-r--r--tools/perf/util/dso.h50
-rw-r--r--tools/perf/util/dwarf-aux.c7
-rw-r--r--tools/perf/util/event.c57
-rw-r--r--tools/perf/util/event.h7
-rw-r--r--tools/perf/util/evsel.c5
-rw-r--r--tools/perf/util/hist.c490
-rw-r--r--tools/perf/util/hist.h58
-rw-r--r--tools/perf/util/machine.c4
-rw-r--r--tools/perf/util/map.c4
-rw-r--r--tools/perf/util/map.h4
-rw-r--r--tools/perf/util/perf_regs.c10
-rw-r--r--tools/perf/util/perf_regs.h4
-rw-r--r--tools/perf/util/probe-event.c13
-rw-r--r--tools/perf/util/probe-finder.c15
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c2
-rw-r--r--tools/perf/util/sort.c214
-rw-r--r--tools/perf/util/sort.h22
-rw-r--r--tools/perf/util/symbol.c11
-rw-r--r--tools/perf/util/symbol.h1
-rw-r--r--tools/perf/util/unwind-libunwind.c2
-rw-r--r--tools/perf/util/util.c1
-rw-r--r--tools/perf/util/util.h1
26 files changed, 1185 insertions, 133 deletions
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 9a42382b3921..48b6d3f50012 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -616,7 +616,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
616 if (sample->callchain == NULL) 616 if (sample->callchain == NULL)
617 return 0; 617 return 0;
618 618
619 if (symbol_conf.use_callchain || sort__has_parent) { 619 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
620 sort__has_parent) {
620 return machine__resolve_callchain(al->machine, evsel, al->thread, 621 return machine__resolve_callchain(al->machine, evsel, al->thread,
621 sample, parent, al, max_stack); 622 sample, parent, al, max_stack);
622 } 623 }
@@ -629,3 +630,45 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *samp
629 return 0; 630 return 0;
630 return callchain_append(he->callchain, &callchain_cursor, sample->period); 631 return callchain_append(he->callchain, &callchain_cursor, sample->period);
631} 632}
633
634int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
635 bool hide_unresolved)
636{
637 al->map = node->map;
638 al->sym = node->sym;
639 if (node->map)
640 al->addr = node->map->map_ip(node->map, node->ip);
641 else
642 al->addr = node->ip;
643
644 if (al->sym == NULL) {
645 if (hide_unresolved)
646 return 0;
647 if (al->map == NULL)
648 goto out;
649 }
650
651 if (al->map->groups == &al->machine->kmaps) {
652 if (machine__is_host(al->machine)) {
653 al->cpumode = PERF_RECORD_MISC_KERNEL;
654 al->level = 'k';
655 } else {
656 al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
657 al->level = 'g';
658 }
659 } else {
660 if (machine__is_host(al->machine)) {
661 al->cpumode = PERF_RECORD_MISC_USER;
662 al->level = '.';
663 } else if (perf_guest) {
664 al->cpumode = PERF_RECORD_MISC_GUEST_USER;
665 al->level = 'u';
666 } else {
667 al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
668 al->level = 'H';
669 }
670 }
671
672out:
673 return 1;
674}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index bde2b0cc24cf..8f84423a75da 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -162,7 +162,18 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
162 struct perf_evsel *evsel, struct addr_location *al, 162 struct perf_evsel *evsel, struct addr_location *al,
163 int max_stack); 163 int max_stack);
164int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); 164int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample);
165int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
166 bool hide_unresolved);
165 167
166extern const char record_callchain_help[]; 168extern const char record_callchain_help[];
167int parse_callchain_report_opt(const char *arg); 169int parse_callchain_report_opt(const char *arg);
170
171static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
172 struct callchain_cursor *src)
173{
174 *dest = *src;
175
176 dest->first = src->curr;
177 dest->nr -= src->pos;
178}
168#endif /* __PERF_CALLCHAIN_H */ 179#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 64453d63b971..819f10414f08 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1,3 +1,6 @@
1#include <asm/bug.h>
2#include <sys/time.h>
3#include <sys/resource.h>
1#include "symbol.h" 4#include "symbol.h"
2#include "dso.h" 5#include "dso.h"
3#include "machine.h" 6#include "machine.h"
@@ -136,7 +139,48 @@ int dso__read_binary_type_filename(const struct dso *dso,
136 return ret; 139 return ret;
137} 140}
138 141
139static int open_dso(struct dso *dso, struct machine *machine) 142/*
143 * Global list of open DSOs and the counter.
144 */
145static LIST_HEAD(dso__data_open);
146static long dso__data_open_cnt;
147
148static void dso__list_add(struct dso *dso)
149{
150 list_add_tail(&dso->data.open_entry, &dso__data_open);
151 dso__data_open_cnt++;
152}
153
154static void dso__list_del(struct dso *dso)
155{
156 list_del(&dso->data.open_entry);
157 WARN_ONCE(dso__data_open_cnt <= 0,
158 "DSO data fd counter out of bounds.");
159 dso__data_open_cnt--;
160}
161
162static void close_first_dso(void);
163
164static int do_open(char *name)
165{
166 int fd;
167
168 do {
169 fd = open(name, O_RDONLY);
170 if (fd >= 0)
171 return fd;
172
173 pr_debug("dso open failed, mmap: %s\n", strerror(errno));
174 if (!dso__data_open_cnt || errno != EMFILE)
175 break;
176
177 close_first_dso();
178 } while (1);
179
180 return -1;
181}
182
183static int __open_dso(struct dso *dso, struct machine *machine)
140{ 184{
141 int fd; 185 int fd;
142 char *root_dir = (char *)""; 186 char *root_dir = (char *)"";
@@ -154,11 +198,130 @@ static int open_dso(struct dso *dso, struct machine *machine)
154 return -EINVAL; 198 return -EINVAL;
155 } 199 }
156 200
157 fd = open(name, O_RDONLY); 201 fd = do_open(name);
158 free(name); 202 free(name);
159 return fd; 203 return fd;
160} 204}
161 205
206static void check_data_close(void);
207
208/**
209 * dso_close - Open DSO data file
210 * @dso: dso object
211 *
212 * Open @dso's data file descriptor and updates
213 * list/count of open DSO objects.
214 */
215static int open_dso(struct dso *dso, struct machine *machine)
216{
217 int fd = __open_dso(dso, machine);
218
219 if (fd > 0) {
220 dso__list_add(dso);
221 /*
222 * Check if we crossed the allowed number
223 * of opened DSOs and close one if needed.
224 */
225 check_data_close();
226 }
227
228 return fd;
229}
230
231static void close_data_fd(struct dso *dso)
232{
233 if (dso->data.fd >= 0) {
234 close(dso->data.fd);
235 dso->data.fd = -1;
236 dso->data.file_size = 0;
237 dso__list_del(dso);
238 }
239}
240
241/**
242 * dso_close - Close DSO data file
243 * @dso: dso object
244 *
245 * Close @dso's data file descriptor and updates
246 * list/count of open DSO objects.
247 */
248static void close_dso(struct dso *dso)
249{
250 close_data_fd(dso);
251}
252
253static void close_first_dso(void)
254{
255 struct dso *dso;
256
257 dso = list_first_entry(&dso__data_open, struct dso, data.open_entry);
258 close_dso(dso);
259}
260
261static rlim_t get_fd_limit(void)
262{
263 struct rlimit l;
264 rlim_t limit = 0;
265
266 /* Allow half of the current open fd limit. */
267 if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
268 if (l.rlim_cur == RLIM_INFINITY)
269 limit = l.rlim_cur;
270 else
271 limit = l.rlim_cur / 2;
272 } else {
273 pr_err("failed to get fd limit\n");
274 limit = 1;
275 }
276
277 return limit;
278}
279
280static bool may_cache_fd(void)
281{
282 static rlim_t limit;
283
284 if (!limit)
285 limit = get_fd_limit();
286
287 if (limit == RLIM_INFINITY)
288 return true;
289
290 return limit > (rlim_t) dso__data_open_cnt;
291}
292
293/*
294 * Check and close LRU dso if we crossed allowed limit
295 * for opened dso file descriptors. The limit is half
296 * of the RLIMIT_NOFILE files opened.
297*/
298static void check_data_close(void)
299{
300 bool cache_fd = may_cache_fd();
301
302 if (!cache_fd)
303 close_first_dso();
304}
305
306/**
307 * dso__data_close - Close DSO data file
308 * @dso: dso object
309 *
310 * External interface to close @dso's data file descriptor.
311 */
312void dso__data_close(struct dso *dso)
313{
314 close_dso(dso);
315}
316
317/**
318 * dso__data_fd - Get dso's data file descriptor
319 * @dso: dso object
320 * @machine: machine object
321 *
322 * External interface to find dso's file, open it and
323 * returns file descriptor.
324 */
162int dso__data_fd(struct dso *dso, struct machine *machine) 325int dso__data_fd(struct dso *dso, struct machine *machine)
163{ 326{
164 enum dso_binary_type binary_type_data[] = { 327 enum dso_binary_type binary_type_data[] = {
@@ -168,8 +331,13 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
168 }; 331 };
169 int i = 0; 332 int i = 0;
170 333
171 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) 334 if (dso->data.fd >= 0)
172 return open_dso(dso, machine); 335 return dso->data.fd;
336
337 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
338 dso->data.fd = open_dso(dso, machine);
339 return dso->data.fd;
340 }
173 341
174 do { 342 do {
175 int fd; 343 int fd;
@@ -178,7 +346,7 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
178 346
179 fd = open_dso(dso, machine); 347 fd = open_dso(dso, machine);
180 if (fd >= 0) 348 if (fd >= 0)
181 return fd; 349 return dso->data.fd = fd;
182 350
183 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); 351 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
184 352
@@ -260,16 +428,10 @@ dso_cache__memcpy(struct dso_cache *cache, u64 offset,
260} 428}
261 429
262static ssize_t 430static ssize_t
263dso_cache__read(struct dso *dso, struct machine *machine, 431dso_cache__read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
264 u64 offset, u8 *data, ssize_t size)
265{ 432{
266 struct dso_cache *cache; 433 struct dso_cache *cache;
267 ssize_t ret; 434 ssize_t ret;
268 int fd;
269
270 fd = dso__data_fd(dso, machine);
271 if (fd < 0)
272 return -1;
273 435
274 do { 436 do {
275 u64 cache_offset; 437 u64 cache_offset;
@@ -283,16 +445,16 @@ dso_cache__read(struct dso *dso, struct machine *machine,
283 cache_offset = offset & DSO__DATA_CACHE_MASK; 445 cache_offset = offset & DSO__DATA_CACHE_MASK;
284 ret = -EINVAL; 446 ret = -EINVAL;
285 447
286 if (-1 == lseek(fd, cache_offset, SEEK_SET)) 448 if (-1 == lseek(dso->data.fd, cache_offset, SEEK_SET))
287 break; 449 break;
288 450
289 ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); 451 ret = read(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE);
290 if (ret <= 0) 452 if (ret <= 0)
291 break; 453 break;
292 454
293 cache->offset = cache_offset; 455 cache->offset = cache_offset;
294 cache->size = ret; 456 cache->size = ret;
295 dso_cache__insert(&dso->cache, cache); 457 dso_cache__insert(&dso->data.cache, cache);
296 458
297 ret = dso_cache__memcpy(cache, offset, data, size); 459 ret = dso_cache__memcpy(cache, offset, data, size);
298 460
@@ -301,24 +463,27 @@ dso_cache__read(struct dso *dso, struct machine *machine,
301 if (ret <= 0) 463 if (ret <= 0)
302 free(cache); 464 free(cache);
303 465
304 close(fd);
305 return ret; 466 return ret;
306} 467}
307 468
308static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, 469static ssize_t dso_cache_read(struct dso *dso, u64 offset,
309 u64 offset, u8 *data, ssize_t size) 470 u8 *data, ssize_t size)
310{ 471{
311 struct dso_cache *cache; 472 struct dso_cache *cache;
312 473
313 cache = dso_cache__find(&dso->cache, offset); 474 cache = dso_cache__find(&dso->data.cache, offset);
314 if (cache) 475 if (cache)
315 return dso_cache__memcpy(cache, offset, data, size); 476 return dso_cache__memcpy(cache, offset, data, size);
316 else 477 else
317 return dso_cache__read(dso, machine, offset, data, size); 478 return dso_cache__read(dso, offset, data, size);
318} 479}
319 480
320ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 481/*
321 u64 offset, u8 *data, ssize_t size) 482 * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks
483 * in the rb_tree. Any read to already cached data is served
484 * by cached data.
485 */
486static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
322{ 487{
323 ssize_t r = 0; 488 ssize_t r = 0;
324 u8 *p = data; 489 u8 *p = data;
@@ -326,7 +491,7 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
326 do { 491 do {
327 ssize_t ret; 492 ssize_t ret;
328 493
329 ret = dso_cache_read(dso, machine, offset, p, size); 494 ret = dso_cache_read(dso, offset, p, size);
330 if (ret < 0) 495 if (ret < 0)
331 return ret; 496 return ret;
332 497
@@ -346,6 +511,67 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
346 return r; 511 return r;
347} 512}
348 513
514static int data_file_size(struct dso *dso)
515{
516 struct stat st;
517
518 if (!dso->data.file_size) {
519 if (fstat(dso->data.fd, &st)) {
520 pr_err("dso mmap failed, fstat: %s\n", strerror(errno));
521 return -1;
522 }
523 dso->data.file_size = st.st_size;
524 }
525
526 return 0;
527}
528
529static ssize_t data_read_offset(struct dso *dso, u64 offset,
530 u8 *data, ssize_t size)
531{
532 if (data_file_size(dso))
533 return -1;
534
535 /* Check the offset sanity. */
536 if (offset > dso->data.file_size)
537 return -1;
538
539 if (offset + size < offset)
540 return -1;
541
542 return cached_read(dso, offset, data, size);
543}
544
545/**
546 * dso__data_read_offset - Read data from dso file offset
547 * @dso: dso object
548 * @machine: machine object
549 * @offset: file offset
550 * @data: buffer to store data
551 * @size: size of the @data buffer
552 *
553 * External interface to read data from dso file offset. Open
554 * dso data file and use cached_read to get the data.
555 */
556ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
557 u64 offset, u8 *data, ssize_t size)
558{
559 if (dso__data_fd(dso, machine) < 0)
560 return -1;
561
562 return data_read_offset(dso, offset, data, size);
563}
564
565/**
566 * dso__data_read_addr - Read data from dso address
567 * @dso: dso object
568 * @machine: machine object
569 * @add: virtual memory address
570 * @data: buffer to store data
571 * @size: size of the @data buffer
572 *
573 * External interface to read data from dso address.
574 */
349ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 575ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
350 struct machine *machine, u64 addr, 576 struct machine *machine, u64 addr,
351 u8 *data, ssize_t size) 577 u8 *data, ssize_t size)
@@ -473,7 +699,8 @@ struct dso *dso__new(const char *name)
473 dso__set_short_name(dso, dso->name, false); 699 dso__set_short_name(dso, dso->name, false);
474 for (i = 0; i < MAP__NR_TYPES; ++i) 700 for (i = 0; i < MAP__NR_TYPES; ++i)
475 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 701 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
476 dso->cache = RB_ROOT; 702 dso->data.cache = RB_ROOT;
703 dso->data.fd = -1;
477 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 704 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
478 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; 705 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
479 dso->loaded = 0; 706 dso->loaded = 0;
@@ -485,6 +712,7 @@ struct dso *dso__new(const char *name)
485 dso->kernel = DSO_TYPE_USER; 712 dso->kernel = DSO_TYPE_USER;
486 dso->needs_swap = DSO_SWAP__UNSET; 713 dso->needs_swap = DSO_SWAP__UNSET;
487 INIT_LIST_HEAD(&dso->node); 714 INIT_LIST_HEAD(&dso->node);
715 INIT_LIST_HEAD(&dso->data.open_entry);
488 } 716 }
489 717
490 return dso; 718 return dso;
@@ -506,7 +734,8 @@ void dso__delete(struct dso *dso)
506 dso->long_name_allocated = false; 734 dso->long_name_allocated = false;
507 } 735 }
508 736
509 dso_cache__free(&dso->cache); 737 dso__data_close(dso);
738 dso_cache__free(&dso->data.cache);
510 dso__free_a2l(dso); 739 dso__free_a2l(dso);
511 zfree(&dso->symsrc_filename); 740 zfree(&dso->symsrc_filename);
512 free(dso); 741 free(dso);
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 38efe95a7fdd..ad553ba257bf 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -76,7 +76,6 @@ struct dso {
76 struct list_head node; 76 struct list_head node;
77 struct rb_root symbols[MAP__NR_TYPES]; 77 struct rb_root symbols[MAP__NR_TYPES];
78 struct rb_root symbol_names[MAP__NR_TYPES]; 78 struct rb_root symbol_names[MAP__NR_TYPES];
79 struct rb_root cache;
80 void *a2l; 79 void *a2l;
81 char *symsrc_filename; 80 char *symsrc_filename;
82 unsigned int a2l_fails; 81 unsigned int a2l_fails;
@@ -99,6 +98,15 @@ struct dso {
99 const char *long_name; 98 const char *long_name;
100 u16 long_name_len; 99 u16 long_name_len;
101 u16 short_name_len; 100 u16 short_name_len;
101
102 /* dso data file */
103 struct {
104 struct rb_root cache;
105 int fd;
106 size_t file_size;
107 struct list_head open_entry;
108 } data;
109
102 char name[0]; 110 char name[0];
103}; 111};
104 112
@@ -141,7 +149,47 @@ char dso__symtab_origin(const struct dso *dso);
141int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, 149int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
142 char *root_dir, char *filename, size_t size); 150 char *root_dir, char *filename, size_t size);
143 151
152/*
153 * The dso__data_* external interface provides following functions:
154 * dso__data_fd
155 * dso__data_close
156 * dso__data_read_offset
157 * dso__data_read_addr
158 *
159 * Please refer to the dso.c object code for each function and
160 * arguments documentation. Following text tries to explain the
161 * dso file descriptor caching.
162 *
163 * The dso__data* interface allows caching of opened file descriptors
164 * to speed up the dso data accesses. The idea is to leave the file
165 * descriptor opened ideally for the whole life of the dso object.
166 *
167 * The current usage of the dso__data_* interface is as follows:
168 *
169 * Get DSO's fd:
170 * int fd = dso__data_fd(dso, machine);
171 * USE 'fd' SOMEHOW
172 *
173 * Read DSO's data:
174 * n = dso__data_read_offset(dso_0, &machine, 0, buf, BUFSIZE);
175 * n = dso__data_read_addr(dso_0, &machine, 0, buf, BUFSIZE);
176 *
177 * Eventually close DSO's fd:
178 * dso__data_close(dso);
179 *
180 * It is not necessary to close the DSO object data file. Each time new
181 * DSO data file is opened, the limit (RLIMIT_NOFILE/2) is checked. Once
182 * it is crossed, the oldest opened DSO object is closed.
183 *
184 * The dso__delete function calls close_dso function to ensure the
185 * data file descriptor gets closed/unmapped before the dso object
186 * is freed.
187 *
188 * TODO
189*/
144int dso__data_fd(struct dso *dso, struct machine *machine); 190int dso__data_fd(struct dso *dso, struct machine *machine);
191void dso__data_close(struct dso *dso);
192
145ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 193ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
146 u64 offset, u8 *data, ssize_t size); 194 u64 offset, u8 *data, ssize_t size);
147ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 195ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 7defd77105d0..cc66c4049e09 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -747,14 +747,17 @@ struct __find_variable_param {
747static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) 747static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
748{ 748{
749 struct __find_variable_param *fvp = data; 749 struct __find_variable_param *fvp = data;
750 Dwarf_Attribute attr;
750 int tag; 751 int tag;
751 752
752 tag = dwarf_tag(die_mem); 753 tag = dwarf_tag(die_mem);
753 if ((tag == DW_TAG_formal_parameter || 754 if ((tag == DW_TAG_formal_parameter ||
754 tag == DW_TAG_variable) && 755 tag == DW_TAG_variable) &&
755 die_compare_name(die_mem, fvp->name)) 756 die_compare_name(die_mem, fvp->name) &&
757 /* Does the DIE have location information or external instance? */
758 (dwarf_attr(die_mem, DW_AT_external, &attr) ||
759 dwarf_attr(die_mem, DW_AT_location, &attr)))
756 return DIE_FIND_CB_END; 760 return DIE_FIND_CB_END;
757
758 if (dwarf_haspc(die_mem, fvp->addr)) 761 if (dwarf_haspc(die_mem, fvp->addr))
759 return DIE_FIND_CB_CONTINUE; 762 return DIE_FIND_CB_CONTINUE;
760 else 763 else
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 65795b835b39..d0281bdfa582 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,4 +1,5 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include <sys/mman.h>
2#include "event.h" 3#include "event.h"
3#include "debug.h" 4#include "debug.h"
4#include "hist.h" 5#include "hist.h"
@@ -178,13 +179,14 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
178 return -1; 179 return -1;
179 } 180 }
180 181
181 event->header.type = PERF_RECORD_MMAP; 182 event->header.type = PERF_RECORD_MMAP2;
182 183
183 while (1) { 184 while (1) {
184 char bf[BUFSIZ]; 185 char bf[BUFSIZ];
185 char prot[5]; 186 char prot[5];
186 char execname[PATH_MAX]; 187 char execname[PATH_MAX];
187 char anonstr[] = "//anon"; 188 char anonstr[] = "//anon";
189 unsigned int ino;
188 size_t size; 190 size_t size;
189 ssize_t n; 191 ssize_t n;
190 192
@@ -195,15 +197,20 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
195 strcpy(execname, ""); 197 strcpy(execname, "");
196 198
197 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 199 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
198 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", 200 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
199 &event->mmap.start, &event->mmap.len, prot, 201 &event->mmap2.start, &event->mmap2.len, prot,
200 &event->mmap.pgoff, 202 &event->mmap2.pgoff, &event->mmap2.maj,
201 execname); 203 &event->mmap2.min,
204 &ino, execname);
205
202 /* 206 /*
203 * Anon maps don't have the execname. 207 * Anon maps don't have the execname.
204 */ 208 */
205 if (n < 4) 209 if (n < 7)
206 continue; 210 continue;
211
212 event->mmap2.ino = (u64)ino;
213
207 /* 214 /*
208 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 215 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
209 */ 216 */
@@ -212,6 +219,21 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
212 else 219 else
213 event->header.misc = PERF_RECORD_MISC_GUEST_USER; 220 event->header.misc = PERF_RECORD_MISC_GUEST_USER;
214 221
222 /* map protection and flags bits */
223 event->mmap2.prot = 0;
224 event->mmap2.flags = 0;
225 if (prot[0] == 'r')
226 event->mmap2.prot |= PROT_READ;
227 if (prot[1] == 'w')
228 event->mmap2.prot |= PROT_WRITE;
229 if (prot[2] == 'x')
230 event->mmap2.prot |= PROT_EXEC;
231
232 if (prot[3] == 's')
233 event->mmap2.flags |= MAP_SHARED;
234 else
235 event->mmap2.flags |= MAP_PRIVATE;
236
215 if (prot[2] != 'x') { 237 if (prot[2] != 'x') {
216 if (!mmap_data || prot[0] != 'r') 238 if (!mmap_data || prot[0] != 'r')
217 continue; 239 continue;
@@ -223,15 +245,15 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
223 strcpy(execname, anonstr); 245 strcpy(execname, anonstr);
224 246
225 size = strlen(execname) + 1; 247 size = strlen(execname) + 1;
226 memcpy(event->mmap.filename, execname, size); 248 memcpy(event->mmap2.filename, execname, size);
227 size = PERF_ALIGN(size, sizeof(u64)); 249 size = PERF_ALIGN(size, sizeof(u64));
228 event->mmap.len -= event->mmap.start; 250 event->mmap2.len -= event->mmap.start;
229 event->mmap.header.size = (sizeof(event->mmap) - 251 event->mmap2.header.size = (sizeof(event->mmap2) -
230 (sizeof(event->mmap.filename) - size)); 252 (sizeof(event->mmap2.filename) - size));
231 memset(event->mmap.filename + size, 0, machine->id_hdr_size); 253 memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
232 event->mmap.header.size += machine->id_hdr_size; 254 event->mmap2.header.size += machine->id_hdr_size;
233 event->mmap.pid = tgid; 255 event->mmap2.pid = tgid;
234 event->mmap.tid = pid; 256 event->mmap2.tid = pid;
235 257
236 if (process(tool, event, &synth_sample, machine) != 0) { 258 if (process(tool, event, &synth_sample, machine) != 0) {
237 rc = -1; 259 rc = -1;
@@ -612,12 +634,15 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
612size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) 634size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
613{ 635{
614 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 636 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
615 " %02x:%02x %"PRIu64" %"PRIu64"]: %c %s\n", 637 " %02x:%02x %"PRIu64" %"PRIu64"]: %c%c%c%c %s\n",
616 event->mmap2.pid, event->mmap2.tid, event->mmap2.start, 638 event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
617 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, 639 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
618 event->mmap2.min, event->mmap2.ino, 640 event->mmap2.min, event->mmap2.ino,
619 event->mmap2.ino_generation, 641 event->mmap2.ino_generation,
620 (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x', 642 (event->mmap2.prot & PROT_READ) ? 'r' : '-',
643 (event->mmap2.prot & PROT_WRITE) ? 'w' : '-',
644 (event->mmap2.prot & PROT_EXEC) ? 'x' : '-',
645 (event->mmap2.flags & MAP_SHARED) ? 's' : 'p',
621 event->mmap2.filename); 646 event->mmap2.filename);
622} 647}
623 648
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index d970232cb270..e5dd40addb30 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -7,6 +7,7 @@
7#include "../perf.h" 7#include "../perf.h"
8#include "map.h" 8#include "map.h"
9#include "build-id.h" 9#include "build-id.h"
10#include "perf_regs.h"
10 11
11struct mmap_event { 12struct mmap_event {
12 struct perf_event_header header; 13 struct perf_event_header header;
@@ -27,6 +28,8 @@ struct mmap2_event {
27 u32 min; 28 u32 min;
28 u64 ino; 29 u64 ino;
29 u64 ino_generation; 30 u64 ino_generation;
31 u32 prot;
32 u32 flags;
30 char filename[PATH_MAX]; 33 char filename[PATH_MAX];
31}; 34};
32 35
@@ -87,6 +90,10 @@ struct regs_dump {
87 u64 abi; 90 u64 abi;
88 u64 mask; 91 u64 mask;
89 u64 *regs; 92 u64 *regs;
93
94 /* Cached values/mask filled by first register access. */
95 u64 cache_regs[PERF_REGS_MAX];
96 u64 cache_mask;
90}; 97};
91 98
92struct stack_dump { 99struct stack_dump {
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 5c28d82b76c4..8606175fe1e8 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -589,10 +589,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
589 } 589 }
590 590
591 /* 591 /*
592 * We default some events to a 1 default interval. But keep 592 * We default some events to have a default interval. But keep
593 * it a weak assumption overridable by the user. 593 * it a weak assumption overridable by the user.
594 */ 594 */
595 if (!attr->sample_period || (opts->user_freq != UINT_MAX && 595 if (!attr->sample_period || (opts->user_freq != UINT_MAX ||
596 opts->user_interval != ULLONG_MAX)) { 596 opts->user_interval != ULLONG_MAX)) {
597 if (opts->freq) { 597 if (opts->freq) {
598 perf_evsel__set_sample_bit(evsel, PERIOD); 598 perf_evsel__set_sample_bit(evsel, PERIOD);
@@ -659,6 +659,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
659 perf_evsel__set_sample_bit(evsel, WEIGHT); 659 perf_evsel__set_sample_bit(evsel, WEIGHT);
660 660
661 attr->mmap = track; 661 attr->mmap = track;
662 attr->mmap2 = track && !perf_missing_features.mmap2;
662 attr->comm = track; 663 attr->comm = track;
663 664
664 if (opts->sample_transaction) 665 if (opts->sample_transaction)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index b262b44b7a65..30df6187ee02 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -4,6 +4,7 @@
4#include "session.h" 4#include "session.h"
5#include "sort.h" 5#include "sort.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "annotate.h"
7#include <math.h> 8#include <math.h>
8 9
9static bool hists__filter_entry_by_dso(struct hists *hists, 10static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -127,6 +128,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
127 + unresolved_col_width + 2; 128 + unresolved_col_width + 2;
128 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 129 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
129 symlen); 130 symlen);
131 hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
132 symlen + 1);
130 } else { 133 } else {
131 symlen = unresolved_col_width + 4 + 2; 134 symlen = unresolved_col_width + 4 + 2;
132 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 135 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
@@ -231,6 +234,8 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
231 return true; 234 return true;
232 235
233 he_stat__decay(&he->stat); 236 he_stat__decay(&he->stat);
237 if (symbol_conf.cumulate_callchain)
238 he_stat__decay(he->stat_acc);
234 239
235 diff = prev_period - he->stat.period; 240 diff = prev_period - he->stat.period;
236 241
@@ -276,14 +281,31 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
276 * histogram, sorted on item, collects periods 281 * histogram, sorted on item, collects periods
277 */ 282 */
278 283
279static struct hist_entry *hist_entry__new(struct hist_entry *template) 284static struct hist_entry *hist_entry__new(struct hist_entry *template,
285 bool sample_self)
280{ 286{
281 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; 287 size_t callchain_size = 0;
282 struct hist_entry *he = zalloc(sizeof(*he) + callchain_size); 288 struct hist_entry *he;
289
290 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain)
291 callchain_size = sizeof(struct callchain_root);
292
293 he = zalloc(sizeof(*he) + callchain_size);
283 294
284 if (he != NULL) { 295 if (he != NULL) {
285 *he = *template; 296 *he = *template;
286 297
298 if (symbol_conf.cumulate_callchain) {
299 he->stat_acc = malloc(sizeof(he->stat));
300 if (he->stat_acc == NULL) {
301 free(he);
302 return NULL;
303 }
304 memcpy(he->stat_acc, &he->stat, sizeof(he->stat));
305 if (!sample_self)
306 memset(&he->stat, 0, sizeof(he->stat));
307 }
308
287 if (he->ms.map) 309 if (he->ms.map)
288 he->ms.map->referenced = true; 310 he->ms.map->referenced = true;
289 311
@@ -295,6 +317,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
295 */ 317 */
296 he->branch_info = malloc(sizeof(*he->branch_info)); 318 he->branch_info = malloc(sizeof(*he->branch_info));
297 if (he->branch_info == NULL) { 319 if (he->branch_info == NULL) {
320 free(he->stat_acc);
298 free(he); 321 free(he);
299 return NULL; 322 return NULL;
300 } 323 }
@@ -333,7 +356,8 @@ static u8 symbol__parent_filter(const struct symbol *parent)
333 356
334static struct hist_entry *add_hist_entry(struct hists *hists, 357static struct hist_entry *add_hist_entry(struct hists *hists,
335 struct hist_entry *entry, 358 struct hist_entry *entry,
336 struct addr_location *al) 359 struct addr_location *al,
360 bool sample_self)
337{ 361{
338 struct rb_node **p; 362 struct rb_node **p;
339 struct rb_node *parent = NULL; 363 struct rb_node *parent = NULL;
@@ -357,7 +381,10 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
357 cmp = hist_entry__cmp(he, entry); 381 cmp = hist_entry__cmp(he, entry);
358 382
359 if (!cmp) { 383 if (!cmp) {
360 he_stat__add_period(&he->stat, period, weight); 384 if (sample_self)
385 he_stat__add_period(&he->stat, period, weight);
386 if (symbol_conf.cumulate_callchain)
387 he_stat__add_period(he->stat_acc, period, weight);
361 388
362 /* 389 /*
363 * This mem info was allocated from sample__resolve_mem 390 * This mem info was allocated from sample__resolve_mem
@@ -385,14 +412,17 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
385 p = &(*p)->rb_right; 412 p = &(*p)->rb_right;
386 } 413 }
387 414
388 he = hist_entry__new(entry); 415 he = hist_entry__new(entry, sample_self);
389 if (!he) 416 if (!he)
390 return NULL; 417 return NULL;
391 418
392 rb_link_node(&he->rb_node_in, parent, p); 419 rb_link_node(&he->rb_node_in, parent, p);
393 rb_insert_color(&he->rb_node_in, hists->entries_in); 420 rb_insert_color(&he->rb_node_in, hists->entries_in);
394out: 421out:
395 he_stat__add_cpumode_period(&he->stat, al->cpumode, period); 422 if (sample_self)
423 he_stat__add_cpumode_period(&he->stat, al->cpumode, period);
424 if (symbol_conf.cumulate_callchain)
425 he_stat__add_cpumode_period(he->stat_acc, al->cpumode, period);
396 return he; 426 return he;
397} 427}
398 428
@@ -401,7 +431,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
401 struct symbol *sym_parent, 431 struct symbol *sym_parent,
402 struct branch_info *bi, 432 struct branch_info *bi,
403 struct mem_info *mi, 433 struct mem_info *mi,
404 u64 period, u64 weight, u64 transaction) 434 u64 period, u64 weight, u64 transaction,
435 bool sample_self)
405{ 436{
406 struct hist_entry entry = { 437 struct hist_entry entry = {
407 .thread = al->thread, 438 .thread = al->thread,
@@ -410,9 +441,10 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
410 .map = al->map, 441 .map = al->map,
411 .sym = al->sym, 442 .sym = al->sym,
412 }, 443 },
413 .cpu = al->cpu, 444 .cpu = al->cpu,
414 .ip = al->addr, 445 .cpumode = al->cpumode,
415 .level = al->level, 446 .ip = al->addr,
447 .level = al->level,
416 .stat = { 448 .stat = {
417 .nr_events = 1, 449 .nr_events = 1,
418 .period = period, 450 .period = period,
@@ -426,7 +458,429 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
426 .transaction = transaction, 458 .transaction = transaction,
427 }; 459 };
428 460
429 return add_hist_entry(hists, &entry, al); 461 return add_hist_entry(hists, &entry, al, sample_self);
462}
463
464static int
465iter_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
466 struct addr_location *al __maybe_unused)
467{
468 return 0;
469}
470
471static int
472iter_add_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
473 struct addr_location *al __maybe_unused)
474{
475 return 0;
476}
477
478static int
479iter_prepare_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
480{
481 struct perf_sample *sample = iter->sample;
482 struct mem_info *mi;
483
484 mi = sample__resolve_mem(sample, al);
485 if (mi == NULL)
486 return -ENOMEM;
487
488 iter->priv = mi;
489 return 0;
490}
491
492static int
493iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
494{
495 u64 cost;
496 struct mem_info *mi = iter->priv;
497 struct hist_entry *he;
498
499 if (mi == NULL)
500 return -EINVAL;
501
502 cost = iter->sample->weight;
503 if (!cost)
504 cost = 1;
505
506 /*
507 * must pass period=weight in order to get the correct
508 * sorting from hists__collapse_resort() which is solely
509 * based on periods. We want sorting be done on nr_events * weight
510 * and this is indirectly achieved by passing period=weight here
511 * and the he_stat__add_period() function.
512 */
513 he = __hists__add_entry(&iter->evsel->hists, al, iter->parent, NULL, mi,
514 cost, cost, 0, true);
515 if (!he)
516 return -ENOMEM;
517
518 iter->he = he;
519 return 0;
520}
521
522static int
523iter_finish_mem_entry(struct hist_entry_iter *iter,
524 struct addr_location *al __maybe_unused)
525{
526 struct perf_evsel *evsel = iter->evsel;
527 struct hist_entry *he = iter->he;
528 int err = -EINVAL;
529
530 if (he == NULL)
531 goto out;
532
533 hists__inc_nr_samples(&evsel->hists, he->filtered);
534
535 err = hist_entry__append_callchain(he, iter->sample);
536
537out:
538 /*
539 * We don't need to free iter->priv (mem_info) here since
540 * the mem info was either already freed in add_hist_entry() or
541 * passed to a new hist entry by hist_entry__new().
542 */
543 iter->priv = NULL;
544
545 iter->he = NULL;
546 return err;
547}
548
549static int
550iter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
551{
552 struct branch_info *bi;
553 struct perf_sample *sample = iter->sample;
554
555 bi = sample__resolve_bstack(sample, al);
556 if (!bi)
557 return -ENOMEM;
558
559 iter->curr = 0;
560 iter->total = sample->branch_stack->nr;
561
562 iter->priv = bi;
563 return 0;
564}
565
566static int
567iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused,
568 struct addr_location *al __maybe_unused)
569{
570 /* to avoid calling callback function */
571 iter->he = NULL;
572
573 return 0;
574}
575
576static int
577iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
578{
579 struct branch_info *bi = iter->priv;
580 int i = iter->curr;
581
582 if (bi == NULL)
583 return 0;
584
585 if (iter->curr >= iter->total)
586 return 0;
587
588 al->map = bi[i].to.map;
589 al->sym = bi[i].to.sym;
590 al->addr = bi[i].to.addr;
591 return 1;
592}
593
594static int
595iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
596{
597 struct branch_info *bi;
598 struct perf_evsel *evsel = iter->evsel;
599 struct hist_entry *he = NULL;
600 int i = iter->curr;
601 int err = 0;
602
603 bi = iter->priv;
604
605 if (iter->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
606 goto out;
607
608 /*
609 * The report shows the percentage of total branches captured
610 * and not events sampled. Thus we use a pseudo period of 1.
611 */
612 he = __hists__add_entry(&evsel->hists, al, iter->parent, &bi[i], NULL,
613 1, 1, 0, true);
614 if (he == NULL)
615 return -ENOMEM;
616
617 hists__inc_nr_samples(&evsel->hists, he->filtered);
618
619out:
620 iter->he = he;
621 iter->curr++;
622 return err;
623}
624
625static int
626iter_finish_branch_entry(struct hist_entry_iter *iter,
627 struct addr_location *al __maybe_unused)
628{
629 zfree(&iter->priv);
630 iter->he = NULL;
631
632 return iter->curr >= iter->total ? 0 : -1;
633}
634
635static int
636iter_prepare_normal_entry(struct hist_entry_iter *iter __maybe_unused,
637 struct addr_location *al __maybe_unused)
638{
639 return 0;
640}
641
642static int
643iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location *al)
644{
645 struct perf_evsel *evsel = iter->evsel;
646 struct perf_sample *sample = iter->sample;
647 struct hist_entry *he;
648
649 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
650 sample->period, sample->weight,
651 sample->transaction, true);
652 if (he == NULL)
653 return -ENOMEM;
654
655 iter->he = he;
656 return 0;
657}
658
659static int
660iter_finish_normal_entry(struct hist_entry_iter *iter,
661 struct addr_location *al __maybe_unused)
662{
663 struct hist_entry *he = iter->he;
664 struct perf_evsel *evsel = iter->evsel;
665 struct perf_sample *sample = iter->sample;
666
667 if (he == NULL)
668 return 0;
669
670 iter->he = NULL;
671
672 hists__inc_nr_samples(&evsel->hists, he->filtered);
673
674 return hist_entry__append_callchain(he, sample);
675}
676
677static int
678iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused,
679 struct addr_location *al __maybe_unused)
680{
681 struct hist_entry **he_cache;
682
683 callchain_cursor_commit(&callchain_cursor);
684
685 /*
686 * This is for detecting cycles or recursions so that they're
687 * cumulated only one time to prevent entries more than 100%
688 * overhead.
689 */
690 he_cache = malloc(sizeof(*he_cache) * (PERF_MAX_STACK_DEPTH + 1));
691 if (he_cache == NULL)
692 return -ENOMEM;
693
694 iter->priv = he_cache;
695 iter->curr = 0;
696
697 return 0;
698}
699
700static int
701iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
702 struct addr_location *al)
703{
704 struct perf_evsel *evsel = iter->evsel;
705 struct perf_sample *sample = iter->sample;
706 struct hist_entry **he_cache = iter->priv;
707 struct hist_entry *he;
708 int err = 0;
709
710 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
711 sample->period, sample->weight,
712 sample->transaction, true);
713 if (he == NULL)
714 return -ENOMEM;
715
716 iter->he = he;
717 he_cache[iter->curr++] = he;
718
719 callchain_append(he->callchain, &callchain_cursor, sample->period);
720
721 /*
722 * We need to re-initialize the cursor since callchain_append()
723 * advanced the cursor to the end.
724 */
725 callchain_cursor_commit(&callchain_cursor);
726
727 hists__inc_nr_samples(&evsel->hists, he->filtered);
728
729 return err;
730}
731
732static int
733iter_next_cumulative_entry(struct hist_entry_iter *iter,
734 struct addr_location *al)
735{
736 struct callchain_cursor_node *node;
737
738 node = callchain_cursor_current(&callchain_cursor);
739 if (node == NULL)
740 return 0;
741
742 return fill_callchain_info(al, node, iter->hide_unresolved);
743}
744
745static int
746iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
747 struct addr_location *al)
748{
749 struct perf_evsel *evsel = iter->evsel;
750 struct perf_sample *sample = iter->sample;
751 struct hist_entry **he_cache = iter->priv;
752 struct hist_entry *he;
753 struct hist_entry he_tmp = {
754 .cpu = al->cpu,
755 .thread = al->thread,
756 .comm = thread__comm(al->thread),
757 .ip = al->addr,
758 .ms = {
759 .map = al->map,
760 .sym = al->sym,
761 },
762 .parent = iter->parent,
763 };
764 int i;
765 struct callchain_cursor cursor;
766
767 callchain_cursor_snapshot(&cursor, &callchain_cursor);
768
769 callchain_cursor_advance(&callchain_cursor);
770
771 /*
772 * Check if there's duplicate entries in the callchain.
773 * It's possible that it has cycles or recursive calls.
774 */
775 for (i = 0; i < iter->curr; i++) {
776 if (hist_entry__cmp(he_cache[i], &he_tmp) == 0) {
777 /* to avoid calling callback function */
778 iter->he = NULL;
779 return 0;
780 }
781 }
782
783 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
784 sample->period, sample->weight,
785 sample->transaction, false);
786 if (he == NULL)
787 return -ENOMEM;
788
789 iter->he = he;
790 he_cache[iter->curr++] = he;
791
792 callchain_append(he->callchain, &cursor, sample->period);
793 return 0;
794}
795
796static int
797iter_finish_cumulative_entry(struct hist_entry_iter *iter,
798 struct addr_location *al __maybe_unused)
799{
800 zfree(&iter->priv);
801 iter->he = NULL;
802
803 return 0;
804}
805
806const struct hist_iter_ops hist_iter_mem = {
807 .prepare_entry = iter_prepare_mem_entry,
808 .add_single_entry = iter_add_single_mem_entry,
809 .next_entry = iter_next_nop_entry,
810 .add_next_entry = iter_add_next_nop_entry,
811 .finish_entry = iter_finish_mem_entry,
812};
813
814const struct hist_iter_ops hist_iter_branch = {
815 .prepare_entry = iter_prepare_branch_entry,
816 .add_single_entry = iter_add_single_branch_entry,
817 .next_entry = iter_next_branch_entry,
818 .add_next_entry = iter_add_next_branch_entry,
819 .finish_entry = iter_finish_branch_entry,
820};
821
822const struct hist_iter_ops hist_iter_normal = {
823 .prepare_entry = iter_prepare_normal_entry,
824 .add_single_entry = iter_add_single_normal_entry,
825 .next_entry = iter_next_nop_entry,
826 .add_next_entry = iter_add_next_nop_entry,
827 .finish_entry = iter_finish_normal_entry,
828};
829
830const struct hist_iter_ops hist_iter_cumulative = {
831 .prepare_entry = iter_prepare_cumulative_entry,
832 .add_single_entry = iter_add_single_cumulative_entry,
833 .next_entry = iter_next_cumulative_entry,
834 .add_next_entry = iter_add_next_cumulative_entry,
835 .finish_entry = iter_finish_cumulative_entry,
836};
837
838int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
839 struct perf_evsel *evsel, struct perf_sample *sample,
840 int max_stack_depth, void *arg)
841{
842 int err, err2;
843
844 err = sample__resolve_callchain(sample, &iter->parent, evsel, al,
845 max_stack_depth);
846 if (err)
847 return err;
848
849 iter->evsel = evsel;
850 iter->sample = sample;
851
852 err = iter->ops->prepare_entry(iter, al);
853 if (err)
854 goto out;
855
856 err = iter->ops->add_single_entry(iter, al);
857 if (err)
858 goto out;
859
860 if (iter->he && iter->add_entry_cb) {
861 err = iter->add_entry_cb(iter, al, true, arg);
862 if (err)
863 goto out;
864 }
865
866 while (iter->ops->next_entry(iter, al)) {
867 err = iter->ops->add_next_entry(iter, al);
868 if (err)
869 break;
870
871 if (iter->he && iter->add_entry_cb) {
872 err = iter->add_entry_cb(iter, al, false, arg);
873 if (err)
874 goto out;
875 }
876 }
877
878out:
879 err2 = iter->ops->finish_entry(iter, al);
880 if (!err)
881 err = err2;
882
883 return err;
430} 884}
431 885
432int64_t 886int64_t
@@ -469,6 +923,7 @@ void hist_entry__free(struct hist_entry *he)
469{ 923{
470 zfree(&he->branch_info); 924 zfree(&he->branch_info);
471 zfree(&he->mem_info); 925 zfree(&he->mem_info);
926 zfree(&he->stat_acc);
472 free_srcline(he->srcline); 927 free_srcline(he->srcline);
473 free(he); 928 free(he);
474} 929}
@@ -494,6 +949,8 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
494 949
495 if (!cmp) { 950 if (!cmp) {
496 he_stat__add_stat(&iter->stat, &he->stat); 951 he_stat__add_stat(&iter->stat, &he->stat);
952 if (symbol_conf.cumulate_callchain)
953 he_stat__add_stat(iter->stat_acc, he->stat_acc);
497 954
498 if (symbol_conf.use_callchain) { 955 if (symbol_conf.use_callchain) {
499 callchain_cursor_reset(&callchain_cursor); 956 callchain_cursor_reset(&callchain_cursor);
@@ -800,6 +1257,13 @@ void hists__inc_nr_events(struct hists *hists, u32 type)
800 events_stats__inc(&hists->stats, type); 1257 events_stats__inc(&hists->stats, type);
801} 1258}
802 1259
1260void hists__inc_nr_samples(struct hists *hists, bool filtered)
1261{
1262 events_stats__inc(&hists->stats, PERF_RECORD_SAMPLE);
1263 if (!filtered)
1264 hists->stats.nr_non_filtered_samples++;
1265}
1266
803static struct hist_entry *hists__add_dummy_entry(struct hists *hists, 1267static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
804 struct hist_entry *pair) 1268 struct hist_entry *pair)
805{ 1269{
@@ -831,7 +1295,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
831 p = &(*p)->rb_right; 1295 p = &(*p)->rb_right;
832 } 1296 }
833 1297
834 he = hist_entry__new(pair); 1298 he = hist_entry__new(pair, true);
835 if (he) { 1299 if (he) {
836 memset(&he->stat, 0, sizeof(he->stat)); 1300 memset(&he->stat, 0, sizeof(he->stat));
837 he->hists = hists; 1301 he->hists = hists;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index a8418d19808d..742f49a85725 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -72,6 +72,7 @@ enum hist_column {
72 HISTC_MEM_TLB, 72 HISTC_MEM_TLB,
73 HISTC_MEM_LVL, 73 HISTC_MEM_LVL,
74 HISTC_MEM_SNOOP, 74 HISTC_MEM_SNOOP,
75 HISTC_MEM_DCACHELINE,
75 HISTC_TRANSACTION, 76 HISTC_TRANSACTION,
76 HISTC_NR_COLS, /* Last entry */ 77 HISTC_NR_COLS, /* Last entry */
77}; 78};
@@ -96,12 +97,50 @@ struct hists {
96 u16 col_len[HISTC_NR_COLS]; 97 u16 col_len[HISTC_NR_COLS];
97}; 98};
98 99
100struct hist_entry_iter;
101
102struct hist_iter_ops {
103 int (*prepare_entry)(struct hist_entry_iter *, struct addr_location *);
104 int (*add_single_entry)(struct hist_entry_iter *, struct addr_location *);
105 int (*next_entry)(struct hist_entry_iter *, struct addr_location *);
106 int (*add_next_entry)(struct hist_entry_iter *, struct addr_location *);
107 int (*finish_entry)(struct hist_entry_iter *, struct addr_location *);
108};
109
110struct hist_entry_iter {
111 int total;
112 int curr;
113
114 bool hide_unresolved;
115
116 struct perf_evsel *evsel;
117 struct perf_sample *sample;
118 struct hist_entry *he;
119 struct symbol *parent;
120 void *priv;
121
122 const struct hist_iter_ops *ops;
123 /* user-defined callback function (optional) */
124 int (*add_entry_cb)(struct hist_entry_iter *iter,
125 struct addr_location *al, bool single, void *arg);
126};
127
128extern const struct hist_iter_ops hist_iter_normal;
129extern const struct hist_iter_ops hist_iter_branch;
130extern const struct hist_iter_ops hist_iter_mem;
131extern const struct hist_iter_ops hist_iter_cumulative;
132
99struct hist_entry *__hists__add_entry(struct hists *hists, 133struct hist_entry *__hists__add_entry(struct hists *hists,
100 struct addr_location *al, 134 struct addr_location *al,
101 struct symbol *parent, 135 struct symbol *parent,
102 struct branch_info *bi, 136 struct branch_info *bi,
103 struct mem_info *mi, u64 period, 137 struct mem_info *mi, u64 period,
104 u64 weight, u64 transaction); 138 u64 weight, u64 transaction,
139 bool sample_self);
140int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
141 struct perf_evsel *evsel, struct perf_sample *sample,
142 int max_stack_depth, void *arg);
143
105int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 144int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
106int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 145int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
107int hist_entry__transaction_len(void); 146int hist_entry__transaction_len(void);
@@ -119,6 +158,7 @@ u64 hists__total_period(struct hists *hists);
119void hists__reset_stats(struct hists *hists); 158void hists__reset_stats(struct hists *hists);
120void hists__inc_stats(struct hists *hists, struct hist_entry *h); 159void hists__inc_stats(struct hists *hists, struct hist_entry *h);
121void hists__inc_nr_events(struct hists *hists, u32 type); 160void hists__inc_nr_events(struct hists *hists, u32 type);
161void hists__inc_nr_samples(struct hists *hists, bool filtered);
122void events_stats__inc(struct events_stats *stats, u32 type); 162void events_stats__inc(struct events_stats *stats, u32 type);
123size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); 163size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
124 164
@@ -166,6 +206,7 @@ struct perf_hpp_fmt {
166 206
167 struct list_head list; 207 struct list_head list;
168 struct list_head sort_list; 208 struct list_head sort_list;
209 bool elide;
169}; 210};
170 211
171extern struct list_head perf_hpp__list; 212extern struct list_head perf_hpp__list;
@@ -192,6 +233,7 @@ enum {
192 PERF_HPP__OVERHEAD_US, 233 PERF_HPP__OVERHEAD_US,
193 PERF_HPP__OVERHEAD_GUEST_SYS, 234 PERF_HPP__OVERHEAD_GUEST_SYS,
194 PERF_HPP__OVERHEAD_GUEST_US, 235 PERF_HPP__OVERHEAD_GUEST_US,
236 PERF_HPP__OVERHEAD_ACC,
195 PERF_HPP__SAMPLES, 237 PERF_HPP__SAMPLES,
196 PERF_HPP__PERIOD, 238 PERF_HPP__PERIOD,
197 239
@@ -200,7 +242,11 @@ enum {
200 242
201void perf_hpp__init(void); 243void perf_hpp__init(void);
202void perf_hpp__column_register(struct perf_hpp_fmt *format); 244void perf_hpp__column_register(struct perf_hpp_fmt *format);
245void perf_hpp__column_unregister(struct perf_hpp_fmt *format);
203void perf_hpp__column_enable(unsigned col); 246void perf_hpp__column_enable(unsigned col);
247void perf_hpp__column_disable(unsigned col);
248void perf_hpp__cancel_cumulate(void);
249
204void perf_hpp__register_sort_field(struct perf_hpp_fmt *format); 250void perf_hpp__register_sort_field(struct perf_hpp_fmt *format);
205void perf_hpp__setup_output_field(void); 251void perf_hpp__setup_output_field(void);
206void perf_hpp__reset_output_field(void); 252void perf_hpp__reset_output_field(void);
@@ -208,7 +254,12 @@ void perf_hpp__append_sort_keys(void);
208 254
209bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format); 255bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
210bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b); 256bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
211bool perf_hpp__should_skip(struct perf_hpp_fmt *format); 257
258static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
259{
260 return format->elide;
261}
262
212void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); 263void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
213 264
214typedef u64 (*hpp_field_fn)(struct hist_entry *he); 265typedef u64 (*hpp_field_fn)(struct hist_entry *he);
@@ -218,6 +269,9 @@ typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
218int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 269int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
219 hpp_field_fn get_field, const char *fmt, 270 hpp_field_fn get_field, const char *fmt,
220 hpp_snprint_fn print_fn, bool fmt_percent); 271 hpp_snprint_fn print_fn, bool fmt_percent);
272int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
273 hpp_field_fn get_field, const char *fmt,
274 hpp_snprint_fn print_fn, bool fmt_percent);
221 275
222static inline void advance_hpp(struct perf_hpp *hpp, int inc) 276static inline void advance_hpp(struct perf_hpp *hpp, int inc)
223{ 277{
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 7409ac8de51c..0e5fea95d596 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1060,6 +1060,8 @@ int machine__process_mmap2_event(struct machine *machine,
1060 event->mmap2.pid, event->mmap2.maj, 1060 event->mmap2.pid, event->mmap2.maj,
1061 event->mmap2.min, event->mmap2.ino, 1061 event->mmap2.min, event->mmap2.ino,
1062 event->mmap2.ino_generation, 1062 event->mmap2.ino_generation,
1063 event->mmap2.prot,
1064 event->mmap2.flags,
1063 event->mmap2.filename, type); 1065 event->mmap2.filename, type);
1064 1066
1065 if (map == NULL) 1067 if (map == NULL)
@@ -1105,7 +1107,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1105 1107
1106 map = map__new(&machine->user_dsos, event->mmap.start, 1108 map = map__new(&machine->user_dsos, event->mmap.start,
1107 event->mmap.len, event->mmap.pgoff, 1109 event->mmap.len, event->mmap.pgoff,
1108 event->mmap.pid, 0, 0, 0, 0, 1110 event->mmap.pid, 0, 0, 0, 0, 0, 0,
1109 event->mmap.filename, 1111 event->mmap.filename,
1110 type); 1112 type);
1111 1113
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 8ccbb32eda25..25c571f4cba6 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -138,7 +138,7 @@ void map__init(struct map *map, enum map_type type,
138 138
139struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 139struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
141 u64 ino_gen, char *filename, 141 u64 ino_gen, u32 prot, u32 flags, char *filename,
142 enum map_type type) 142 enum map_type type)
143{ 143{
144 struct map *map = malloc(sizeof(*map)); 144 struct map *map = malloc(sizeof(*map));
@@ -157,6 +157,8 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
157 map->min = d_min; 157 map->min = d_min;
158 map->ino = ino; 158 map->ino = ino;
159 map->ino_generation = ino_gen; 159 map->ino_generation = ino_gen;
160 map->prot = prot;
161 map->flags = flags;
160 162
161 if ((anon || no_dso) && type == MAP__FUNCTION) { 163 if ((anon || no_dso) && type == MAP__FUNCTION) {
162 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 164 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index ae2d45110588..7758c72522ef 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -35,6 +35,8 @@ struct map {
35 bool referenced; 35 bool referenced;
36 bool erange_warned; 36 bool erange_warned;
37 u32 priv; 37 u32 priv;
38 u32 prot;
39 u32 flags;
38 u64 pgoff; 40 u64 pgoff;
39 u64 reloc; 41 u64 reloc;
40 u32 maj, min; /* only valid for MMAP2 record */ 42 u32 maj, min; /* only valid for MMAP2 record */
@@ -118,7 +120,7 @@ void map__init(struct map *map, enum map_type type,
118 u64 start, u64 end, u64 pgoff, struct dso *dso); 120 u64 start, u64 end, u64 pgoff, struct dso *dso);
119struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 121struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
120 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 122 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
121 u64 ino_gen, 123 u64 ino_gen, u32 prot, u32 flags,
122 char *filename, enum map_type type); 124 char *filename, enum map_type type);
123struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 125struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
124void map__delete(struct map *map); 126void map__delete(struct map *map);
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
index a3539ef30b15..43168fb0d9a2 100644
--- a/tools/perf/util/perf_regs.c
+++ b/tools/perf/util/perf_regs.c
@@ -1,11 +1,15 @@
1#include <errno.h> 1#include <errno.h>
2#include "perf_regs.h" 2#include "perf_regs.h"
3#include "event.h"
3 4
4int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) 5int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
5{ 6{
6 int i, idx = 0; 7 int i, idx = 0;
7 u64 mask = regs->mask; 8 u64 mask = regs->mask;
8 9
10 if (regs->cache_mask & (1 << id))
11 goto out;
12
9 if (!(mask & (1 << id))) 13 if (!(mask & (1 << id)))
10 return -EINVAL; 14 return -EINVAL;
11 15
@@ -14,6 +18,10 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
14 idx++; 18 idx++;
15 } 19 }
16 20
17 *valp = regs->regs[idx]; 21 regs->cache_mask |= (1 << id);
22 regs->cache_regs[id] = regs->regs[idx];
23
24out:
25 *valp = regs->cache_regs[id];
18 return 0; 26 return 0;
19} 27}
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index 79c78f74e0cf..980dbf76bc98 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -2,7 +2,8 @@
2#define __PERF_REGS_H 2#define __PERF_REGS_H
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include "event.h" 5
6struct regs_dump;
6 7
7#ifdef HAVE_PERF_REGS_SUPPORT 8#ifdef HAVE_PERF_REGS_SUPPORT
8#include <perf_regs.h> 9#include <perf_regs.h>
@@ -11,6 +12,7 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
11 12
12#else 13#else
13#define PERF_REGS_MASK 0 14#define PERF_REGS_MASK 0
15#define PERF_REGS_MAX 0
14 16
15static inline const char *perf_reg_name(int id __maybe_unused) 17static inline const char *perf_reg_name(int id __maybe_unused)
16{ 18{
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 0d1542f33d87..9a0a1839a377 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -628,11 +628,11 @@ static int __show_line_range(struct line_range *lr, const char *module)
628 628
629 ret = debuginfo__find_line_range(dinfo, lr); 629 ret = debuginfo__find_line_range(dinfo, lr);
630 debuginfo__delete(dinfo); 630 debuginfo__delete(dinfo);
631 if (ret == 0) { 631 if (ret == 0 || ret == -ENOENT) {
632 pr_warning("Specified source line is not found.\n"); 632 pr_warning("Specified source line is not found.\n");
633 return -ENOENT; 633 return -ENOENT;
634 } else if (ret < 0) { 634 } else if (ret < 0) {
635 pr_warning("Debuginfo analysis failed. (%d)\n", ret); 635 pr_warning("Debuginfo analysis failed.\n");
636 return ret; 636 return ret;
637 } 637 }
638 638
@@ -641,7 +641,7 @@ static int __show_line_range(struct line_range *lr, const char *module)
641 ret = get_real_path(tmp, lr->comp_dir, &lr->path); 641 ret = get_real_path(tmp, lr->comp_dir, &lr->path);
642 free(tmp); /* Free old path */ 642 free(tmp); /* Free old path */
643 if (ret < 0) { 643 if (ret < 0) {
644 pr_warning("Failed to find source file. (%d)\n", ret); 644 pr_warning("Failed to find source file path.\n");
645 return ret; 645 return ret;
646 } 646 }
647 647
@@ -721,9 +721,14 @@ static int show_available_vars_at(struct debuginfo *dinfo,
721 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, 721 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls,
722 max_vls, externs); 722 max_vls, externs);
723 if (ret <= 0) { 723 if (ret <= 0) {
724 pr_err("Failed to find variables at %s (%d)\n", buf, ret); 724 if (ret == 0 || ret == -ENOENT) {
725 pr_err("Failed to find the address of %s\n", buf);
726 ret = -ENOENT;
727 } else
728 pr_warning("Debuginfo analysis failed.\n");
725 goto end; 729 goto end;
726 } 730 }
731
727 /* Some variables are found */ 732 /* Some variables are found */
728 fprintf(stdout, "Available variables at %s\n", buf); 733 fprintf(stdout, "Available variables at %s\n", buf);
729 for (i = 0; i < ret; i++) { 734 for (i = 0; i < ret; i++) {
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 562762117639..98e304766416 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -511,12 +511,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
511 511
512 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 512 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
513 &pf->sp_die, pf->tvar); 513 &pf->sp_die, pf->tvar);
514 if (ret == -ENOENT) 514 if (ret == -ENOENT || ret == -EINVAL)
515 pr_err("Failed to find the location of %s at this address.\n" 515 pr_err("Failed to find the location of %s at this address.\n"
516 " Perhaps, it has been optimized out.\n", pf->pvar->var); 516 " Perhaps, it has been optimized out.\n", pf->pvar->var);
517 else if (ret == -ENOTSUP) 517 else if (ret == -ENOTSUP)
518 pr_err("Sorry, we don't support this variable location yet.\n"); 518 pr_err("Sorry, we don't support this variable location yet.\n");
519 else if (pf->pvar->field) { 519 else if (ret == 0 && pf->pvar->field) {
520 ret = convert_variable_fields(vr_die, pf->pvar->var, 520 ret = convert_variable_fields(vr_die, pf->pvar->var,
521 pf->pvar->field, &pf->tvar->ref, 521 pf->pvar->field, &pf->tvar->ref,
522 &die_mem); 522 &die_mem);
@@ -573,14 +573,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
573 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 573 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
574 /* Search again in global variables */ 574 /* Search again in global variables */
575 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 575 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
576 pr_warning("Failed to find '%s' in this function.\n",
577 pf->pvar->var);
576 ret = -ENOENT; 578 ret = -ENOENT;
577 } 579 }
578 if (ret >= 0) 580 if (ret >= 0)
579 ret = convert_variable(&vr_die, pf); 581 ret = convert_variable(&vr_die, pf);
580 582
581 if (ret < 0)
582 pr_warning("Failed to find '%s' in this function.\n",
583 pf->pvar->var);
584 return ret; 583 return ret;
585} 584}
586 585
@@ -1281,7 +1280,11 @@ out:
1281 return ret; 1280 return ret;
1282} 1281}
1283 1282
1284/* Find available variables at given probe point */ 1283/*
1284 * Find available variables at given probe point
1285 * Return the number of found probe points. Return 0 if there is no
1286 * matched probe point. Return <0 if an error occurs.
1287 */
1285int debuginfo__find_available_vars_at(struct debuginfo *dbg, 1288int debuginfo__find_available_vars_at(struct debuginfo *dbg,
1286 struct perf_probe_event *pev, 1289 struct perf_probe_event *pev,
1287 struct variable_list **vls, 1290 struct variable_list **vls,
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index e108207c5de0..af7da565a750 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -215,6 +215,7 @@ static void define_event_symbols(struct event_format *event,
215 case PRINT_BSTRING: 215 case PRINT_BSTRING:
216 case PRINT_DYNAMIC_ARRAY: 216 case PRINT_DYNAMIC_ARRAY:
217 case PRINT_STRING: 217 case PRINT_STRING:
218 case PRINT_BITMASK:
218 break; 219 break;
219 case PRINT_TYPE: 220 case PRINT_TYPE:
220 define_event_symbols(event, ev_name, args->typecast.item); 221 define_event_symbols(event, ev_name, args->typecast.item);
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index cd9774df3750..1c419321f707 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -197,6 +197,7 @@ static void define_event_symbols(struct event_format *event,
197 case PRINT_BSTRING: 197 case PRINT_BSTRING:
198 case PRINT_DYNAMIC_ARRAY: 198 case PRINT_DYNAMIC_ARRAY:
199 case PRINT_FUNC: 199 case PRINT_FUNC:
200 case PRINT_BITMASK:
200 /* we should warn... */ 201 /* we should warn... */
201 return; 202 return;
202 } 203 }
@@ -622,6 +623,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
622 fprintf(ofp, "%s=", f->name); 623 fprintf(ofp, "%s=", f->name);
623 if (f->flags & FIELD_IS_STRING || 624 if (f->flags & FIELD_IS_STRING ||
624 f->flags & FIELD_IS_FLAG || 625 f->flags & FIELD_IS_FLAG ||
626 f->flags & FIELD_IS_ARRAY ||
625 f->flags & FIELD_IS_SYMBOLIC) 627 f->flags & FIELD_IS_SYMBOLIC)
626 fprintf(ofp, "%%s"); 628 fprintf(ofp, "%%s");
627 else if (f->flags & FIELD_IS_SIGNED) 629 else if (f->flags & FIELD_IS_SIGNED)
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 901b9bece2ee..1ec57dd82284 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,3 +1,4 @@
1#include <sys/mman.h>
1#include "sort.h" 2#include "sort.h"
2#include "hist.h" 3#include "hist.h"
3#include "comm.h" 4#include "comm.h"
@@ -784,6 +785,104 @@ static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
784 return repsep_snprintf(bf, size, "%-*s", width, out); 785 return repsep_snprintf(bf, size, "%-*s", width, out);
785} 786}
786 787
788static inline u64 cl_address(u64 address)
789{
790 /* return the cacheline of the address */
791 return (address & ~(cacheline_size - 1));
792}
793
794static int64_t
795sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
796{
797 u64 l, r;
798 struct map *l_map, *r_map;
799
800 if (!left->mem_info) return -1;
801 if (!right->mem_info) return 1;
802
803 /* group event types together */
804 if (left->cpumode > right->cpumode) return -1;
805 if (left->cpumode < right->cpumode) return 1;
806
807 l_map = left->mem_info->daddr.map;
808 r_map = right->mem_info->daddr.map;
809
810 /* if both are NULL, jump to sort on al_addr instead */
811 if (!l_map && !r_map)
812 goto addr;
813
814 if (!l_map) return -1;
815 if (!r_map) return 1;
816
817 if (l_map->maj > r_map->maj) return -1;
818 if (l_map->maj < r_map->maj) return 1;
819
820 if (l_map->min > r_map->min) return -1;
821 if (l_map->min < r_map->min) return 1;
822
823 if (l_map->ino > r_map->ino) return -1;
824 if (l_map->ino < r_map->ino) return 1;
825
826 if (l_map->ino_generation > r_map->ino_generation) return -1;
827 if (l_map->ino_generation < r_map->ino_generation) return 1;
828
829 /*
830 * Addresses with no major/minor numbers are assumed to be
831 * anonymous in userspace. Sort those on pid then address.
832 *
833 * The kernel and non-zero major/minor mapped areas are
834 * assumed to be unity mapped. Sort those on address.
835 */
836
837 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
838 (!(l_map->flags & MAP_SHARED)) &&
839 !l_map->maj && !l_map->min && !l_map->ino &&
840 !l_map->ino_generation) {
841 /* userspace anonymous */
842
843 if (left->thread->pid_ > right->thread->pid_) return -1;
844 if (left->thread->pid_ < right->thread->pid_) return 1;
845 }
846
847addr:
848 /* al_addr does all the right addr - start + offset calculations */
849 l = cl_address(left->mem_info->daddr.al_addr);
850 r = cl_address(right->mem_info->daddr.al_addr);
851
852 if (l > r) return -1;
853 if (l < r) return 1;
854
855 return 0;
856}
857
858static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
859 size_t size, unsigned int width)
860{
861
862 uint64_t addr = 0;
863 struct map *map = NULL;
864 struct symbol *sym = NULL;
865 char level = he->level;
866
867 if (he->mem_info) {
868 addr = cl_address(he->mem_info->daddr.al_addr);
869 map = he->mem_info->daddr.map;
870 sym = he->mem_info->daddr.sym;
871
872 /* print [s] for shared data mmaps */
873 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
874 map && (map->type == MAP__VARIABLE) &&
875 (map->flags & MAP_SHARED) &&
876 (map->maj || map->min || map->ino ||
877 map->ino_generation))
878 level = 's';
879 else if (!map)
880 level = 'X';
881 }
882 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
883 width);
884}
885
787struct sort_entry sort_mispredict = { 886struct sort_entry sort_mispredict = {
788 .se_header = "Branch Mispredicted", 887 .se_header = "Branch Mispredicted",
789 .se_cmp = sort__mispredict_cmp, 888 .se_cmp = sort__mispredict_cmp,
@@ -876,6 +975,13 @@ struct sort_entry sort_mem_snoop = {
876 .se_width_idx = HISTC_MEM_SNOOP, 975 .se_width_idx = HISTC_MEM_SNOOP,
877}; 976};
878 977
978struct sort_entry sort_mem_dcacheline = {
979 .se_header = "Data Cacheline",
980 .se_cmp = sort__dcacheline_cmp,
981 .se_snprintf = hist_entry__dcacheline_snprintf,
982 .se_width_idx = HISTC_MEM_DCACHELINE,
983};
984
879static int64_t 985static int64_t
880sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) 986sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
881{ 987{
@@ -1043,6 +1149,7 @@ static struct sort_dimension memory_sort_dimensions[] = {
1043 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), 1149 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1044 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), 1150 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1045 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), 1151 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1152 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
1046}; 1153};
1047 1154
1048#undef DIM 1155#undef DIM
@@ -1061,6 +1168,7 @@ static struct hpp_dimension hpp_sort_dimensions[] = {
1061 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"), 1168 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1062 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"), 1169 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1063 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"), 1170 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1171 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
1064 DIM(PERF_HPP__SAMPLES, "sample"), 1172 DIM(PERF_HPP__SAMPLES, "sample"),
1065 DIM(PERF_HPP__PERIOD, "period"), 1173 DIM(PERF_HPP__PERIOD, "period"),
1066}; 1174};
@@ -1156,6 +1264,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1156 1264
1157 INIT_LIST_HEAD(&hse->hpp.list); 1265 INIT_LIST_HEAD(&hse->hpp.list);
1158 INIT_LIST_HEAD(&hse->hpp.sort_list); 1266 INIT_LIST_HEAD(&hse->hpp.sort_list);
1267 hse->hpp.elide = false;
1159 1268
1160 return hse; 1269 return hse;
1161} 1270}
@@ -1363,27 +1472,64 @@ static int __setup_sorting(void)
1363 return ret; 1472 return ret;
1364} 1473}
1365 1474
1366bool perf_hpp__should_skip(struct perf_hpp_fmt *format) 1475void perf_hpp__set_elide(int idx, bool elide)
1367{ 1476{
1368 if (perf_hpp__is_sort_entry(format)) { 1477 struct perf_hpp_fmt *fmt;
1369 struct hpp_sort_entry *hse; 1478 struct hpp_sort_entry *hse;
1479
1480 perf_hpp__for_each_format(fmt) {
1481 if (!perf_hpp__is_sort_entry(fmt))
1482 continue;
1370 1483
1371 hse = container_of(format, struct hpp_sort_entry, hpp); 1484 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1372 return hse->se->elide; 1485 if (hse->se->se_width_idx == idx) {
1486 fmt->elide = elide;
1487 break;
1488 }
1373 } 1489 }
1374 return false;
1375} 1490}
1376 1491
1377static void sort_entry__setup_elide(struct sort_entry *se, 1492static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
1378 struct strlist *list,
1379 const char *list_name, FILE *fp)
1380{ 1493{
1381 if (list && strlist__nr_entries(list) == 1) { 1494 if (list && strlist__nr_entries(list) == 1) {
1382 if (fp != NULL) 1495 if (fp != NULL)
1383 fprintf(fp, "# %s: %s\n", list_name, 1496 fprintf(fp, "# %s: %s\n", list_name,
1384 strlist__entry(list, 0)->s); 1497 strlist__entry(list, 0)->s);
1385 se->elide = true; 1498 return true;
1386 } 1499 }
1500 return false;
1501}
1502
1503static bool get_elide(int idx, FILE *output)
1504{
1505 switch (idx) {
1506 case HISTC_SYMBOL:
1507 return __get_elide(symbol_conf.sym_list, "symbol", output);
1508 case HISTC_DSO:
1509 return __get_elide(symbol_conf.dso_list, "dso", output);
1510 case HISTC_COMM:
1511 return __get_elide(symbol_conf.comm_list, "comm", output);
1512 default:
1513 break;
1514 }
1515
1516 if (sort__mode != SORT_MODE__BRANCH)
1517 return false;
1518
1519 switch (idx) {
1520 case HISTC_SYMBOL_FROM:
1521 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1522 case HISTC_SYMBOL_TO:
1523 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1524 case HISTC_DSO_FROM:
1525 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1526 case HISTC_DSO_TO:
1527 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1528 default:
1529 break;
1530 }
1531
1532 return false;
1387} 1533}
1388 1534
1389void sort__setup_elide(FILE *output) 1535void sort__setup_elide(FILE *output)
@@ -1391,39 +1537,12 @@ void sort__setup_elide(FILE *output)
1391 struct perf_hpp_fmt *fmt; 1537 struct perf_hpp_fmt *fmt;
1392 struct hpp_sort_entry *hse; 1538 struct hpp_sort_entry *hse;
1393 1539
1394 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, 1540 perf_hpp__for_each_format(fmt) {
1395 "dso", output); 1541 if (!perf_hpp__is_sort_entry(fmt))
1396 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, 1542 continue;
1397 "comm", output); 1543
1398 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, 1544 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1399 "symbol", output); 1545 fmt->elide = get_elide(hse->se->se_width_idx, output);
1400
1401 if (sort__mode == SORT_MODE__BRANCH) {
1402 sort_entry__setup_elide(&sort_dso_from,
1403 symbol_conf.dso_from_list,
1404 "dso_from", output);
1405 sort_entry__setup_elide(&sort_dso_to,
1406 symbol_conf.dso_to_list,
1407 "dso_to", output);
1408 sort_entry__setup_elide(&sort_sym_from,
1409 symbol_conf.sym_from_list,
1410 "sym_from", output);
1411 sort_entry__setup_elide(&sort_sym_to,
1412 symbol_conf.sym_to_list,
1413 "sym_to", output);
1414 } else if (sort__mode == SORT_MODE__MEMORY) {
1415 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1416 "symbol_daddr", output);
1417 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1418 "dso_daddr", output);
1419 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1420 "mem", output);
1421 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1422 "local_weight", output);
1423 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1424 "tlb", output);
1425 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1426 "snoop", output);
1427 } 1546 }
1428 1547
1429 /* 1548 /*
@@ -1434,8 +1553,7 @@ void sort__setup_elide(FILE *output)
1434 if (!perf_hpp__is_sort_entry(fmt)) 1553 if (!perf_hpp__is_sort_entry(fmt))
1435 continue; 1554 continue;
1436 1555
1437 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1556 if (!fmt->elide)
1438 if (!hse->se->elide)
1439 return; 1557 return;
1440 } 1558 }
1441 1559
@@ -1443,8 +1561,7 @@ void sort__setup_elide(FILE *output)
1443 if (!perf_hpp__is_sort_entry(fmt)) 1561 if (!perf_hpp__is_sort_entry(fmt))
1444 continue; 1562 continue;
1445 1563
1446 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1564 fmt->elide = false;
1447 hse->se->elide = false;
1448 } 1565 }
1449} 1566}
1450 1567
@@ -1581,6 +1698,9 @@ void reset_output_field(void)
1581 sort__has_sym = 0; 1698 sort__has_sym = 0;
1582 sort__has_dso = 0; 1699 sort__has_dso = 0;
1583 1700
1701 field_order = NULL;
1702 sort_order = NULL;
1703
1584 reset_dimensions(); 1704 reset_dimensions();
1585 perf_hpp__reset_output_field(); 1705 perf_hpp__reset_output_field();
1586} 1706}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 5f38d925e92f..041f0c9cea2b 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -20,7 +20,7 @@
20 20
21#include "parse-options.h" 21#include "parse-options.h"
22#include "parse-events.h" 22#include "parse-events.h"
23 23#include "hist.h"
24#include "thread.h" 24#include "thread.h"
25 25
26extern regex_t parent_regex; 26extern regex_t parent_regex;
@@ -82,12 +82,14 @@ struct hist_entry {
82 struct list_head head; 82 struct list_head head;
83 } pairs; 83 } pairs;
84 struct he_stat stat; 84 struct he_stat stat;
85 struct he_stat *stat_acc;
85 struct map_symbol ms; 86 struct map_symbol ms;
86 struct thread *thread; 87 struct thread *thread;
87 struct comm *comm; 88 struct comm *comm;
88 u64 ip; 89 u64 ip;
89 u64 transaction; 90 u64 transaction;
90 s32 cpu; 91 s32 cpu;
92 u8 cpumode;
91 93
92 struct hist_entry_diff diff; 94 struct hist_entry_diff diff;
93 95
@@ -130,6 +132,21 @@ static inline void hist_entry__add_pair(struct hist_entry *pair,
130 list_add_tail(&pair->pairs.node, &he->pairs.head); 132 list_add_tail(&pair->pairs.node, &he->pairs.head);
131} 133}
132 134
135static inline float hist_entry__get_percent_limit(struct hist_entry *he)
136{
137 u64 period = he->stat.period;
138 u64 total_period = hists__total_period(he->hists);
139
140 if (unlikely(total_period == 0))
141 return 0;
142
143 if (symbol_conf.cumulate_callchain)
144 period = he->stat_acc->period;
145
146 return period * 100.0 / total_period;
147}
148
149
133enum sort_mode { 150enum sort_mode {
134 SORT_MODE__NORMAL, 151 SORT_MODE__NORMAL,
135 SORT_MODE__BRANCH, 152 SORT_MODE__BRANCH,
@@ -169,6 +186,7 @@ enum sort_type {
169 SORT_MEM_TLB, 186 SORT_MEM_TLB,
170 SORT_MEM_LVL, 187 SORT_MEM_LVL,
171 SORT_MEM_SNOOP, 188 SORT_MEM_SNOOP,
189 SORT_MEM_DCACHELINE,
172}; 190};
173 191
174/* 192/*
@@ -186,7 +204,6 @@ struct sort_entry {
186 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size, 204 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
187 unsigned int width); 205 unsigned int width);
188 u8 se_width_idx; 206 u8 se_width_idx;
189 bool elide;
190}; 207};
191 208
192extern struct sort_entry sort_thread; 209extern struct sort_entry sort_thread;
@@ -197,6 +214,7 @@ int setup_output_field(void);
197void reset_output_field(void); 214void reset_output_field(void);
198extern int sort_dimension__add(const char *); 215extern int sort_dimension__add(const char *);
199void sort__setup_elide(FILE *fp); 216void sort__setup_elide(FILE *fp);
217void perf_hpp__set_elide(int idx, bool elide);
200 218
201int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); 219int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
202 220
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 95e249779931..7b9096f29cdb 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,11 +29,12 @@ int vmlinux_path__nr_entries;
29char **vmlinux_path; 29char **vmlinux_path;
30 30
31struct symbol_conf symbol_conf = { 31struct symbol_conf symbol_conf = {
32 .use_modules = true, 32 .use_modules = true,
33 .try_vmlinux_path = true, 33 .try_vmlinux_path = true,
34 .annotate_src = true, 34 .annotate_src = true,
35 .demangle = true, 35 .demangle = true,
36 .symfs = "", 36 .cumulate_callchain = true,
37 .symfs = "",
37}; 38};
38 39
39static enum dso_binary_type binary_type_symtab[] = { 40static enum dso_binary_type binary_type_symtab[] = {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 33ede53fa6b9..615c752dd767 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -109,6 +109,7 @@ struct symbol_conf {
109 show_nr_samples, 109 show_nr_samples,
110 show_total_period, 110 show_total_period,
111 use_callchain, 111 use_callchain,
112 cumulate_callchain,
112 exclude_other, 113 exclude_other,
113 show_cpu_utilization, 114 show_cpu_utilization,
114 initialized, 115 initialized,
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index bd5768d74f01..25578b98f5c5 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -250,7 +250,6 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
250 250
251 /* Check the .eh_frame section for unwinding info */ 251 /* Check the .eh_frame section for unwinding info */
252 offset = elf_section_offset(fd, ".eh_frame_hdr"); 252 offset = elf_section_offset(fd, ".eh_frame_hdr");
253 close(fd);
254 253
255 if (offset) 254 if (offset)
256 ret = unwind_spec_ehframe(dso, machine, offset, 255 ret = unwind_spec_ehframe(dso, machine, offset,
@@ -271,7 +270,6 @@ static int read_unwind_spec_debug_frame(struct dso *dso,
271 270
272 /* Check the .debug_frame section for unwinding info */ 271 /* Check the .debug_frame section for unwinding info */
273 *offset = elf_section_offset(fd, ".debug_frame"); 272 *offset = elf_section_offset(fd, ".debug_frame");
274 close(fd);
275 273
276 if (*offset) 274 if (*offset)
277 return 0; 275 return 0;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 7fff6be07f07..95aefa78bb07 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -17,6 +17,7 @@
17 * XXX We need to find a better place for these things... 17 * XXX We need to find a better place for these things...
18 */ 18 */
19unsigned int page_size; 19unsigned int page_size;
20int cacheline_size;
20 21
21bool test_attr__enabled; 22bool test_attr__enabled;
22 23
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index b03da44e94e4..66864364ccb4 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -304,6 +304,7 @@ char *rtrim(char *s);
304void dump_stack(void); 304void dump_stack(void);
305 305
306extern unsigned int page_size; 306extern unsigned int page_size;
307extern int cacheline_size;
307 308
308void get_term_dimensions(struct winsize *ws); 309void get_term_dimensions(struct winsize *ws);
309 310