aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt8
-rw-r--r--tools/perf/builtin-buildid-list.c4
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-probe.c1
-rw-r--r--tools/perf/builtin-record.c37
-rw-r--r--tools/perf/builtin-report.c2
-rw-r--r--tools/perf/util/build-id.c18
-rw-r--r--tools/perf/util/event.c42
-rw-r--r--tools/perf/util/hist.c160
-rw-r--r--tools/perf/util/hist.h30
-rw-r--r--tools/perf/util/map.c81
-rw-r--r--tools/perf/util/map.h4
-rw-r--r--tools/perf/util/newt.c991
-rw-r--r--tools/perf/util/probe-event.c135
-rw-r--r--tools/perf/util/probe-event.h27
-rw-r--r--tools/perf/util/probe-finder.c34
-rw-r--r--tools/perf/util/probe-finder.h10
-rw-r--r--tools/perf/util/session.c48
-rw-r--r--tools/perf/util/sort.c17
-rw-r--r--tools/perf/util/sort.h18
-rw-r--r--tools/perf/util/symbol.c219
-rw-r--r--tools/perf/util/symbol.h10
-rw-r--r--tools/perf/util/thread.c7
-rw-r--r--tools/perf/util/thread.h2
24 files changed, 1253 insertions, 654 deletions
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
index 5d1a9500277f..c1057701a7dc 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -12,9 +12,9 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command manages the build-id cache. It can add and remove files to the 15This command manages the build-id cache. It can add and remove files to/from
16cache. In the future it should as well purge older entries, set upper limits 16the cache. In the future it should as well purge older entries, set upper
17for the space used by the cache, etc. 17limits for the space used by the cache, etc.
18 18
19OPTIONS 19OPTIONS
20------- 20-------
@@ -23,7 +23,7 @@ OPTIONS
23 Add specified file to the cache. 23 Add specified file to the cache.
24-r:: 24-r::
25--remove=:: 25--remove=::
26 Remove specified file to the cache. 26 Remove specified file from the cache.
27-v:: 27-v::
28--verbose:: 28--verbose::
29 Be more verbose. 29 Be more verbose.
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 99890728409e..44a47e13bd67 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -43,10 +43,8 @@ static int __cmd_buildid_list(void)
43 if (session == NULL) 43 if (session == NULL)
44 return -1; 44 return -1;
45 45
46 if (with_hits) { 46 if (with_hits)
47 symbol_conf.full_paths = true;
48 perf_session__process_events(session, &build_id__mark_dso_hit_ops); 47 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
49 }
50 48
51 perf_session__fprintf_dsos_buildid(session, stdout, with_hits); 49 perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
52 50
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 39e6627ebb96..fca1d4402910 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -180,8 +180,6 @@ static const struct option options[] = {
180 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 180 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
181 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 181 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
182 "load module symbols - WARNING: use only with -k and LIVE kernel"), 182 "load module symbols - WARNING: use only with -k and LIVE kernel"),
183 OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
184 "Don't shorten the pathnames taking into account the cwd"),
185 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 183 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
186 "only consider symbols in these dsos"), 184 "only consider symbols in these dsos"),
187 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 185 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 54551867e7e0..199d5e19554f 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -267,4 +267,3 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
267 } 267 }
268 return 0; 268 return 0;
269} 269}
270
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index b93879677cca..ff77b805de71 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -439,6 +439,8 @@ static void atexit_header(void)
439 439
440 process_buildids(); 440 process_buildids();
441 perf_header__write(&session->header, output, true); 441 perf_header__write(&session->header, output, true);
442 perf_session__delete(session);
443 symbol__exit();
442 } 444 }
443} 445}
444 446
@@ -558,12 +560,15 @@ static int __cmd_record(int argc, const char **argv)
558 if (!file_new) { 560 if (!file_new) {
559 err = perf_header__read(session, output); 561 err = perf_header__read(session, output);
560 if (err < 0) 562 if (err < 0)
561 return err; 563 goto out_delete_session;
562 } 564 }
563 565
564 if (have_tracepoints(attrs, nr_counters)) 566 if (have_tracepoints(attrs, nr_counters))
565 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 567 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
566 568
569 /*
570 * perf_session__delete(session) will be called at atexit_header()
571 */
567 atexit(atexit_header); 572 atexit(atexit_header);
568 573
569 if (forks) { 574 if (forks) {
@@ -768,6 +773,10 @@ static int __cmd_record(int argc, const char **argv)
768 bytes_written / 24); 773 bytes_written / 24);
769 774
770 return 0; 775 return 0;
776
777out_delete_session:
778 perf_session__delete(session);
779 return err;
771} 780}
772 781
773static const char * const record_usage[] = { 782static const char * const record_usage[] = {
@@ -824,7 +833,7 @@ static const struct option options[] = {
824 833
825int cmd_record(int argc, const char **argv, const char *prefix __used) 834int cmd_record(int argc, const char **argv, const char *prefix __used)
826{ 835{
827 int i,j; 836 int i, j, err = -ENOMEM;
828 837
829 argc = parse_options(argc, argv, options, record_usage, 838 argc = parse_options(argc, argv, options, record_usage,
830 PARSE_OPT_STOP_AT_NON_OPTION); 839 PARSE_OPT_STOP_AT_NON_OPTION);
@@ -863,7 +872,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
863 } else { 872 } else {
864 all_tids=malloc(sizeof(pid_t)); 873 all_tids=malloc(sizeof(pid_t));
865 if (!all_tids) 874 if (!all_tids)
866 return -ENOMEM; 875 goto out_symbol_exit;
867 876
868 all_tids[0] = target_tid; 877 all_tids[0] = target_tid;
869 thread_num = 1; 878 thread_num = 1;
@@ -873,13 +882,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
873 for (j = 0; j < MAX_COUNTERS; j++) { 882 for (j = 0; j < MAX_COUNTERS; j++) {
874 fd[i][j] = malloc(sizeof(int)*thread_num); 883 fd[i][j] = malloc(sizeof(int)*thread_num);
875 if (!fd[i][j]) 884 if (!fd[i][j])
876 return -ENOMEM; 885 goto out_free_fd;
877 } 886 }
878 } 887 }
879 event_array = malloc( 888 event_array = malloc(
880 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); 889 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
881 if (!event_array) 890 if (!event_array)
882 return -ENOMEM; 891 goto out_free_fd;
883 892
884 if (user_interval != ULLONG_MAX) 893 if (user_interval != ULLONG_MAX)
885 default_interval = user_interval; 894 default_interval = user_interval;
@@ -895,8 +904,22 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
895 default_interval = freq; 904 default_interval = freq;
896 } else { 905 } else {
897 fprintf(stderr, "frequency and count are zero, aborting\n"); 906 fprintf(stderr, "frequency and count are zero, aborting\n");
898 exit(EXIT_FAILURE); 907 err = -EINVAL;
908 goto out_free_event_array;
899 } 909 }
900 910
901 return __cmd_record(argc, argv); 911 err = __cmd_record(argc, argv);
912
913out_free_event_array:
914 free(event_array);
915out_free_fd:
916 for (i = 0; i < MAX_NR_CPUS; i++) {
917 for (j = 0; j < MAX_COUNTERS; j++)
918 free(fd[i][j]);
919 }
920 free(all_tids);
921 all_tids = NULL;
922out_symbol_exit:
923 symbol__exit();
924 return err;
902} 925}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index ce42bbaa252d..2f4b92925b26 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -441,8 +441,6 @@ static const struct option options[] = {
441 "pretty printing style key: normal raw"), 441 "pretty printing style key: normal raw"),
442 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 442 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
443 "sort by key(s): pid, comm, dso, symbol, parent"), 443 "sort by key(s): pid, comm, dso, symbol, parent"),
444 OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
445 "Don't shorten the pathnames taking into account the cwd"),
446 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 444 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
447 "Show sample percentage for different cpu modes"), 445 "Show sample percentage for different cpu modes"),
448 OPT_STRING('p', "parent", &parent_pattern, "regex", 446 OPT_STRING('p', "parent", &parent_pattern, "regex",
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 5c26e2d314af..e437edb72417 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -12,6 +12,7 @@
12#include "event.h" 12#include "event.h"
13#include "symbol.h" 13#include "symbol.h"
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include "debug.h"
15 16
16static int build_id__mark_dso_hit(event_t *event, struct perf_session *session) 17static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
17{ 18{
@@ -34,10 +35,27 @@ static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
34 return 0; 35 return 0;
35} 36}
36 37
38static int event__exit_del_thread(event_t *self, struct perf_session *session)
39{
40 struct thread *thread = perf_session__findnew(session, self->fork.tid);
41
42 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
43 self->fork.ppid, self->fork.ptid);
44
45 if (thread) {
46 rb_erase(&thread->rb_node, &session->threads);
47 session->last_match = NULL;
48 thread__delete(thread);
49 }
50
51 return 0;
52}
53
37struct perf_event_ops build_id__mark_dso_hit_ops = { 54struct perf_event_ops build_id__mark_dso_hit_ops = {
38 .sample = build_id__mark_dso_hit, 55 .sample = build_id__mark_dso_hit,
39 .mmap = event__process_mmap, 56 .mmap = event__process_mmap,
40 .fork = event__process_task, 57 .fork = event__process_task,
58 .exit = event__exit_del_thread,
41}; 59};
42 60
43char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 61char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index d7f21d71eb69..6b0db5577929 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -340,30 +340,29 @@ int event__synthesize_kernel_mmap(event__handler_t process,
340 return process(&ev, session); 340 return process(&ev, session);
341} 341}
342 342
343static void thread__comm_adjust(struct thread *self) 343static void thread__comm_adjust(struct thread *self, struct hists *hists)
344{ 344{
345 char *comm = self->comm; 345 char *comm = self->comm;
346 346
347 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 347 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
348 (!symbol_conf.comm_list || 348 (!symbol_conf.comm_list ||
349 strlist__has_entry(symbol_conf.comm_list, comm))) { 349 strlist__has_entry(symbol_conf.comm_list, comm))) {
350 unsigned int slen = strlen(comm); 350 u16 slen = strlen(comm);
351 351
352 if (slen > comms__col_width) { 352 if (hists__new_col_len(hists, HISTC_COMM, slen))
353 comms__col_width = slen; 353 hists__set_col_len(hists, HISTC_THREAD, slen + 6);
354 threads__col_width = slen + 6;
355 }
356 } 354 }
357} 355}
358 356
359static int thread__set_comm_adjust(struct thread *self, const char *comm) 357static int thread__set_comm_adjust(struct thread *self, const char *comm,
358 struct hists *hists)
360{ 359{
361 int ret = thread__set_comm(self, comm); 360 int ret = thread__set_comm(self, comm);
362 361
363 if (ret) 362 if (ret)
364 return ret; 363 return ret;
365 364
366 thread__comm_adjust(self); 365 thread__comm_adjust(self, hists);
367 366
368 return 0; 367 return 0;
369} 368}
@@ -374,7 +373,8 @@ int event__process_comm(event_t *self, struct perf_session *session)
374 373
375 dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid); 374 dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid);
376 375
377 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) { 376 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm,
377 &session->hists)) {
378 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 378 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
379 return -1; 379 return -1;
380 } 380 }
@@ -456,6 +456,7 @@ static int event__process_kernel_mmap(event_t *self,
456 goto out_problem; 456 goto out_problem;
457 457
458 map->dso->short_name = name; 458 map->dso->short_name = name;
459 map->dso->sname_alloc = 1;
459 map->end = map->start + self->mmap.len; 460 map->end = map->start + self->mmap.len;
460 } else if (is_kernel_mmap) { 461 } else if (is_kernel_mmap) {
461 const char *symbol_name = (self->mmap.filename + 462 const char *symbol_name = (self->mmap.filename +
@@ -514,12 +515,13 @@ int event__process_mmap(event_t *self, struct perf_session *session)
514 if (machine == NULL) 515 if (machine == NULL)
515 goto out_problem; 516 goto out_problem;
516 thread = perf_session__findnew(session, self->mmap.pid); 517 thread = perf_session__findnew(session, self->mmap.pid);
518 if (thread == NULL)
519 goto out_problem;
517 map = map__new(&machine->user_dsos, self->mmap.start, 520 map = map__new(&machine->user_dsos, self->mmap.start,
518 self->mmap.len, self->mmap.pgoff, 521 self->mmap.len, self->mmap.pgoff,
519 self->mmap.pid, self->mmap.filename, 522 self->mmap.pid, self->mmap.filename,
520 MAP__FUNCTION, session->cwd, session->cwdlen); 523 MAP__FUNCTION);
521 524 if (map == NULL)
522 if (thread == NULL || map == NULL)
523 goto out_problem; 525 goto out_problem;
524 526
525 thread__insert_map(thread, map); 527 thread__insert_map(thread, map);
@@ -641,16 +643,13 @@ void thread__find_addr_location(struct thread *self,
641 al->sym = NULL; 643 al->sym = NULL;
642} 644}
643 645
644static void dso__calc_col_width(struct dso *self) 646static void dso__calc_col_width(struct dso *self, struct hists *hists)
645{ 647{
646 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 648 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
647 (!symbol_conf.dso_list || 649 (!symbol_conf.dso_list ||
648 strlist__has_entry(symbol_conf.dso_list, self->name))) { 650 strlist__has_entry(symbol_conf.dso_list, self->name))) {
649 u16 slen = self->short_name_len; 651 u16 slen = dso__name_len(self);
650 if (verbose) 652 hists__new_col_len(hists, HISTC_DSO, slen);
651 slen = self->long_name_len;
652 if (dsos__col_width < slen)
653 dsos__col_width = slen;
654 } 653 }
655 654
656 self->slen_calculated = 1; 655 self->slen_calculated = 1;
@@ -729,16 +728,17 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
729 * sampled. 728 * sampled.
730 */ 729 */
731 if (!sort_dso.elide && !al->map->dso->slen_calculated) 730 if (!sort_dso.elide && !al->map->dso->slen_calculated)
732 dso__calc_col_width(al->map->dso); 731 dso__calc_col_width(al->map->dso, &session->hists);
733 732
734 al->sym = map__find_symbol(al->map, al->addr, filter); 733 al->sym = map__find_symbol(al->map, al->addr, filter);
735 } else { 734 } else {
736 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 735 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
737 736
738 if (dsos__col_width < unresolved_col_width && 737 if (hists__col_len(&session->hists, HISTC_DSO) < unresolved_col_width &&
739 !symbol_conf.col_width_list_str && !symbol_conf.field_sep && 738 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
740 !symbol_conf.dso_list) 739 !symbol_conf.dso_list)
741 dsos__col_width = unresolved_col_width; 740 hists__set_col_len(&session->hists, HISTC_DSO,
741 unresolved_col_width);
742 } 742 }
743 743
744 if (symbol_conf.sym_list && al->sym && 744 if (symbol_conf.sym_list && al->sym &&
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 7b5848ce1505..d0f07f7bdf16 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -5,11 +5,61 @@
5#include "sort.h" 5#include "sort.h"
6#include <math.h> 6#include <math.h>
7 7
8enum hist_filter {
9 HIST_FILTER__DSO,
10 HIST_FILTER__THREAD,
11 HIST_FILTER__PARENT,
12};
13
8struct callchain_param callchain_param = { 14struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL, 15 .mode = CHAIN_GRAPH_REL,
10 .min_percent = 0.5 16 .min_percent = 0.5
11}; 17};
12 18
19u16 hists__col_len(struct hists *self, enum hist_column col)
20{
21 return self->col_len[col];
22}
23
24void hists__set_col_len(struct hists *self, enum hist_column col, u16 len)
25{
26 self->col_len[col] = len;
27}
28
29bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len)
30{
31 if (len > hists__col_len(self, col)) {
32 hists__set_col_len(self, col, len);
33 return true;
34 }
35 return false;
36}
37
38static void hists__reset_col_len(struct hists *self)
39{
40 enum hist_column col;
41
42 for (col = 0; col < HISTC_NR_COLS; ++col)
43 hists__set_col_len(self, col, 0);
44}
45
46static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
47{
48 u16 len;
49
50 if (h->ms.sym)
51 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
52
53 len = thread__comm_len(h->thread);
54 if (hists__new_col_len(self, HISTC_COMM, len))
55 hists__set_col_len(self, HISTC_THREAD, len + 6);
56
57 if (h->ms.map) {
58 len = dso__name_len(h->ms.map->dso);
59 hists__new_col_len(self, HISTC_DSO, len);
60 }
61}
62
13static void hist_entry__add_cpumode_period(struct hist_entry *self, 63static void hist_entry__add_cpumode_period(struct hist_entry *self,
14 unsigned int cpumode, u64 period) 64 unsigned int cpumode, u64 period)
15{ 65{
@@ -50,11 +100,19 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
50 return self; 100 return self;
51} 101}
52 102
53static void hists__inc_nr_entries(struct hists *self, struct hist_entry *entry) 103static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h)
54{ 104{
55 if (entry->ms.sym && self->max_sym_namelen < entry->ms.sym->namelen) 105 if (!h->filtered) {
56 self->max_sym_namelen = entry->ms.sym->namelen; 106 hists__calc_col_len(self, h);
57 ++self->nr_entries; 107 ++self->nr_entries;
108 }
109}
110
111static u8 symbol__parent_filter(const struct symbol *parent)
112{
113 if (symbol_conf.exclude_other && parent == NULL)
114 return 1 << HIST_FILTER__PARENT;
115 return 0;
58} 116}
59 117
60struct hist_entry *__hists__add_entry(struct hists *self, 118struct hist_entry *__hists__add_entry(struct hists *self,
@@ -75,6 +133,7 @@ struct hist_entry *__hists__add_entry(struct hists *self,
75 .level = al->level, 133 .level = al->level,
76 .period = period, 134 .period = period,
77 .parent = sym_parent, 135 .parent = sym_parent,
136 .filtered = symbol__parent_filter(sym_parent),
78 }; 137 };
79 int cmp; 138 int cmp;
80 139
@@ -192,7 +251,7 @@ void hists__collapse_resort(struct hists *self)
192 tmp = RB_ROOT; 251 tmp = RB_ROOT;
193 next = rb_first(&self->entries); 252 next = rb_first(&self->entries);
194 self->nr_entries = 0; 253 self->nr_entries = 0;
195 self->max_sym_namelen = 0; 254 hists__reset_col_len(self);
196 255
197 while (next) { 256 while (next) {
198 n = rb_entry(next, struct hist_entry, rb_node); 257 n = rb_entry(next, struct hist_entry, rb_node);
@@ -249,7 +308,7 @@ void hists__output_resort(struct hists *self)
249 next = rb_first(&self->entries); 308 next = rb_first(&self->entries);
250 309
251 self->nr_entries = 0; 310 self->nr_entries = 0;
252 self->max_sym_namelen = 0; 311 hists__reset_col_len(self);
253 312
254 while (next) { 313 while (next) {
255 n = rb_entry(next, struct hist_entry, rb_node); 314 n = rb_entry(next, struct hist_entry, rb_node);
@@ -516,8 +575,9 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
516} 575}
517 576
518int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, 577int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
519 struct hists *pair_hists, bool show_displacement, 578 struct hists *hists, struct hists *pair_hists,
520 long displacement, bool color, u64 session_total) 579 bool show_displacement, long displacement,
580 bool color, u64 session_total)
521{ 581{
522 struct sort_entry *se; 582 struct sort_entry *se;
523 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; 583 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
@@ -621,24 +681,25 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
621 681
622 ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); 682 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
623 ret += se->se_snprintf(self, s + ret, size - ret, 683 ret += se->se_snprintf(self, s + ret, size - ret,
624 se->se_width ? *se->se_width : 0); 684 hists__col_len(hists, se->se_width_idx));
625 } 685 }
626 686
627 return ret; 687 return ret;
628} 688}
629 689
630int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists, 690int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
631 bool show_displacement, long displacement, FILE *fp, 691 struct hists *pair_hists, bool show_displacement,
632 u64 session_total) 692 long displacement, FILE *fp, u64 session_total)
633{ 693{
634 char bf[512]; 694 char bf[512];
635 hist_entry__snprintf(self, bf, sizeof(bf), pair_hists, 695 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists,
636 show_displacement, displacement, 696 show_displacement, displacement,
637 true, session_total); 697 true, session_total);
638 return fprintf(fp, "%s\n", bf); 698 return fprintf(fp, "%s\n", bf);
639} 699}
640 700
641static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp, 701static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
702 struct hists *hists, FILE *fp,
642 u64 session_total) 703 u64 session_total)
643{ 704{
644 int left_margin = 0; 705 int left_margin = 0;
@@ -646,7 +707,7 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
646 if (sort__first_dimension == SORT_COMM) { 707 if (sort__first_dimension == SORT_COMM) {
647 struct sort_entry *se = list_first_entry(&hist_entry__sort_list, 708 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
648 typeof(*se), list); 709 typeof(*se), list);
649 left_margin = se->se_width ? *se->se_width : 0; 710 left_margin = hists__col_len(hists, se->se_width_idx);
650 left_margin -= thread__comm_len(self->thread); 711 left_margin -= thread__comm_len(self->thread);
651 } 712 }
652 713
@@ -717,17 +778,17 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
717 continue; 778 continue;
718 } 779 }
719 width = strlen(se->se_header); 780 width = strlen(se->se_header);
720 if (se->se_width) { 781 if (symbol_conf.col_width_list_str) {
721 if (symbol_conf.col_width_list_str) { 782 if (col_width) {
722 if (col_width) { 783 hists__set_col_len(self, se->se_width_idx,
723 *se->se_width = atoi(col_width); 784 atoi(col_width));
724 col_width = strchr(col_width, ','); 785 col_width = strchr(col_width, ',');
725 if (col_width) 786 if (col_width)
726 ++col_width; 787 ++col_width;
727 }
728 } 788 }
729 width = *se->se_width = max(*se->se_width, width);
730 } 789 }
790 if (!hists__new_col_len(self, se->se_width_idx, width))
791 width = hists__col_len(self, se->se_width_idx);
731 fprintf(fp, " %*s", width, se->se_header); 792 fprintf(fp, " %*s", width, se->se_header);
732 } 793 }
733 fprintf(fp, "\n"); 794 fprintf(fp, "\n");
@@ -750,9 +811,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
750 continue; 811 continue;
751 812
752 fprintf(fp, " "); 813 fprintf(fp, " ");
753 if (se->se_width) 814 width = hists__col_len(self, se->se_width_idx);
754 width = *se->se_width; 815 if (width == 0)
755 else
756 width = strlen(se->se_header); 816 width = strlen(se->se_header);
757 for (i = 0; i < width; i++) 817 for (i = 0; i < width; i++)
758 fprintf(fp, "."); 818 fprintf(fp, ".");
@@ -772,12 +832,12 @@ print_entries:
772 displacement = 0; 832 displacement = 0;
773 ++position; 833 ++position;
774 } 834 }
775 ret += hist_entry__fprintf(h, pair, show_displacement, 835 ret += hist_entry__fprintf(h, self, pair, show_displacement,
776 displacement, fp, self->stats.total_period); 836 displacement, fp, self->stats.total_period);
777 837
778 if (symbol_conf.use_callchain) 838 if (symbol_conf.use_callchain)
779 ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period); 839 ret += hist_entry__fprintf_callchain(h, self, fp,
780 840 self->stats.total_period);
781 if (h->ms.map == NULL && verbose > 1) { 841 if (h->ms.map == NULL && verbose > 1) {
782 __map_groups__fprintf_maps(&h->thread->mg, 842 __map_groups__fprintf_maps(&h->thread->mg,
783 MAP__FUNCTION, verbose, fp); 843 MAP__FUNCTION, verbose, fp);
@@ -790,10 +850,32 @@ print_entries:
790 return ret; 850 return ret;
791} 851}
792 852
793enum hist_filter { 853/*
794 HIST_FILTER__DSO, 854 * See hists__fprintf to match the column widths
795 HIST_FILTER__THREAD, 855 */
796}; 856unsigned int hists__sort_list_width(struct hists *self)
857{
858 struct sort_entry *se;
859 int ret = 9; /* total % */
860
861 if (symbol_conf.show_cpu_utilization) {
862 ret += 7; /* count_sys % */
863 ret += 6; /* count_us % */
864 if (perf_guest) {
865 ret += 13; /* count_guest_sys % */
866 ret += 12; /* count_guest_us % */
867 }
868 }
869
870 if (symbol_conf.show_nr_samples)
871 ret += 11;
872
873 list_for_each_entry(se, &hist_entry__sort_list, list)
874 if (!se->elide)
875 ret += 2 + hists__col_len(self, se->se_width_idx);
876
877 return ret;
878}
797 879
798static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h, 880static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
799 enum hist_filter filter) 881 enum hist_filter filter)
@@ -803,11 +885,13 @@ static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
803 return; 885 return;
804 886
805 ++self->nr_entries; 887 ++self->nr_entries;
888 if (h->ms.unfolded)
889 self->nr_entries += h->nr_rows;
890 h->row_offset = 0;
806 self->stats.total_period += h->period; 891 self->stats.total_period += h->period;
807 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; 892 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
808 893
809 if (h->ms.sym && self->max_sym_namelen < h->ms.sym->namelen) 894 hists__calc_col_len(self, h);
810 self->max_sym_namelen = h->ms.sym->namelen;
811} 895}
812 896
813void hists__filter_by_dso(struct hists *self, const struct dso *dso) 897void hists__filter_by_dso(struct hists *self, const struct dso *dso)
@@ -816,7 +900,7 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
816 900
817 self->nr_entries = self->stats.total_period = 0; 901 self->nr_entries = self->stats.total_period = 0;
818 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 902 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
819 self->max_sym_namelen = 0; 903 hists__reset_col_len(self);
820 904
821 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 905 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
822 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 906 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -839,7 +923,7 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
839 923
840 self->nr_entries = self->stats.total_period = 0; 924 self->nr_entries = self->stats.total_period = 0;
841 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 925 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
842 self->max_sym_namelen = 0; 926 hists__reset_col_len(self);
843 927
844 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 928 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
845 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 929 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 83fa33a7b38b..65a48db46a29 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -56,6 +56,16 @@ struct events_stats {
56 u32 nr_unknown_events; 56 u32 nr_unknown_events;
57}; 57};
58 58
59enum hist_column {
60 HISTC_SYMBOL,
61 HISTC_DSO,
62 HISTC_THREAD,
63 HISTC_COMM,
64 HISTC_PARENT,
65 HISTC_CPU,
66 HISTC_NR_COLS, /* Last entry */
67};
68
59struct hists { 69struct hists {
60 struct rb_node rb_node; 70 struct rb_node rb_node;
61 struct rb_root entries; 71 struct rb_root entries;
@@ -64,7 +74,7 @@ struct hists {
64 u64 config; 74 u64 config;
65 u64 event_stream; 75 u64 event_stream;
66 u32 type; 76 u32 type;
67 u32 max_sym_namelen; 77 u16 col_len[HISTC_NR_COLS];
68}; 78};
69 79
70struct hist_entry *__hists__add_entry(struct hists *self, 80struct hist_entry *__hists__add_entry(struct hists *self,
@@ -72,12 +82,13 @@ struct hist_entry *__hists__add_entry(struct hists *self,
72 struct symbol *parent, u64 period); 82 struct symbol *parent, u64 period);
73extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 83extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
74extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 84extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
75int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists, 85int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
76 bool show_displacement, long displacement, FILE *fp, 86 struct hists *pair_hists, bool show_displacement,
77 u64 total); 87 long displacement, FILE *fp, u64 total);
78int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, 88int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
79 struct hists *pair_hists, bool show_displacement, 89 struct hists *hists, struct hists *pair_hists,
80 long displacement, bool color, u64 total); 90 bool show_displacement, long displacement,
91 bool color, u64 total);
81void hist_entry__free(struct hist_entry *); 92void hist_entry__free(struct hist_entry *);
82 93
83void hists__output_resort(struct hists *self); 94void hists__output_resort(struct hists *self);
@@ -95,6 +106,10 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head);
95void hists__filter_by_dso(struct hists *self, const struct dso *dso); 106void hists__filter_by_dso(struct hists *self, const struct dso *dso);
96void hists__filter_by_thread(struct hists *self, const struct thread *thread); 107void hists__filter_by_thread(struct hists *self, const struct thread *thread);
97 108
109u16 hists__col_len(struct hists *self, enum hist_column col);
110void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
111bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
112
98#ifdef NO_NEWT_SUPPORT 113#ifdef NO_NEWT_SUPPORT
99static inline int hists__browse(struct hists *self __used, 114static inline int hists__browse(struct hists *self __used,
100 const char *helpline __used, 115 const char *helpline __used,
@@ -126,4 +141,7 @@ int hist_entry__tui_annotate(struct hist_entry *self);
126 141
127int hists__tui_browse_tree(struct rb_root *self, const char *help); 142int hists__tui_browse_tree(struct rb_root *self, const char *help);
128#endif 143#endif
144
145unsigned int hists__sort_list_width(struct hists *self);
146
129#endif /* __PERF_HIST_H */ 147#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index e672f2fef65b..15d6a6dd50c5 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -17,16 +17,6 @@ static inline int is_anon_memory(const char *filename)
17 return strcmp(filename, "//anon") == 0; 17 return strcmp(filename, "//anon") == 0;
18} 18}
19 19
20static int strcommon(const char *pathname, char *cwd, int cwdlen)
21{
22 int n = 0;
23
24 while (n < cwdlen && pathname[n] == cwd[n])
25 ++n;
26
27 return n;
28}
29
30void map__init(struct map *self, enum map_type type, 20void map__init(struct map *self, enum map_type type,
31 u64 start, u64 end, u64 pgoff, struct dso *dso) 21 u64 start, u64 end, u64 pgoff, struct dso *dso)
32{ 22{
@@ -43,7 +33,7 @@ void map__init(struct map *self, enum map_type type,
43 33
44struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 34struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
45 u64 pgoff, u32 pid, char *filename, 35 u64 pgoff, u32 pid, char *filename,
46 enum map_type type, char *cwd, int cwdlen) 36 enum map_type type)
47{ 37{
48 struct map *self = malloc(sizeof(*self)); 38 struct map *self = malloc(sizeof(*self));
49 39
@@ -52,16 +42,6 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
52 struct dso *dso; 42 struct dso *dso;
53 int anon; 43 int anon;
54 44
55 if (cwd) {
56 int n = strcommon(filename, cwd, cwdlen);
57
58 if (n == cwdlen) {
59 snprintf(newfilename, sizeof(newfilename),
60 ".%s", filename + n);
61 filename = newfilename;
62 }
63 }
64
65 anon = is_anon_memory(filename); 45 anon = is_anon_memory(filename);
66 46
67 if (anon) { 47 if (anon) {
@@ -248,6 +228,39 @@ void map_groups__init(struct map_groups *self)
248 self->machine = NULL; 228 self->machine = NULL;
249} 229}
250 230
231static void maps__delete(struct rb_root *self)
232{
233 struct rb_node *next = rb_first(self);
234
235 while (next) {
236 struct map *pos = rb_entry(next, struct map, rb_node);
237
238 next = rb_next(&pos->rb_node);
239 rb_erase(&pos->rb_node, self);
240 map__delete(pos);
241 }
242}
243
244static void maps__delete_removed(struct list_head *self)
245{
246 struct map *pos, *n;
247
248 list_for_each_entry_safe(pos, n, self, node) {
249 list_del(&pos->node);
250 map__delete(pos);
251 }
252}
253
254void map_groups__exit(struct map_groups *self)
255{
256 int i;
257
258 for (i = 0; i < MAP__NR_TYPES; ++i) {
259 maps__delete(&self->maps[i]);
260 maps__delete_removed(&self->removed_maps[i]);
261 }
262}
263
251void map_groups__flush(struct map_groups *self) 264void map_groups__flush(struct map_groups *self)
252{ 265{
253 int type; 266 int type;
@@ -526,6 +539,32 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid)
526 return self->root_dir == NULL ? -ENOMEM : 0; 539 return self->root_dir == NULL ? -ENOMEM : 0;
527} 540}
528 541
542static void dsos__delete(struct list_head *self)
543{
544 struct dso *pos, *n;
545
546 list_for_each_entry_safe(pos, n, self, node) {
547 list_del(&pos->node);
548 dso__delete(pos);
549 }
550}
551
552void machine__exit(struct machine *self)
553{
554 struct kmap *kmap = map__kmap(self->vmlinux_maps[MAP__FUNCTION]);
555
556 if (kmap->ref_reloc_sym) {
557 free((char *)kmap->ref_reloc_sym->name);
558 free(kmap->ref_reloc_sym);
559 }
560
561 map_groups__exit(&self->kmaps);
562 dsos__delete(&self->user_dsos);
563 dsos__delete(&self->kernel_dsos);
564 free(self->root_dir);
565 self->root_dir = NULL;
566}
567
529struct machine *machines__add(struct rb_root *self, pid_t pid, 568struct machine *machines__add(struct rb_root *self, pid_t pid,
530 const char *root_dir) 569 const char *root_dir)
531{ 570{
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index f39134512829..0e0984e86fce 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -106,7 +106,7 @@ void map__init(struct map *self, enum map_type type,
106 u64 start, u64 end, u64 pgoff, struct dso *dso); 106 u64 start, u64 end, u64 pgoff, struct dso *dso);
107struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 107struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
108 u64 pgoff, u32 pid, char *filename, 108 u64 pgoff, u32 pid, char *filename,
109 enum map_type type, char *cwd, int cwdlen); 109 enum map_type type);
110void map__delete(struct map *self); 110void map__delete(struct map *self);
111struct map *map__clone(struct map *self); 111struct map *map__clone(struct map *self);
112int map__overlap(struct map *l, struct map *r); 112int map__overlap(struct map *l, struct map *r);
@@ -127,6 +127,7 @@ size_t __map_groups__fprintf_maps(struct map_groups *self,
127void maps__insert(struct rb_root *maps, struct map *map); 127void maps__insert(struct rb_root *maps, struct map *map);
128struct map *maps__find(struct rb_root *maps, u64 addr); 128struct map *maps__find(struct rb_root *maps, u64 addr);
129void map_groups__init(struct map_groups *self); 129void map_groups__init(struct map_groups *self);
130void map_groups__exit(struct map_groups *self);
130int map_groups__clone(struct map_groups *self, 131int map_groups__clone(struct map_groups *self,
131 struct map_groups *parent, enum map_type type); 132 struct map_groups *parent, enum map_type type);
132size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); 133size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
@@ -142,6 +143,7 @@ struct machine *machines__find(struct rb_root *self, pid_t pid);
142struct machine *machines__findnew(struct rb_root *self, pid_t pid); 143struct machine *machines__findnew(struct rb_root *self, pid_t pid);
143char *machine__mmap_name(struct machine *self, char *bf, size_t size); 144char *machine__mmap_name(struct machine *self, char *bf, size_t size);
144int machine__init(struct machine *self, const char *root_dir, pid_t pid); 145int machine__init(struct machine *self, const char *root_dir, pid_t pid);
146void machine__exit(struct machine *self);
145 147
146/* 148/*
147 * Default guest kernel is defined by parameter --guestkallsyms 149 * Default guest kernel is defined by parameter --guestkallsyms
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
index 7979003adeaf..91de99b58445 100644
--- a/tools/perf/util/newt.c
+++ b/tools/perf/util/newt.c
@@ -11,6 +11,7 @@
11#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG 11#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
12#endif 12#endif
13#include <slang.h> 13#include <slang.h>
14#include <signal.h>
14#include <stdlib.h> 15#include <stdlib.h>
15#include <newt.h> 16#include <newt.h>
16#include <sys/ttydefaults.h> 17#include <sys/ttydefaults.h>
@@ -342,15 +343,17 @@ static void ui_browser__reset_index(struct ui_browser *self)
342 343
343static int ui_browser__show(struct ui_browser *self, const char *title) 344static int ui_browser__show(struct ui_browser *self, const char *title)
344{ 345{
345 if (self->form != NULL) 346 if (self->form != NULL) {
346 return 0; 347 newtFormDestroy(self->form);
348 newtPopWindow();
349 }
347 ui_browser__refresh_dimensions(self); 350 ui_browser__refresh_dimensions(self);
348 newtCenteredWindow(self->width + 2, self->height, title); 351 newtCenteredWindow(self->width, self->height, title);
349 self->form = newt_form__new(); 352 self->form = newt_form__new();
350 if (self->form == NULL) 353 if (self->form == NULL)
351 return -1; 354 return -1;
352 355
353 self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height, 356 self->sb = newtVerticalScrollbar(self->width, 0, self->height,
354 HE_COLORSET_NORMAL, 357 HE_COLORSET_NORMAL,
355 HE_COLORSET_SELECTED); 358 HE_COLORSET_SELECTED);
356 if (self->sb == NULL) 359 if (self->sb == NULL)
@@ -507,38 +510,6 @@ static int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es)
507 return 0; 510 return 0;
508} 511}
509 512
510/*
511 * When debugging newt problems it was useful to be able to "unroll"
512 * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate
513 * a source file with the sequence of calls to these methods, to then
514 * tweak the arrays to get the intended results, so I'm keeping this code
515 * here, may be useful again in the future.
516 */
517#undef NEWT_DEBUG
518
519static void newt_checkbox_tree__add(newtComponent tree, const char *str,
520 void *priv, int *indexes)
521{
522#ifdef NEWT_DEBUG
523 /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */
524 int i = 0, len = 40 - strlen(str);
525
526 fprintf(stderr,
527 "\tnewtCheckboxTreeAddItem(tree, %*.*s\"%s\", (void *)%p, 0, ",
528 len, len, " ", str, priv);
529 while (indexes[i] != NEWT_ARG_LAST) {
530 if (indexes[i] != NEWT_ARG_APPEND)
531 fprintf(stderr, " %d,", indexes[i]);
532 else
533 fprintf(stderr, " %s,", "NEWT_ARG_APPEND");
534 ++i;
535 }
536 fprintf(stderr, " %s", " NEWT_ARG_LAST);\n");
537 fflush(stderr);
538#endif
539 newtCheckboxTreeAddArray(tree, str, priv, 0, indexes);
540}
541
542static char *callchain_list__sym_name(struct callchain_list *self, 513static char *callchain_list__sym_name(struct callchain_list *self,
543 char *bf, size_t bfsize) 514 char *bf, size_t bfsize)
544{ 515{
@@ -574,146 +545,6 @@ static unsigned int hist_entry__annotate_browser_refresh(struct ui_browser *self
574 return row; 545 return row;
575} 546}
576 547
577static void __callchain__append_graph_browser(struct callchain_node *self,
578 newtComponent tree, u64 total,
579 int *indexes, int depth)
580{
581 struct rb_node *node;
582 u64 new_total, remaining;
583 int idx = 0;
584
585 if (callchain_param.mode == CHAIN_GRAPH_REL)
586 new_total = self->children_hit;
587 else
588 new_total = total;
589
590 remaining = new_total;
591 node = rb_first(&self->rb_root);
592 while (node) {
593 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
594 struct rb_node *next = rb_next(node);
595 u64 cumul = cumul_hits(child);
596 struct callchain_list *chain;
597 int first = true, printed = 0;
598 int chain_idx = -1;
599 remaining -= cumul;
600
601 indexes[depth] = NEWT_ARG_APPEND;
602 indexes[depth + 1] = NEWT_ARG_LAST;
603
604 list_for_each_entry(chain, &child->val, list) {
605 char ipstr[BITS_PER_LONG / 4 + 1],
606 *alloc_str = NULL;
607 const char *str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
608
609 if (first) {
610 double percent = cumul * 100.0 / new_total;
611
612 first = false;
613 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
614 str = "Not enough memory!";
615 else
616 str = alloc_str;
617 } else {
618 indexes[depth] = idx;
619 indexes[depth + 1] = NEWT_ARG_APPEND;
620 indexes[depth + 2] = NEWT_ARG_LAST;
621 ++chain_idx;
622 }
623 newt_checkbox_tree__add(tree, str, &chain->ms, indexes);
624 free(alloc_str);
625 ++printed;
626 }
627
628 indexes[depth] = idx;
629 if (chain_idx != -1)
630 indexes[depth + 1] = chain_idx;
631 if (printed != 0)
632 ++idx;
633 __callchain__append_graph_browser(child, tree, new_total, indexes,
634 depth + (chain_idx != -1 ? 2 : 1));
635 node = next;
636 }
637}
638
639static void callchain__append_graph_browser(struct callchain_node *self,
640 newtComponent tree, u64 total,
641 int *indexes, int parent_idx)
642{
643 struct callchain_list *chain;
644 int i = 0;
645
646 indexes[1] = NEWT_ARG_APPEND;
647 indexes[2] = NEWT_ARG_LAST;
648
649 list_for_each_entry(chain, &self->val, list) {
650 char ipstr[BITS_PER_LONG / 4 + 1], *str;
651
652 if (chain->ip >= PERF_CONTEXT_MAX)
653 continue;
654
655 if (!i++ && sort__first_dimension == SORT_SYM)
656 continue;
657
658 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
659 newt_checkbox_tree__add(tree, str, &chain->ms, indexes);
660 }
661
662 indexes[1] = parent_idx;
663 indexes[2] = NEWT_ARG_APPEND;
664 indexes[3] = NEWT_ARG_LAST;
665 __callchain__append_graph_browser(self, tree, total, indexes, 2);
666}
667
668static void hist_entry__append_callchain_browser(struct hist_entry *self,
669 newtComponent tree, u64 total, int parent_idx)
670{
671 struct rb_node *rb_node;
672 int indexes[1024] = { [0] = parent_idx, };
673 int idx = 0;
674 struct callchain_node *chain;
675
676 rb_node = rb_first(&self->sorted_chain);
677 while (rb_node) {
678 chain = rb_entry(rb_node, struct callchain_node, rb_node);
679 switch (callchain_param.mode) {
680 case CHAIN_FLAT:
681 break;
682 case CHAIN_GRAPH_ABS: /* falldown */
683 case CHAIN_GRAPH_REL:
684 callchain__append_graph_browser(chain, tree, total, indexes, idx++);
685 break;
686 case CHAIN_NONE:
687 default:
688 break;
689 }
690 rb_node = rb_next(rb_node);
691 }
692}
693
694static size_t hist_entry__append_browser(struct hist_entry *self,
695 newtComponent tree, u64 total)
696{
697 char s[256];
698 size_t ret;
699
700 if (symbol_conf.exclude_other && !self->parent)
701 return 0;
702
703 ret = hist_entry__snprintf(self, s, sizeof(s), NULL,
704 false, 0, false, total);
705 if (symbol_conf.use_callchain) {
706 int indexes[2];
707
708 indexes[0] = NEWT_ARG_APPEND;
709 indexes[1] = NEWT_ARG_LAST;
710 newt_checkbox_tree__add(tree, s, &self->ms, indexes);
711 } else
712 newtListboxAppendEntry(tree, s, &self->ms);
713
714 return ret;
715}
716
717int hist_entry__tui_annotate(struct hist_entry *self) 548int hist_entry__tui_annotate(struct hist_entry *self)
718{ 549{
719 struct ui_browser browser; 550 struct ui_browser browser;
@@ -749,6 +580,7 @@ int hist_entry__tui_annotate(struct hist_entry *self)
749 580
750 browser.width += 18; /* Percentage */ 581 browser.width += 18; /* Percentage */
751 ui_browser__show(&browser, self->ms.sym->name); 582 ui_browser__show(&browser, self->ms.sym->name);
583 newtFormAddHotKey(browser.form, ' ');
752 ret = ui_browser__run(&browser, &es); 584 ret = ui_browser__run(&browser, &es);
753 newtFormDestroy(browser.form); 585 newtFormDestroy(browser.form);
754 newtPopWindow(); 586 newtPopWindow();
@@ -760,157 +592,48 @@ int hist_entry__tui_annotate(struct hist_entry *self)
760 return ret; 592 return ret;
761} 593}
762 594
763static const void *newt__symbol_tree_get_current(newtComponent self)
764{
765 if (symbol_conf.use_callchain)
766 return newtCheckboxTreeGetCurrent(self);
767 return newtListboxGetCurrent(self);
768}
769
770static void hist_browser__selection(newtComponent self, void *data)
771{
772 const struct map_symbol **symbol_ptr = data;
773 *symbol_ptr = newt__symbol_tree_get_current(self);
774}
775
776struct hist_browser { 595struct hist_browser {
777 newtComponent form, tree; 596 struct ui_browser b;
778 const struct map_symbol *selection; 597 struct hists *hists;
598 struct hist_entry *he_selection;
599 struct map_symbol *selection;
779}; 600};
780 601
781static struct hist_browser *hist_browser__new(void) 602static void hist_browser__reset(struct hist_browser *self);
603static int hist_browser__run(struct hist_browser *self, const char *title,
604 struct newtExitStruct *es);
605static unsigned int hist_browser__refresh_entries(struct ui_browser *self);
606static void ui_browser__hists_seek(struct ui_browser *self,
607 off_t offset, int whence);
608
609static struct hist_browser *hist_browser__new(struct hists *hists)
782{ 610{
783 struct hist_browser *self = malloc(sizeof(*self)); 611 struct hist_browser *self = zalloc(sizeof(*self));
784 612
785 if (self != NULL) 613 if (self) {
786 self->form = NULL; 614 self->hists = hists;
615 self->b.refresh_entries = hist_browser__refresh_entries;
616 self->b.seek = ui_browser__hists_seek;
617 }
787 618
788 return self; 619 return self;
789} 620}
790 621
791static void hist_browser__delete(struct hist_browser *self) 622static void hist_browser__delete(struct hist_browser *self)
792{ 623{
793 newtFormDestroy(self->form); 624 newtFormDestroy(self->b.form);
794 newtPopWindow(); 625 newtPopWindow();
795 free(self); 626 free(self);
796} 627}
797 628
798static int hist_browser__populate(struct hist_browser *self, struct hists *hists,
799 const char *title)
800{
801 int max_len = 0, idx, cols, rows;
802 struct ui_progress *progress;
803 struct rb_node *nd;
804 u64 curr_hist = 0;
805 char seq[] = ".", unit;
806 char str[256];
807 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
808
809 if (self->form) {
810 newtFormDestroy(self->form);
811 newtPopWindow();
812 }
813
814 nr_events = convert_unit(nr_events, &unit);
815 snprintf(str, sizeof(str), "Events: %lu%c ",
816 nr_events, unit);
817 newtDrawRootText(0, 0, str);
818
819 newtGetScreenSize(NULL, &rows);
820
821 if (symbol_conf.use_callchain)
822 self->tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq,
823 NEWT_FLAG_SCROLL);
824 else
825 self->tree = newtListbox(0, 0, rows - 5,
826 (NEWT_FLAG_SCROLL |
827 NEWT_FLAG_RETURNEXIT));
828
829 newtComponentAddCallback(self->tree, hist_browser__selection,
830 &self->selection);
831
832 progress = ui_progress__new("Adding entries to the browser...",
833 hists->nr_entries);
834 if (progress == NULL)
835 return -1;
836
837 idx = 0;
838 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
839 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
840 int len;
841
842 if (h->filtered)
843 continue;
844
845 len = hist_entry__append_browser(h, self->tree, hists->stats.total_period);
846 if (len > max_len)
847 max_len = len;
848 if (symbol_conf.use_callchain)
849 hist_entry__append_callchain_browser(h, self->tree,
850 hists->stats.total_period, idx++);
851 ++curr_hist;
852 if (curr_hist % 5)
853 ui_progress__update(progress, curr_hist);
854 }
855
856 ui_progress__delete(progress);
857
858 newtGetScreenSize(&cols, &rows);
859
860 if (max_len > cols)
861 max_len = cols - 3;
862
863 if (!symbol_conf.use_callchain)
864 newtListboxSetWidth(self->tree, max_len);
865
866 newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0),
867 rows - 5, title);
868 self->form = newt_form__new();
869 if (self->form == NULL)
870 return -1;
871
872 newtFormAddHotKey(self->form, 'A');
873 newtFormAddHotKey(self->form, 'a');
874 newtFormAddHotKey(self->form, 'D');
875 newtFormAddHotKey(self->form, 'd');
876 newtFormAddHotKey(self->form, 'T');
877 newtFormAddHotKey(self->form, 't');
878 newtFormAddHotKey(self->form, '?');
879 newtFormAddHotKey(self->form, 'H');
880 newtFormAddHotKey(self->form, 'h');
881 newtFormAddHotKey(self->form, NEWT_KEY_F1);
882 newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
883 newtFormAddHotKey(self->form, NEWT_KEY_TAB);
884 newtFormAddHotKey(self->form, NEWT_KEY_UNTAB);
885 newtFormAddComponents(self->form, self->tree, NULL);
886 self->selection = newt__symbol_tree_get_current(self->tree);
887
888 return 0;
889}
890
891static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self) 629static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
892{ 630{
893 int *indexes; 631 return self->he_selection;
894
895 if (!symbol_conf.use_callchain)
896 goto out;
897
898 indexes = newtCheckboxTreeFindItem(self->tree, (void *)self->selection);
899 if (indexes) {
900 bool is_hist_entry = indexes[1] == NEWT_ARG_LAST;
901 free(indexes);
902 if (is_hist_entry)
903 goto out;
904 }
905 return NULL;
906out:
907 return container_of(self->selection, struct hist_entry, ms);
908} 632}
909 633
910static struct thread *hist_browser__selected_thread(struct hist_browser *self) 634static struct thread *hist_browser__selected_thread(struct hist_browser *self)
911{ 635{
912 struct hist_entry *he = hist_browser__selected_entry(self); 636 return self->he_selection->thread;
913 return he ? he->thread : NULL;
914} 637}
915 638
916static int hist_browser__title(char *bf, size_t size, const char *ev_name, 639static int hist_browser__title(char *bf, size_t size, const char *ev_name,
@@ -932,7 +655,7 @@ static int hist_browser__title(char *bf, size_t size, const char *ev_name,
932 655
933int hists__browse(struct hists *self, const char *helpline, const char *ev_name) 656int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
934{ 657{
935 struct hist_browser *browser = hist_browser__new(); 658 struct hist_browser *browser = hist_browser__new(self);
936 struct pstack *fstack; 659 struct pstack *fstack;
937 const struct thread *thread_filter = NULL; 660 const struct thread *thread_filter = NULL;
938 const struct dso *dso_filter = NULL; 661 const struct dso *dso_filter = NULL;
@@ -951,8 +674,6 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
951 674
952 hist_browser__title(msg, sizeof(msg), ev_name, 675 hist_browser__title(msg, sizeof(msg), ev_name,
953 dso_filter, thread_filter); 676 dso_filter, thread_filter);
954 if (hist_browser__populate(browser, self, msg) < 0)
955 goto out_free_stack;
956 677
957 while (1) { 678 while (1) {
958 const struct thread *thread; 679 const struct thread *thread;
@@ -961,7 +682,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
961 int nr_options = 0, choice = 0, i, 682 int nr_options = 0, choice = 0, i,
962 annotate = -2, zoom_dso = -2, zoom_thread = -2; 683 annotate = -2, zoom_dso = -2, zoom_thread = -2;
963 684
964 newtFormRun(browser->form, &es); 685 if (hist_browser__run(browser, msg, &es))
686 break;
965 687
966 thread = hist_browser__selected_thread(browser); 688 thread = hist_browser__selected_thread(browser);
967 dso = browser->selection->map ? browser->selection->map->dso : NULL; 689 dso = browser->selection->map ? browser->selection->map->dso : NULL;
@@ -1096,8 +818,7 @@ zoom_out_dso:
1096 hists__filter_by_dso(self, dso_filter); 818 hists__filter_by_dso(self, dso_filter);
1097 hist_browser__title(msg, sizeof(msg), ev_name, 819 hist_browser__title(msg, sizeof(msg), ev_name,
1098 dso_filter, thread_filter); 820 dso_filter, thread_filter);
1099 if (hist_browser__populate(browser, self, msg) < 0) 821 hist_browser__reset(browser);
1100 goto out;
1101 } else if (choice == zoom_thread) { 822 } else if (choice == zoom_thread) {
1102zoom_thread: 823zoom_thread:
1103 if (thread_filter) { 824 if (thread_filter) {
@@ -1115,8 +836,7 @@ zoom_out_thread:
1115 hists__filter_by_thread(self, thread_filter); 836 hists__filter_by_thread(self, thread_filter);
1116 hist_browser__title(msg, sizeof(msg), ev_name, 837 hist_browser__title(msg, sizeof(msg), ev_name,
1117 dso_filter, thread_filter); 838 dso_filter, thread_filter);
1118 if (hist_browser__populate(browser, self, msg) < 0) 839 hist_browser__reset(browser);
1119 goto out;
1120 } 840 }
1121 } 841 }
1122out_free_stack: 842out_free_stack:
@@ -1172,6 +892,13 @@ static struct newtPercentTreeColors {
1172 "blue", "lightgray", 892 "blue", "lightgray",
1173}; 893};
1174 894
895static void newt_suspend(void *d __used)
896{
897 newtSuspend();
898 raise(SIGTSTP);
899 newtResume();
900}
901
1175void setup_browser(void) 902void setup_browser(void)
1176{ 903{
1177 struct newtPercentTreeColors *c = &defaultPercentTreeColors; 904 struct newtPercentTreeColors *c = &defaultPercentTreeColors;
@@ -1185,6 +912,7 @@ void setup_browser(void)
1185 use_browser = 1; 912 use_browser = 1;
1186 newtInit(); 913 newtInit();
1187 newtCls(); 914 newtCls();
915 newtSetSuspendCallback(newt_suspend, NULL);
1188 ui_helpline__puts(" "); 916 ui_helpline__puts(" ");
1189 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); 917 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg);
1190 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); 918 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg);
@@ -1203,3 +931,638 @@ void exit_browser(bool wait_for_ok)
1203 newtFinished(); 931 newtFinished();
1204 } 932 }
1205} 933}
934
935static void hist_browser__refresh_dimensions(struct hist_browser *self)
936{
937 /* 3 == +/- toggle symbol before actual hist_entry rendering */
938 self->b.width = 3 + (hists__sort_list_width(self->hists) +
939 sizeof("[k]"));
940}
941
942static void hist_browser__reset(struct hist_browser *self)
943{
944 self->b.nr_entries = self->hists->nr_entries;
945 hist_browser__refresh_dimensions(self);
946 ui_browser__reset_index(&self->b);
947}
948
949static char tree__folded_sign(bool unfolded)
950{
951 return unfolded ? '-' : '+';
952}
953
954static char map_symbol__folded(const struct map_symbol *self)
955{
956 return self->has_children ? tree__folded_sign(self->unfolded) : ' ';
957}
958
959static char hist_entry__folded(const struct hist_entry *self)
960{
961 return map_symbol__folded(&self->ms);
962}
963
964static char callchain_list__folded(const struct callchain_list *self)
965{
966 return map_symbol__folded(&self->ms);
967}
968
969static bool map_symbol__toggle_fold(struct map_symbol *self)
970{
971 if (!self->has_children)
972 return false;
973
974 self->unfolded = !self->unfolded;
975 return true;
976}
977
978#define LEVEL_OFFSET_STEP 3
979
980static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
981 struct callchain_node *chain_node,
982 u64 total, int level,
983 unsigned short row,
984 off_t *row_offset,
985 bool *is_current_entry)
986{
987 struct rb_node *node;
988 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
989 u64 new_total, remaining;
990
991 if (callchain_param.mode == CHAIN_GRAPH_REL)
992 new_total = chain_node->children_hit;
993 else
994 new_total = total;
995
996 remaining = new_total;
997 node = rb_first(&chain_node->rb_root);
998 while (node) {
999 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1000 struct rb_node *next = rb_next(node);
1001 u64 cumul = cumul_hits(child);
1002 struct callchain_list *chain;
1003 char folded_sign = ' ';
1004 int first = true;
1005 int extra_offset = 0;
1006
1007 remaining -= cumul;
1008
1009 list_for_each_entry(chain, &child->val, list) {
1010 char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
1011 const char *str;
1012 int color;
1013 bool was_first = first;
1014
1015 if (first) {
1016 first = false;
1017 chain->ms.has_children = chain->list.next != &child->val ||
1018 rb_first(&child->rb_root) != NULL;
1019 } else {
1020 extra_offset = LEVEL_OFFSET_STEP;
1021 chain->ms.has_children = chain->list.next == &child->val &&
1022 rb_first(&child->rb_root) != NULL;
1023 }
1024
1025 folded_sign = callchain_list__folded(chain);
1026 if (*row_offset != 0) {
1027 --*row_offset;
1028 goto do_next;
1029 }
1030
1031 alloc_str = NULL;
1032 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
1033 if (was_first) {
1034 double percent = cumul * 100.0 / new_total;
1035
1036 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1037 str = "Not enough memory!";
1038 else
1039 str = alloc_str;
1040 }
1041
1042 color = HE_COLORSET_NORMAL;
1043 width = self->b.width - (offset + extra_offset + 2);
1044 if (ui_browser__is_current_entry(&self->b, row)) {
1045 self->selection = &chain->ms;
1046 color = HE_COLORSET_SELECTED;
1047 *is_current_entry = true;
1048 }
1049
1050 SLsmg_set_color(color);
1051 SLsmg_gotorc(self->b.top + row, self->b.left);
1052 slsmg_write_nstring(" ", offset + extra_offset);
1053 slsmg_printf("%c ", folded_sign);
1054 slsmg_write_nstring(str, width);
1055 free(alloc_str);
1056
1057 if (++row == self->b.height)
1058 goto out;
1059do_next:
1060 if (folded_sign == '+')
1061 break;
1062 }
1063
1064 if (folded_sign == '-') {
1065 const int new_level = level + (extra_offset ? 2 : 1);
1066 row += hist_browser__show_callchain_node_rb_tree(self, child, new_total,
1067 new_level, row, row_offset,
1068 is_current_entry);
1069 }
1070 if (row == self->b.height)
1071 goto out;
1072 node = next;
1073 }
1074out:
1075 return row - first_row;
1076}
1077
1078static int hist_browser__show_callchain_node(struct hist_browser *self,
1079 struct callchain_node *node,
1080 int level, unsigned short row,
1081 off_t *row_offset,
1082 bool *is_current_entry)
1083{
1084 struct callchain_list *chain;
1085 int first_row = row,
1086 offset = level * LEVEL_OFFSET_STEP,
1087 width = self->b.width - offset;
1088 char folded_sign = ' ';
1089
1090 list_for_each_entry(chain, &node->val, list) {
1091 char ipstr[BITS_PER_LONG / 4 + 1], *s;
1092 int color;
1093 /*
1094 * FIXME: This should be moved to somewhere else,
1095 * probably when the callchain is created, so as not to
1096 * traverse it all over again
1097 */
1098 chain->ms.has_children = rb_first(&node->rb_root) != NULL;
1099 folded_sign = callchain_list__folded(chain);
1100
1101 if (*row_offset != 0) {
1102 --*row_offset;
1103 continue;
1104 }
1105
1106 color = HE_COLORSET_NORMAL;
1107 if (ui_browser__is_current_entry(&self->b, row)) {
1108 self->selection = &chain->ms;
1109 color = HE_COLORSET_SELECTED;
1110 *is_current_entry = true;
1111 }
1112
1113 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
1114 SLsmg_gotorc(self->b.top + row, self->b.left);
1115 SLsmg_set_color(color);
1116 slsmg_write_nstring(" ", offset);
1117 slsmg_printf("%c ", folded_sign);
1118 slsmg_write_nstring(s, width - 2);
1119
1120 if (++row == self->b.height)
1121 goto out;
1122 }
1123
1124 if (folded_sign == '-')
1125 row += hist_browser__show_callchain_node_rb_tree(self, node,
1126 self->hists->stats.total_period,
1127 level + 1, row,
1128 row_offset,
1129 is_current_entry);
1130out:
1131 return row - first_row;
1132}
1133
1134static int hist_browser__show_callchain(struct hist_browser *self,
1135 struct rb_root *chain,
1136 int level, unsigned short row,
1137 off_t *row_offset,
1138 bool *is_current_entry)
1139{
1140 struct rb_node *nd;
1141 int first_row = row;
1142
1143 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1144 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1145
1146 row += hist_browser__show_callchain_node(self, node, level,
1147 row, row_offset,
1148 is_current_entry);
1149 if (row == self->b.height)
1150 break;
1151 }
1152
1153 return row - first_row;
1154}
1155
1156static int hist_browser__show_entry(struct hist_browser *self,
1157 struct hist_entry *entry,
1158 unsigned short row)
1159{
1160 char s[256];
1161 double percent;
1162 int printed = 0;
1163 int color, width = self->b.width;
1164 char folded_sign = ' ';
1165 bool current_entry = ui_browser__is_current_entry(&self->b, row);
1166 off_t row_offset = entry->row_offset;
1167
1168 if (current_entry) {
1169 self->he_selection = entry;
1170 self->selection = &entry->ms;
1171 }
1172
1173 if (symbol_conf.use_callchain) {
1174 entry->ms.has_children = !RB_EMPTY_ROOT(&entry->sorted_chain);
1175 folded_sign = hist_entry__folded(entry);
1176 }
1177
1178 if (row_offset == 0) {
1179 hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false,
1180 0, false, self->hists->stats.total_period);
1181 percent = (entry->period * 100.0) / self->hists->stats.total_period;
1182
1183 color = HE_COLORSET_SELECTED;
1184 if (!current_entry) {
1185 if (percent >= MIN_RED)
1186 color = HE_COLORSET_TOP;
1187 else if (percent >= MIN_GREEN)
1188 color = HE_COLORSET_MEDIUM;
1189 else
1190 color = HE_COLORSET_NORMAL;
1191 }
1192
1193 SLsmg_set_color(color);
1194 SLsmg_gotorc(self->b.top + row, self->b.left);
1195 if (symbol_conf.use_callchain) {
1196 slsmg_printf("%c ", folded_sign);
1197 width -= 2;
1198 }
1199 slsmg_write_nstring(s, width);
1200 ++row;
1201 ++printed;
1202 } else
1203 --row_offset;
1204
1205 if (folded_sign == '-' && row != self->b.height) {
1206 printed += hist_browser__show_callchain(self, &entry->sorted_chain,
1207 1, row, &row_offset,
1208 &current_entry);
1209 if (current_entry)
1210 self->he_selection = entry;
1211 }
1212
1213 return printed;
1214}
1215
1216static unsigned int hist_browser__refresh_entries(struct ui_browser *self)
1217{
1218 unsigned row = 0;
1219 struct rb_node *nd;
1220 struct hist_browser *hb = container_of(self, struct hist_browser, b);
1221
1222 if (self->first_visible_entry == NULL)
1223 self->first_visible_entry = rb_first(&hb->hists->entries);
1224
1225 for (nd = self->first_visible_entry; nd; nd = rb_next(nd)) {
1226 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1227
1228 if (h->filtered)
1229 continue;
1230
1231 row += hist_browser__show_entry(hb, h, row);
1232 if (row == self->height)
1233 break;
1234 }
1235
1236 return row;
1237}
1238
1239static void callchain_node__init_have_children_rb_tree(struct callchain_node *self)
1240{
1241 struct rb_node *nd = rb_first(&self->rb_root);
1242
1243 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
1244 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
1245 struct callchain_list *chain;
1246 int first = true;
1247
1248 list_for_each_entry(chain, &child->val, list) {
1249 if (first) {
1250 first = false;
1251 chain->ms.has_children = chain->list.next != &child->val ||
1252 rb_first(&child->rb_root) != NULL;
1253 } else
1254 chain->ms.has_children = chain->list.next == &child->val &&
1255 rb_first(&child->rb_root) != NULL;
1256 }
1257
1258 callchain_node__init_have_children_rb_tree(child);
1259 }
1260}
1261
1262static void callchain_node__init_have_children(struct callchain_node *self)
1263{
1264 struct callchain_list *chain;
1265
1266 list_for_each_entry(chain, &self->val, list)
1267 chain->ms.has_children = rb_first(&self->rb_root) != NULL;
1268
1269 callchain_node__init_have_children_rb_tree(self);
1270}
1271
1272static void callchain__init_have_children(struct rb_root *self)
1273{
1274 struct rb_node *nd;
1275
1276 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
1277 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1278 callchain_node__init_have_children(node);
1279 }
1280}
1281
1282static void hist_entry__init_have_children(struct hist_entry *self)
1283{
1284 if (!self->init_have_children) {
1285 callchain__init_have_children(&self->sorted_chain);
1286 self->init_have_children = true;
1287 }
1288}
1289
1290static struct rb_node *hists__filter_entries(struct rb_node *nd)
1291{
1292 while (nd != NULL) {
1293 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1294 if (!h->filtered)
1295 return nd;
1296
1297 nd = rb_next(nd);
1298 }
1299
1300 return NULL;
1301}
1302
1303static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
1304{
1305 while (nd != NULL) {
1306 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1307 if (!h->filtered)
1308 return nd;
1309
1310 nd = rb_prev(nd);
1311 }
1312
1313 return NULL;
1314}
1315
1316static void ui_browser__hists_seek(struct ui_browser *self,
1317 off_t offset, int whence)
1318{
1319 struct hist_entry *h;
1320 struct rb_node *nd;
1321 bool first = true;
1322
1323 switch (whence) {
1324 case SEEK_SET:
1325 nd = hists__filter_entries(rb_first(self->entries));
1326 break;
1327 case SEEK_CUR:
1328 nd = self->first_visible_entry;
1329 goto do_offset;
1330 case SEEK_END:
1331 nd = hists__filter_prev_entries(rb_last(self->entries));
1332 first = false;
1333 break;
1334 default:
1335 return;
1336 }
1337
1338 /*
1339 * Moves not relative to the first visible entry invalidates its
1340 * row_offset:
1341 */
1342 h = rb_entry(self->first_visible_entry, struct hist_entry, rb_node);
1343 h->row_offset = 0;
1344
1345 /*
1346 * Here we have to check if nd is expanded (+), if it is we can't go
1347 * the next top level hist_entry, instead we must compute an offset of
1348 * what _not_ to show and not change the first visible entry.
1349 *
1350 * This offset increments when we are going from top to bottom and
1351 * decreases when we're going from bottom to top.
1352 *
1353 * As we don't have backpointers to the top level in the callchains
1354 * structure, we need to always print the whole hist_entry callchain,
1355 * skipping the first ones that are before the first visible entry
1356 * and stop when we printed enough lines to fill the screen.
1357 */
1358do_offset:
1359 if (offset > 0) {
1360 do {
1361 h = rb_entry(nd, struct hist_entry, rb_node);
1362 if (h->ms.unfolded) {
1363 u16 remaining = h->nr_rows - h->row_offset;
1364 if (offset > remaining) {
1365 offset -= remaining;
1366 h->row_offset = 0;
1367 } else {
1368 h->row_offset += offset;
1369 offset = 0;
1370 self->first_visible_entry = nd;
1371 break;
1372 }
1373 }
1374 nd = hists__filter_entries(rb_next(nd));
1375 if (nd == NULL)
1376 break;
1377 --offset;
1378 self->first_visible_entry = nd;
1379 } while (offset != 0);
1380 } else if (offset < 0) {
1381 while (1) {
1382 h = rb_entry(nd, struct hist_entry, rb_node);
1383 if (h->ms.unfolded) {
1384 if (first) {
1385 if (-offset > h->row_offset) {
1386 offset += h->row_offset;
1387 h->row_offset = 0;
1388 } else {
1389 h->row_offset += offset;
1390 offset = 0;
1391 self->first_visible_entry = nd;
1392 break;
1393 }
1394 } else {
1395 if (-offset > h->nr_rows) {
1396 offset += h->nr_rows;
1397 h->row_offset = 0;
1398 } else {
1399 h->row_offset = h->nr_rows + offset;
1400 offset = 0;
1401 self->first_visible_entry = nd;
1402 break;
1403 }
1404 }
1405 }
1406
1407 nd = hists__filter_prev_entries(rb_prev(nd));
1408 if (nd == NULL)
1409 break;
1410 ++offset;
1411 self->first_visible_entry = nd;
1412 if (offset == 0) {
1413 /*
1414 * Last unfiltered hist_entry, check if it is
1415 * unfolded, if it is then we should have
1416 * row_offset at its last entry.
1417 */
1418 h = rb_entry(nd, struct hist_entry, rb_node);
1419 if (h->ms.unfolded)
1420 h->row_offset = h->nr_rows;
1421 break;
1422 }
1423 first = false;
1424 }
1425 } else {
1426 self->first_visible_entry = nd;
1427 h = rb_entry(nd, struct hist_entry, rb_node);
1428 h->row_offset = 0;
1429 }
1430}
1431
1432static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
1433{
1434 int n = 0;
1435 struct rb_node *nd;
1436
1437 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
1438 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
1439 struct callchain_list *chain;
1440 char folded_sign = ' '; /* No children */
1441
1442 list_for_each_entry(chain, &child->val, list) {
1443 ++n;
1444 /* We need this because we may not have children */
1445 folded_sign = callchain_list__folded(chain);
1446 if (folded_sign == '+')
1447 break;
1448 }
1449
1450 if (folded_sign == '-') /* Have children and they're unfolded */
1451 n += callchain_node__count_rows_rb_tree(child);
1452 }
1453
1454 return n;
1455}
1456
1457static int callchain_node__count_rows(struct callchain_node *node)
1458{
1459 struct callchain_list *chain;
1460 bool unfolded = false;
1461 int n = 0;
1462
1463 list_for_each_entry(chain, &node->val, list) {
1464 ++n;
1465 unfolded = chain->ms.unfolded;
1466 }
1467
1468 if (unfolded)
1469 n += callchain_node__count_rows_rb_tree(node);
1470
1471 return n;
1472}
1473
1474static int callchain__count_rows(struct rb_root *chain)
1475{
1476 struct rb_node *nd;
1477 int n = 0;
1478
1479 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1480 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1481 n += callchain_node__count_rows(node);
1482 }
1483
1484 return n;
1485}
1486
1487static bool hist_browser__toggle_fold(struct hist_browser *self)
1488{
1489 if (map_symbol__toggle_fold(self->selection)) {
1490 struct hist_entry *he = self->he_selection;
1491
1492 hist_entry__init_have_children(he);
1493 self->hists->nr_entries -= he->nr_rows;
1494
1495 if (he->ms.unfolded)
1496 he->nr_rows = callchain__count_rows(&he->sorted_chain);
1497 else
1498 he->nr_rows = 0;
1499 self->hists->nr_entries += he->nr_rows;
1500 self->b.nr_entries = self->hists->nr_entries;
1501
1502 return true;
1503 }
1504
1505 /* If it doesn't have children, no toggling performed */
1506 return false;
1507}
1508
1509static int hist_browser__run(struct hist_browser *self, const char *title,
1510 struct newtExitStruct *es)
1511{
1512 char str[256], unit;
1513 unsigned long nr_events = self->hists->stats.nr_events[PERF_RECORD_SAMPLE];
1514
1515 self->b.entries = &self->hists->entries;
1516 self->b.nr_entries = self->hists->nr_entries;
1517
1518 hist_browser__refresh_dimensions(self);
1519
1520 nr_events = convert_unit(nr_events, &unit);
1521 snprintf(str, sizeof(str), "Events: %lu%c ",
1522 nr_events, unit);
1523 newtDrawRootText(0, 0, str);
1524
1525 if (ui_browser__show(&self->b, title) < 0)
1526 return -1;
1527
1528 newtFormAddHotKey(self->b.form, 'A');
1529 newtFormAddHotKey(self->b.form, 'a');
1530 newtFormAddHotKey(self->b.form, '?');
1531 newtFormAddHotKey(self->b.form, 'h');
1532 newtFormAddHotKey(self->b.form, 'H');
1533 newtFormAddHotKey(self->b.form, 'd');
1534
1535 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
1536 newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT);
1537 newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER);
1538
1539 while (1) {
1540 ui_browser__run(&self->b, es);
1541
1542 if (es->reason != NEWT_EXIT_HOTKEY)
1543 break;
1544 switch (es->u.key) {
1545 case 'd': { /* Debug */
1546 static int seq;
1547 struct hist_entry *h = rb_entry(self->b.first_visible_entry,
1548 struct hist_entry, rb_node);
1549 ui_helpline__pop();
1550 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
1551 seq++, self->b.nr_entries,
1552 self->hists->nr_entries,
1553 self->b.height,
1554 self->b.index,
1555 self->b.first_visible_entry_idx,
1556 h->row_offset, h->nr_rows);
1557 }
1558 continue;
1559 case NEWT_KEY_ENTER:
1560 if (hist_browser__toggle_fold(self))
1561 break;
1562 /* fall thru */
1563 default:
1564 return 0;
1565 }
1566 }
1567 return 0;
1568}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 4445a1e7052f..2e665cb84055 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * probe-event.c : perf-probe definition to kprobe_events format converter 2 * probe-event.c : perf-probe definition to probe_events format converter
3 * 3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com> 4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 * 5 *
@@ -120,8 +120,11 @@ static int open_vmlinux(void)
120 return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY); 120 return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
121} 121}
122 122
123/* Convert trace point to probe point with debuginfo */ 123/*
124static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, 124 * Convert trace point to probe point with debuginfo
125 * Currently only handles kprobes.
126 */
127static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
125 struct perf_probe_point *pp) 128 struct perf_probe_point *pp)
126{ 129{
127 struct symbol *sym; 130 struct symbol *sym;
@@ -151,8 +154,8 @@ static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
151} 154}
152 155
153/* Try to find perf_probe_event with debuginfo */ 156/* Try to find perf_probe_event with debuginfo */
154static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, 157static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
155 struct kprobe_trace_event **tevs, 158 struct probe_trace_event **tevs,
156 int max_tevs) 159 int max_tevs)
157{ 160{
158 bool need_dwarf = perf_probe_event_need_dwarf(pev); 161 bool need_dwarf = perf_probe_event_need_dwarf(pev);
@@ -169,11 +172,11 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
169 } 172 }
170 173
171 /* Searching trace events corresponding to probe event */ 174 /* Searching trace events corresponding to probe event */
172 ntevs = find_kprobe_trace_events(fd, pev, tevs, max_tevs); 175 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs);
173 close(fd); 176 close(fd);
174 177
175 if (ntevs > 0) { /* Succeeded to find trace events */ 178 if (ntevs > 0) { /* Succeeded to find trace events */
176 pr_debug("find %d kprobe_trace_events.\n", ntevs); 179 pr_debug("find %d probe_trace_events.\n", ntevs);
177 return ntevs; 180 return ntevs;
178 } 181 }
179 182
@@ -377,8 +380,8 @@ end:
377 380
378#else /* !DWARF_SUPPORT */ 381#else /* !DWARF_SUPPORT */
379 382
380static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, 383static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
381 struct perf_probe_point *pp) 384 struct perf_probe_point *pp)
382{ 385{
383 pp->function = strdup(tp->symbol); 386 pp->function = strdup(tp->symbol);
384 if (pp->function == NULL) 387 if (pp->function == NULL)
@@ -389,8 +392,8 @@ static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
389 return 0; 392 return 0;
390} 393}
391 394
392static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, 395static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
393 struct kprobe_trace_event **tevs __unused, 396 struct probe_trace_event **tevs __unused,
394 int max_tevs __unused) 397 int max_tevs __unused)
395{ 398{
396 if (perf_probe_event_need_dwarf(pev)) { 399 if (perf_probe_event_need_dwarf(pev)) {
@@ -781,16 +784,17 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
781 return false; 784 return false;
782} 785}
783 786
784/* Parse kprobe_events event into struct probe_point */ 787/* Parse probe_events event into struct probe_point */
785int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) 788static int parse_probe_trace_command(const char *cmd,
789 struct probe_trace_event *tev)
786{ 790{
787 struct kprobe_trace_point *tp = &tev->point; 791 struct probe_trace_point *tp = &tev->point;
788 char pr; 792 char pr;
789 char *p; 793 char *p;
790 int ret, i, argc; 794 int ret, i, argc;
791 char **argv; 795 char **argv;
792 796
793 pr_debug("Parsing kprobe_events: %s\n", cmd); 797 pr_debug("Parsing probe_events: %s\n", cmd);
794 argv = argv_split(cmd, &argc); 798 argv = argv_split(cmd, &argc);
795 if (!argv) { 799 if (!argv) {
796 pr_debug("Failed to split arguments.\n"); 800 pr_debug("Failed to split arguments.\n");
@@ -822,7 +826,7 @@ int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
822 tp->offset = 0; 826 tp->offset = 0;
823 827
824 tev->nargs = argc - 2; 828 tev->nargs = argc - 2;
825 tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); 829 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
826 if (tev->args == NULL) { 830 if (tev->args == NULL) {
827 ret = -ENOMEM; 831 ret = -ENOMEM;
828 goto out; 832 goto out;
@@ -968,13 +972,13 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev)
968} 972}
969#endif 973#endif
970 974
971static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref, 975static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
972 char **buf, size_t *buflen, 976 char **buf, size_t *buflen,
973 int depth) 977 int depth)
974{ 978{
975 int ret; 979 int ret;
976 if (ref->next) { 980 if (ref->next) {
977 depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf, 981 depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
978 buflen, depth + 1); 982 buflen, depth + 1);
979 if (depth < 0) 983 if (depth < 0)
980 goto out; 984 goto out;
@@ -992,10 +996,10 @@ out:
992 996
993} 997}
994 998
995static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, 999static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
996 char *buf, size_t buflen) 1000 char *buf, size_t buflen)
997{ 1001{
998 struct kprobe_trace_arg_ref *ref = arg->ref; 1002 struct probe_trace_arg_ref *ref = arg->ref;
999 int ret, depth = 0; 1003 int ret, depth = 0;
1000 char *tmp = buf; 1004 char *tmp = buf;
1001 1005
@@ -1015,7 +1019,7 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
1015 1019
1016 /* Dereferencing arguments */ 1020 /* Dereferencing arguments */
1017 if (ref) { 1021 if (ref) {
1018 depth = __synthesize_kprobe_trace_arg_ref(ref, &buf, 1022 depth = __synthesize_probe_trace_arg_ref(ref, &buf,
1019 &buflen, 1); 1023 &buflen, 1);
1020 if (depth < 0) 1024 if (depth < 0)
1021 return depth; 1025 return depth;
@@ -1051,9 +1055,9 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
1051 return buf - tmp; 1055 return buf - tmp;
1052} 1056}
1053 1057
1054char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev) 1058char *synthesize_probe_trace_command(struct probe_trace_event *tev)
1055{ 1059{
1056 struct kprobe_trace_point *tp = &tev->point; 1060 struct probe_trace_point *tp = &tev->point;
1057 char *buf; 1061 char *buf;
1058 int i, len, ret; 1062 int i, len, ret;
1059 1063
@@ -1069,7 +1073,7 @@ char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev)
1069 goto error; 1073 goto error;
1070 1074
1071 for (i = 0; i < tev->nargs; i++) { 1075 for (i = 0; i < tev->nargs; i++) {
1072 ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len, 1076 ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
1073 MAX_CMDLEN - len); 1077 MAX_CMDLEN - len);
1074 if (ret <= 0) 1078 if (ret <= 0)
1075 goto error; 1079 goto error;
@@ -1082,7 +1086,7 @@ error:
1082 return NULL; 1086 return NULL;
1083} 1087}
1084 1088
1085int convert_to_perf_probe_event(struct kprobe_trace_event *tev, 1089static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1086 struct perf_probe_event *pev) 1090 struct perf_probe_event *pev)
1087{ 1091{
1088 char buf[64] = ""; 1092 char buf[64] = "";
@@ -1095,7 +1099,7 @@ int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
1095 return -ENOMEM; 1099 return -ENOMEM;
1096 1100
1097 /* Convert trace_point to probe_point */ 1101 /* Convert trace_point to probe_point */
1098 ret = convert_to_perf_probe_point(&tev->point, &pev->point); 1102 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1099 if (ret < 0) 1103 if (ret < 0)
1100 return ret; 1104 return ret;
1101 1105
@@ -1108,7 +1112,7 @@ int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
1108 if (tev->args[i].name) 1112 if (tev->args[i].name)
1109 pev->args[i].name = strdup(tev->args[i].name); 1113 pev->args[i].name = strdup(tev->args[i].name);
1110 else { 1114 else {
1111 ret = synthesize_kprobe_trace_arg(&tev->args[i], 1115 ret = synthesize_probe_trace_arg(&tev->args[i],
1112 buf, 64); 1116 buf, 64);
1113 pev->args[i].name = strdup(buf); 1117 pev->args[i].name = strdup(buf);
1114 } 1118 }
@@ -1159,9 +1163,9 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
1159 memset(pev, 0, sizeof(*pev)); 1163 memset(pev, 0, sizeof(*pev));
1160} 1164}
1161 1165
1162void clear_kprobe_trace_event(struct kprobe_trace_event *tev) 1166static void clear_probe_trace_event(struct probe_trace_event *tev)
1163{ 1167{
1164 struct kprobe_trace_arg_ref *ref, *next; 1168 struct probe_trace_arg_ref *ref, *next;
1165 int i; 1169 int i;
1166 1170
1167 if (tev->event) 1171 if (tev->event)
@@ -1222,7 +1226,7 @@ static int open_kprobe_events(bool readwrite)
1222} 1226}
1223 1227
1224/* Get raw string list of current kprobe_events */ 1228/* Get raw string list of current kprobe_events */
1225static struct strlist *get_kprobe_trace_command_rawlist(int fd) 1229static struct strlist *get_probe_trace_command_rawlist(int fd)
1226{ 1230{
1227 int ret, idx; 1231 int ret, idx;
1228 FILE *fp; 1232 FILE *fp;
@@ -1290,7 +1294,7 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
1290int show_perf_probe_events(void) 1294int show_perf_probe_events(void)
1291{ 1295{
1292 int fd, ret; 1296 int fd, ret;
1293 struct kprobe_trace_event tev; 1297 struct probe_trace_event tev;
1294 struct perf_probe_event pev; 1298 struct perf_probe_event pev;
1295 struct strlist *rawlist; 1299 struct strlist *rawlist;
1296 struct str_node *ent; 1300 struct str_node *ent;
@@ -1307,20 +1311,20 @@ int show_perf_probe_events(void)
1307 if (fd < 0) 1311 if (fd < 0)
1308 return fd; 1312 return fd;
1309 1313
1310 rawlist = get_kprobe_trace_command_rawlist(fd); 1314 rawlist = get_probe_trace_command_rawlist(fd);
1311 close(fd); 1315 close(fd);
1312 if (!rawlist) 1316 if (!rawlist)
1313 return -ENOENT; 1317 return -ENOENT;
1314 1318
1315 strlist__for_each(ent, rawlist) { 1319 strlist__for_each(ent, rawlist) {
1316 ret = parse_kprobe_trace_command(ent->s, &tev); 1320 ret = parse_probe_trace_command(ent->s, &tev);
1317 if (ret >= 0) { 1321 if (ret >= 0) {
1318 ret = convert_to_perf_probe_event(&tev, &pev); 1322 ret = convert_to_perf_probe_event(&tev, &pev);
1319 if (ret >= 0) 1323 if (ret >= 0)
1320 ret = show_perf_probe_event(&pev); 1324 ret = show_perf_probe_event(&pev);
1321 } 1325 }
1322 clear_perf_probe_event(&pev); 1326 clear_perf_probe_event(&pev);
1323 clear_kprobe_trace_event(&tev); 1327 clear_probe_trace_event(&tev);
1324 if (ret < 0) 1328 if (ret < 0)
1325 break; 1329 break;
1326 } 1330 }
@@ -1330,20 +1334,19 @@ int show_perf_probe_events(void)
1330} 1334}
1331 1335
1332/* Get current perf-probe event names */ 1336/* Get current perf-probe event names */
1333static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group) 1337static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
1334{ 1338{
1335 char buf[128]; 1339 char buf[128];
1336 struct strlist *sl, *rawlist; 1340 struct strlist *sl, *rawlist;
1337 struct str_node *ent; 1341 struct str_node *ent;
1338 struct kprobe_trace_event tev; 1342 struct probe_trace_event tev;
1339 int ret = 0; 1343 int ret = 0;
1340 1344
1341 memset(&tev, 0, sizeof(tev)); 1345 memset(&tev, 0, sizeof(tev));
1342 1346 rawlist = get_probe_trace_command_rawlist(fd);
1343 rawlist = get_kprobe_trace_command_rawlist(fd);
1344 sl = strlist__new(true, NULL); 1347 sl = strlist__new(true, NULL);
1345 strlist__for_each(ent, rawlist) { 1348 strlist__for_each(ent, rawlist) {
1346 ret = parse_kprobe_trace_command(ent->s, &tev); 1349 ret = parse_probe_trace_command(ent->s, &tev);
1347 if (ret < 0) 1350 if (ret < 0)
1348 break; 1351 break;
1349 if (include_group) { 1352 if (include_group) {
@@ -1353,7 +1356,7 @@ static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
1353 ret = strlist__add(sl, buf); 1356 ret = strlist__add(sl, buf);
1354 } else 1357 } else
1355 ret = strlist__add(sl, tev.event); 1358 ret = strlist__add(sl, tev.event);
1356 clear_kprobe_trace_event(&tev); 1359 clear_probe_trace_event(&tev);
1357 if (ret < 0) 1360 if (ret < 0)
1358 break; 1361 break;
1359 } 1362 }
@@ -1366,13 +1369,13 @@ static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
1366 return sl; 1369 return sl;
1367} 1370}
1368 1371
1369static int write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev) 1372static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
1370{ 1373{
1371 int ret = 0; 1374 int ret = 0;
1372 char *buf = synthesize_kprobe_trace_command(tev); 1375 char *buf = synthesize_probe_trace_command(tev);
1373 1376
1374 if (!buf) { 1377 if (!buf) {
1375 pr_debug("Failed to synthesize kprobe trace event.\n"); 1378 pr_debug("Failed to synthesize probe trace event.\n");
1376 return -EINVAL; 1379 return -EINVAL;
1377 } 1380 }
1378 1381
@@ -1425,12 +1428,12 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
1425 return ret; 1428 return ret;
1426} 1429}
1427 1430
1428static int __add_kprobe_trace_events(struct perf_probe_event *pev, 1431static int __add_probe_trace_events(struct perf_probe_event *pev,
1429 struct kprobe_trace_event *tevs, 1432 struct probe_trace_event *tevs,
1430 int ntevs, bool allow_suffix) 1433 int ntevs, bool allow_suffix)
1431{ 1434{
1432 int i, fd, ret; 1435 int i, fd, ret;
1433 struct kprobe_trace_event *tev = NULL; 1436 struct probe_trace_event *tev = NULL;
1434 char buf[64]; 1437 char buf[64];
1435 const char *event, *group; 1438 const char *event, *group;
1436 struct strlist *namelist; 1439 struct strlist *namelist;
@@ -1439,7 +1442,7 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev,
1439 if (fd < 0) 1442 if (fd < 0)
1440 return fd; 1443 return fd;
1441 /* Get current event names */ 1444 /* Get current event names */
1442 namelist = get_kprobe_trace_event_names(fd, false); 1445 namelist = get_probe_trace_event_names(fd, false);
1443 if (!namelist) { 1446 if (!namelist) {
1444 pr_debug("Failed to get current event list.\n"); 1447 pr_debug("Failed to get current event list.\n");
1445 return -EIO; 1448 return -EIO;
@@ -1474,7 +1477,7 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev,
1474 ret = -ENOMEM; 1477 ret = -ENOMEM;
1475 break; 1478 break;
1476 } 1479 }
1477 ret = write_kprobe_trace_event(fd, tev); 1480 ret = write_probe_trace_event(fd, tev);
1478 if (ret < 0) 1481 if (ret < 0)
1479 break; 1482 break;
1480 /* Add added event name to namelist */ 1483 /* Add added event name to namelist */
@@ -1511,21 +1514,21 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev,
1511 return ret; 1514 return ret;
1512} 1515}
1513 1516
1514static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, 1517static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1515 struct kprobe_trace_event **tevs, 1518 struct probe_trace_event **tevs,
1516 int max_tevs) 1519 int max_tevs)
1517{ 1520{
1518 struct symbol *sym; 1521 struct symbol *sym;
1519 int ret = 0, i; 1522 int ret = 0, i;
1520 struct kprobe_trace_event *tev; 1523 struct probe_trace_event *tev;
1521 1524
1522 /* Convert perf_probe_event with debuginfo */ 1525 /* Convert perf_probe_event with debuginfo */
1523 ret = try_to_find_kprobe_trace_events(pev, tevs, max_tevs); 1526 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs);
1524 if (ret != 0) 1527 if (ret != 0)
1525 return ret; 1528 return ret;
1526 1529
1527 /* Allocate trace event buffer */ 1530 /* Allocate trace event buffer */
1528 tev = *tevs = zalloc(sizeof(struct kprobe_trace_event)); 1531 tev = *tevs = zalloc(sizeof(struct probe_trace_event));
1529 if (tev == NULL) 1532 if (tev == NULL)
1530 return -ENOMEM; 1533 return -ENOMEM;
1531 1534
@@ -1538,7 +1541,7 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
1538 tev->point.offset = pev->point.offset; 1541 tev->point.offset = pev->point.offset;
1539 tev->nargs = pev->nargs; 1542 tev->nargs = pev->nargs;
1540 if (tev->nargs) { 1543 if (tev->nargs) {
1541 tev->args = zalloc(sizeof(struct kprobe_trace_arg) 1544 tev->args = zalloc(sizeof(struct probe_trace_arg)
1542 * tev->nargs); 1545 * tev->nargs);
1543 if (tev->args == NULL) { 1546 if (tev->args == NULL) {
1544 ret = -ENOMEM; 1547 ret = -ENOMEM;
@@ -1579,7 +1582,7 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
1579 1582
1580 return 1; 1583 return 1;
1581error: 1584error:
1582 clear_kprobe_trace_event(tev); 1585 clear_probe_trace_event(tev);
1583 free(tev); 1586 free(tev);
1584 *tevs = NULL; 1587 *tevs = NULL;
1585 return ret; 1588 return ret;
@@ -1587,7 +1590,7 @@ error:
1587 1590
1588struct __event_package { 1591struct __event_package {
1589 struct perf_probe_event *pev; 1592 struct perf_probe_event *pev;
1590 struct kprobe_trace_event *tevs; 1593 struct probe_trace_event *tevs;
1591 int ntevs; 1594 int ntevs;
1592}; 1595};
1593 1596
@@ -1610,7 +1613,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1610 for (i = 0; i < npevs; i++) { 1613 for (i = 0; i < npevs; i++) {
1611 pkgs[i].pev = &pevs[i]; 1614 pkgs[i].pev = &pevs[i];
1612 /* Convert with or without debuginfo */ 1615 /* Convert with or without debuginfo */
1613 ret = convert_to_kprobe_trace_events(pkgs[i].pev, 1616 ret = convert_to_probe_trace_events(pkgs[i].pev,
1614 &pkgs[i].tevs, max_tevs); 1617 &pkgs[i].tevs, max_tevs);
1615 if (ret < 0) 1618 if (ret < 0)
1616 goto end; 1619 goto end;
@@ -1619,24 +1622,24 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1619 1622
1620 /* Loop 2: add all events */ 1623 /* Loop 2: add all events */
1621 for (i = 0; i < npevs && ret >= 0; i++) 1624 for (i = 0; i < npevs && ret >= 0; i++)
1622 ret = __add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs, 1625 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
1623 pkgs[i].ntevs, force_add); 1626 pkgs[i].ntevs, force_add);
1624end: 1627end:
1625 /* Loop 3: cleanup trace events */ 1628 /* Loop 3: cleanup trace events */
1626 for (i = 0; i < npevs; i++) 1629 for (i = 0; i < npevs; i++)
1627 for (j = 0; j < pkgs[i].ntevs; j++) 1630 for (j = 0; j < pkgs[i].ntevs; j++)
1628 clear_kprobe_trace_event(&pkgs[i].tevs[j]); 1631 clear_probe_trace_event(&pkgs[i].tevs[j]);
1629 1632
1630 return ret; 1633 return ret;
1631} 1634}
1632 1635
1633static int __del_trace_kprobe_event(int fd, struct str_node *ent) 1636static int __del_trace_probe_event(int fd, struct str_node *ent)
1634{ 1637{
1635 char *p; 1638 char *p;
1636 char buf[128]; 1639 char buf[128];
1637 int ret; 1640 int ret;
1638 1641
1639 /* Convert from perf-probe event to trace-kprobe event */ 1642 /* Convert from perf-probe event to trace-probe event */
1640 ret = e_snprintf(buf, 128, "-:%s", ent->s); 1643 ret = e_snprintf(buf, 128, "-:%s", ent->s);
1641 if (ret < 0) 1644 if (ret < 0)
1642 goto error; 1645 goto error;
@@ -1662,7 +1665,7 @@ error:
1662 return ret; 1665 return ret;
1663} 1666}
1664 1667
1665static int del_trace_kprobe_event(int fd, const char *group, 1668static int del_trace_probe_event(int fd, const char *group,
1666 const char *event, struct strlist *namelist) 1669 const char *event, struct strlist *namelist)
1667{ 1670{
1668 char buf[128]; 1671 char buf[128];
@@ -1679,7 +1682,7 @@ static int del_trace_kprobe_event(int fd, const char *group,
1679 strlist__for_each_safe(ent, n, namelist) 1682 strlist__for_each_safe(ent, n, namelist)
1680 if (strglobmatch(ent->s, buf)) { 1683 if (strglobmatch(ent->s, buf)) {
1681 found++; 1684 found++;
1682 ret = __del_trace_kprobe_event(fd, ent); 1685 ret = __del_trace_probe_event(fd, ent);
1683 if (ret < 0) 1686 if (ret < 0)
1684 break; 1687 break;
1685 strlist__remove(namelist, ent); 1688 strlist__remove(namelist, ent);
@@ -1688,7 +1691,7 @@ static int del_trace_kprobe_event(int fd, const char *group,
1688 ent = strlist__find(namelist, buf); 1691 ent = strlist__find(namelist, buf);
1689 if (ent) { 1692 if (ent) {
1690 found++; 1693 found++;
1691 ret = __del_trace_kprobe_event(fd, ent); 1694 ret = __del_trace_probe_event(fd, ent);
1692 if (ret >= 0) 1695 if (ret >= 0)
1693 strlist__remove(namelist, ent); 1696 strlist__remove(namelist, ent);
1694 } 1697 }
@@ -1712,7 +1715,7 @@ int del_perf_probe_events(struct strlist *dellist)
1712 return fd; 1715 return fd;
1713 1716
1714 /* Get current event names */ 1717 /* Get current event names */
1715 namelist = get_kprobe_trace_event_names(fd, true); 1718 namelist = get_probe_trace_event_names(fd, true);
1716 if (namelist == NULL) 1719 if (namelist == NULL)
1717 return -EINVAL; 1720 return -EINVAL;
1718 1721
@@ -1733,7 +1736,7 @@ int del_perf_probe_events(struct strlist *dellist)
1733 event = str; 1736 event = str;
1734 } 1737 }
1735 pr_debug("Group: %s, Event: %s\n", group, event); 1738 pr_debug("Group: %s, Event: %s\n", group, event);
1736 ret = del_trace_kprobe_event(fd, group, event, namelist); 1739 ret = del_trace_probe_event(fd, group, event, namelist);
1737 free(str); 1740 free(str);
1738 if (ret < 0) 1741 if (ret < 0)
1739 break; 1742 break;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index ed362acff4b6..5af39243a25b 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,33 +7,33 @@
7extern bool probe_event_dry_run; 7extern bool probe_event_dry_run;
8 8
9/* kprobe-tracer tracing point */ 9/* kprobe-tracer tracing point */
10struct kprobe_trace_point { 10struct probe_trace_point {
11 char *symbol; /* Base symbol */ 11 char *symbol; /* Base symbol */
12 unsigned long offset; /* Offset from symbol */ 12 unsigned long offset; /* Offset from symbol */
13 bool retprobe; /* Return probe flag */ 13 bool retprobe; /* Return probe flag */
14}; 14};
15 15
16/* kprobe-tracer tracing argument referencing offset */ 16/* probe-tracer tracing argument referencing offset */
17struct kprobe_trace_arg_ref { 17struct probe_trace_arg_ref {
18 struct kprobe_trace_arg_ref *next; /* Next reference */ 18 struct probe_trace_arg_ref *next; /* Next reference */
19 long offset; /* Offset value */ 19 long offset; /* Offset value */
20}; 20};
21 21
22/* kprobe-tracer tracing argument */ 22/* kprobe-tracer tracing argument */
23struct kprobe_trace_arg { 23struct probe_trace_arg {
24 char *name; /* Argument name */ 24 char *name; /* Argument name */
25 char *value; /* Base value */ 25 char *value; /* Base value */
26 char *type; /* Type name */ 26 char *type; /* Type name */
27 struct kprobe_trace_arg_ref *ref; /* Referencing offset */ 27 struct probe_trace_arg_ref *ref; /* Referencing offset */
28}; 28};
29 29
30/* kprobe-tracer tracing event (point + arg) */ 30/* kprobe-tracer tracing event (point + arg) */
31struct kprobe_trace_event { 31struct probe_trace_event {
32 char *event; /* Event name */ 32 char *event; /* Event name */
33 char *group; /* Group name */ 33 char *group; /* Group name */
34 struct kprobe_trace_point point; /* Trace point */ 34 struct probe_trace_point point; /* Trace point */
35 int nargs; /* Number of args */ 35 int nargs; /* Number of args */
36 struct kprobe_trace_arg *args; /* Arguments */ 36 struct probe_trace_arg *args; /* Arguments */
37}; 37};
38 38
39/* Perf probe probing point */ 39/* Perf probe probing point */
@@ -93,25 +93,18 @@ struct line_range {
93/* Command string to events */ 93/* Command string to events */
94extern int parse_perf_probe_command(const char *cmd, 94extern int parse_perf_probe_command(const char *cmd,
95 struct perf_probe_event *pev); 95 struct perf_probe_event *pev);
96extern int parse_kprobe_trace_command(const char *cmd,
97 struct kprobe_trace_event *tev);
98 96
99/* Events to command string */ 97/* Events to command string */
100extern char *synthesize_perf_probe_command(struct perf_probe_event *pev); 98extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
101extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev); 99extern char *synthesize_probe_trace_command(struct probe_trace_event *tev);
102extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, 100extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf,
103 size_t len); 101 size_t len);
104 102
105/* Check the perf_probe_event needs debuginfo */ 103/* Check the perf_probe_event needs debuginfo */
106extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); 104extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
107 105
108/* Convert from kprobe_trace_event to perf_probe_event */
109extern int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
110 struct perf_probe_event *pev);
111
112/* Release event contents */ 106/* Release event contents */
113extern void clear_perf_probe_event(struct perf_probe_event *pev); 107extern void clear_perf_probe_event(struct perf_probe_event *pev);
114extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev);
115 108
116/* Command string to line-range */ 109/* Command string to line-range */
117extern int parse_line_range_desc(const char *cmd, struct line_range *lr); 110extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index f88070ea5b90..840f1aabbb74 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -366,10 +366,10 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
366 * Probe finder related functions 366 * Probe finder related functions
367 */ 367 */
368 368
369static struct kprobe_trace_arg_ref *alloc_trace_arg_ref(long offs) 369static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
370{ 370{
371 struct kprobe_trace_arg_ref *ref; 371 struct probe_trace_arg_ref *ref;
372 ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); 372 ref = zalloc(sizeof(struct probe_trace_arg_ref));
373 if (ref != NULL) 373 if (ref != NULL)
374 ref->offset = offs; 374 ref->offset = offs;
375 return ref; 375 return ref;
@@ -385,7 +385,7 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
385 Dwarf_Word offs = 0; 385 Dwarf_Word offs = 0;
386 bool ref = false; 386 bool ref = false;
387 const char *regs; 387 const char *regs;
388 struct kprobe_trace_arg *tvar = pf->tvar; 388 struct probe_trace_arg *tvar = pf->tvar;
389 int ret; 389 int ret;
390 390
391 /* TODO: handle more than 1 exprs */ 391 /* TODO: handle more than 1 exprs */
@@ -459,10 +459,10 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
459} 459}
460 460
461static int convert_variable_type(Dwarf_Die *vr_die, 461static int convert_variable_type(Dwarf_Die *vr_die,
462 struct kprobe_trace_arg *tvar, 462 struct probe_trace_arg *tvar,
463 const char *cast) 463 const char *cast)
464{ 464{
465 struct kprobe_trace_arg_ref **ref_ptr = &tvar->ref; 465 struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
466 Dwarf_Die type; 466 Dwarf_Die type;
467 char buf[16]; 467 char buf[16];
468 int ret; 468 int ret;
@@ -500,7 +500,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
500 while (*ref_ptr) 500 while (*ref_ptr)
501 ref_ptr = &(*ref_ptr)->next; 501 ref_ptr = &(*ref_ptr)->next;
502 /* Add new reference with offset +0 */ 502 /* Add new reference with offset +0 */
503 *ref_ptr = zalloc(sizeof(struct kprobe_trace_arg_ref)); 503 *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
504 if (*ref_ptr == NULL) { 504 if (*ref_ptr == NULL) {
505 pr_warning("Out of memory error\n"); 505 pr_warning("Out of memory error\n");
506 return -ENOMEM; 506 return -ENOMEM;
@@ -545,10 +545,10 @@ static int convert_variable_type(Dwarf_Die *vr_die,
545 545
546static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 546static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
547 struct perf_probe_arg_field *field, 547 struct perf_probe_arg_field *field,
548 struct kprobe_trace_arg_ref **ref_ptr, 548 struct probe_trace_arg_ref **ref_ptr,
549 Dwarf_Die *die_mem) 549 Dwarf_Die *die_mem)
550{ 550{
551 struct kprobe_trace_arg_ref *ref = *ref_ptr; 551 struct probe_trace_arg_ref *ref = *ref_ptr;
552 Dwarf_Die type; 552 Dwarf_Die type;
553 Dwarf_Word offs; 553 Dwarf_Word offs;
554 int ret, tag; 554 int ret, tag;
@@ -574,7 +574,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
574 pr_debug2("Array real type: (%x)\n", 574 pr_debug2("Array real type: (%x)\n",
575 (unsigned)dwarf_dieoffset(&type)); 575 (unsigned)dwarf_dieoffset(&type));
576 if (tag == DW_TAG_pointer_type) { 576 if (tag == DW_TAG_pointer_type) {
577 ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); 577 ref = zalloc(sizeof(struct probe_trace_arg_ref));
578 if (ref == NULL) 578 if (ref == NULL)
579 return -ENOMEM; 579 return -ENOMEM;
580 if (*ref_ptr) 580 if (*ref_ptr)
@@ -605,7 +605,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
605 return -EINVAL; 605 return -EINVAL;
606 } 606 }
607 607
608 ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); 608 ref = zalloc(sizeof(struct probe_trace_arg_ref));
609 if (ref == NULL) 609 if (ref == NULL)
610 return -ENOMEM; 610 return -ENOMEM;
611 if (*ref_ptr) 611 if (*ref_ptr)
@@ -738,7 +738,7 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
738/* Show a probe point to output buffer */ 738/* Show a probe point to output buffer */
739static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) 739static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
740{ 740{
741 struct kprobe_trace_event *tev; 741 struct probe_trace_event *tev;
742 Dwarf_Addr eaddr; 742 Dwarf_Addr eaddr;
743 Dwarf_Die die_mem; 743 Dwarf_Die die_mem;
744 const char *name; 744 const char *name;
@@ -803,7 +803,7 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
803 803
804 /* Find each argument */ 804 /* Find each argument */
805 tev->nargs = pf->pev->nargs; 805 tev->nargs = pf->pev->nargs;
806 tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); 806 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
807 if (tev->args == NULL) 807 if (tev->args == NULL)
808 return -ENOMEM; 808 return -ENOMEM;
809 for (i = 0; i < pf->pev->nargs; i++) { 809 for (i = 0; i < pf->pev->nargs; i++) {
@@ -1060,9 +1060,9 @@ static int find_probe_point_by_func(struct probe_finder *pf)
1060 return _param.retval; 1060 return _param.retval;
1061} 1061}
1062 1062
1063/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ 1063/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1064int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, 1064int find_probe_trace_events(int fd, struct perf_probe_event *pev,
1065 struct kprobe_trace_event **tevs, int max_tevs) 1065 struct probe_trace_event **tevs, int max_tevs)
1066{ 1066{
1067 struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs}; 1067 struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};
1068 struct perf_probe_point *pp = &pev->point; 1068 struct perf_probe_point *pp = &pev->point;
@@ -1072,7 +1072,7 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
1072 Dwarf *dbg; 1072 Dwarf *dbg;
1073 int ret = 0; 1073 int ret = 0;
1074 1074
1075 pf.tevs = zalloc(sizeof(struct kprobe_trace_event) * max_tevs); 1075 pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
1076 if (pf.tevs == NULL) 1076 if (pf.tevs == NULL)
1077 return -ENOMEM; 1077 return -ENOMEM;
1078 *tevs = pf.tevs; 1078 *tevs = pf.tevs;
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index e1f61dcd18ff..4507d519f183 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -16,9 +16,9 @@ static inline int is_c_varname(const char *name)
16} 16}
17 17
18#ifdef DWARF_SUPPORT 18#ifdef DWARF_SUPPORT
19/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ 19/* Find probe_trace_events specified by perf_probe_event from debuginfo */
20extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, 20extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
21 struct kprobe_trace_event **tevs, 21 struct probe_trace_event **tevs,
22 int max_tevs); 22 int max_tevs);
23 23
24/* Find a perf_probe_point from debuginfo */ 24/* Find a perf_probe_point from debuginfo */
@@ -33,7 +33,7 @@ extern int find_line_range(int fd, struct line_range *lr);
33 33
34struct probe_finder { 34struct probe_finder {
35 struct perf_probe_event *pev; /* Target probe event */ 35 struct perf_probe_event *pev; /* Target probe event */
36 struct kprobe_trace_event *tevs; /* Result trace events */ 36 struct probe_trace_event *tevs; /* Result trace events */
37 int ntevs; /* Number of trace events */ 37 int ntevs; /* Number of trace events */
38 int max_tevs; /* Max number of trace events */ 38 int max_tevs; /* Max number of trace events */
39 39
@@ -50,7 +50,7 @@ struct probe_finder {
50#endif 50#endif
51 Dwarf_Op *fb_ops; /* Frame base attribute */ 51 Dwarf_Op *fb_ops; /* Frame base attribute */
52 struct perf_probe_arg *pvar; /* Current target variable */ 52 struct perf_probe_arg *pvar; /* Current target variable */
53 struct kprobe_trace_arg *tvar; /* Current result variable */ 53 struct probe_trace_arg *tvar; /* Current result variable */
54}; 54};
55 55
56struct line_finder { 56struct line_finder {
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 030791870e33..04a3b3db9e90 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -96,8 +96,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
96 self->hists_tree = RB_ROOT; 96 self->hists_tree = RB_ROOT;
97 self->last_match = NULL; 97 self->last_match = NULL;
98 self->mmap_window = 32; 98 self->mmap_window = 32;
99 self->cwd = NULL;
100 self->cwdlen = 0;
101 self->machines = RB_ROOT; 99 self->machines = RB_ROOT;
102 self->repipe = repipe; 100 self->repipe = repipe;
103 INIT_LIST_HEAD(&self->ordered_samples.samples_head); 101 INIT_LIST_HEAD(&self->ordered_samples.samples_head);
@@ -126,11 +124,36 @@ out_delete:
126 return NULL; 124 return NULL;
127} 125}
128 126
127static void perf_session__delete_dead_threads(struct perf_session *self)
128{
129 struct thread *n, *t;
130
131 list_for_each_entry_safe(t, n, &self->dead_threads, node) {
132 list_del(&t->node);
133 thread__delete(t);
134 }
135}
136
137static void perf_session__delete_threads(struct perf_session *self)
138{
139 struct rb_node *nd = rb_first(&self->threads);
140
141 while (nd) {
142 struct thread *t = rb_entry(nd, struct thread, rb_node);
143
144 rb_erase(&t->rb_node, &self->threads);
145 nd = rb_next(nd);
146 thread__delete(t);
147 }
148}
149
129void perf_session__delete(struct perf_session *self) 150void perf_session__delete(struct perf_session *self)
130{ 151{
131 perf_header__exit(&self->header); 152 perf_header__exit(&self->header);
153 perf_session__delete_dead_threads(self);
154 perf_session__delete_threads(self);
155 machine__exit(&self->host_machine);
132 close(self->fd); 156 close(self->fd);
133 free(self->cwd);
134 free(self); 157 free(self);
135} 158}
136 159
@@ -832,23 +855,6 @@ int perf_session__process_events(struct perf_session *self,
832 if (perf_session__register_idle_thread(self) == NULL) 855 if (perf_session__register_idle_thread(self) == NULL)
833 return -ENOMEM; 856 return -ENOMEM;
834 857
835 if (!symbol_conf.full_paths) {
836 char bf[PATH_MAX];
837
838 if (getcwd(bf, sizeof(bf)) == NULL) {
839 err = -errno;
840out_getcwd_err:
841 pr_err("failed to get the current directory\n");
842 goto out_err;
843 }
844 self->cwd = strdup(bf);
845 if (self->cwd == NULL) {
846 err = -ENOMEM;
847 goto out_getcwd_err;
848 }
849 self->cwdlen = strlen(self->cwd);
850 }
851
852 if (!self->fd_pipe) 858 if (!self->fd_pipe)
853 err = __perf_session__process_events(self, 859 err = __perf_session__process_events(self,
854 self->header.data_offset, 860 self->header.data_offset,
@@ -856,7 +862,7 @@ out_getcwd_err:
856 self->size, ops); 862 self->size, ops);
857 else 863 else
858 err = __perf_session__process_pipe_events(self, ops); 864 err = __perf_session__process_pipe_events(self, ops);
859out_err: 865
860 return err; 866 return err;
861} 867}
862 868
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index c27b4b03fbc1..1c61a4f4aa8a 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,4 +1,5 @@
1#include "sort.h" 1#include "sort.h"
2#include "hist.h"
2 3
3regex_t parent_regex; 4regex_t parent_regex;
4const char default_parent_pattern[] = "^sys_|^do_page_fault"; 5const char default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -10,11 +11,6 @@ int sort__has_parent = 0;
10 11
11enum sort_type sort__first_dimension; 12enum sort_type sort__first_dimension;
12 13
13unsigned int dsos__col_width;
14unsigned int comms__col_width;
15unsigned int threads__col_width;
16unsigned int cpus__col_width;
17static unsigned int parent_symbol__col_width;
18char * field_sep; 14char * field_sep;
19 15
20LIST_HEAD(hist_entry__sort_list); 16LIST_HEAD(hist_entry__sort_list);
@@ -36,7 +32,7 @@ struct sort_entry sort_thread = {
36 .se_header = "Command: Pid", 32 .se_header = "Command: Pid",
37 .se_cmp = sort__thread_cmp, 33 .se_cmp = sort__thread_cmp,
38 .se_snprintf = hist_entry__thread_snprintf, 34 .se_snprintf = hist_entry__thread_snprintf,
39 .se_width = &threads__col_width, 35 .se_width_idx = HISTC_THREAD,
40}; 36};
41 37
42struct sort_entry sort_comm = { 38struct sort_entry sort_comm = {
@@ -44,34 +40,35 @@ struct sort_entry sort_comm = {
44 .se_cmp = sort__comm_cmp, 40 .se_cmp = sort__comm_cmp,
45 .se_collapse = sort__comm_collapse, 41 .se_collapse = sort__comm_collapse,
46 .se_snprintf = hist_entry__comm_snprintf, 42 .se_snprintf = hist_entry__comm_snprintf,
47 .se_width = &comms__col_width, 43 .se_width_idx = HISTC_COMM,
48}; 44};
49 45
50struct sort_entry sort_dso = { 46struct sort_entry sort_dso = {
51 .se_header = "Shared Object", 47 .se_header = "Shared Object",
52 .se_cmp = sort__dso_cmp, 48 .se_cmp = sort__dso_cmp,
53 .se_snprintf = hist_entry__dso_snprintf, 49 .se_snprintf = hist_entry__dso_snprintf,
54 .se_width = &dsos__col_width, 50 .se_width_idx = HISTC_DSO,
55}; 51};
56 52
57struct sort_entry sort_sym = { 53struct sort_entry sort_sym = {
58 .se_header = "Symbol", 54 .se_header = "Symbol",
59 .se_cmp = sort__sym_cmp, 55 .se_cmp = sort__sym_cmp,
60 .se_snprintf = hist_entry__sym_snprintf, 56 .se_snprintf = hist_entry__sym_snprintf,
57 .se_width_idx = HISTC_SYMBOL,
61}; 58};
62 59
63struct sort_entry sort_parent = { 60struct sort_entry sort_parent = {
64 .se_header = "Parent symbol", 61 .se_header = "Parent symbol",
65 .se_cmp = sort__parent_cmp, 62 .se_cmp = sort__parent_cmp,
66 .se_snprintf = hist_entry__parent_snprintf, 63 .se_snprintf = hist_entry__parent_snprintf,
67 .se_width = &parent_symbol__col_width, 64 .se_width_idx = HISTC_PARENT,
68}; 65};
69 66
70struct sort_entry sort_cpu = { 67struct sort_entry sort_cpu = {
71 .se_header = "CPU", 68 .se_header = "CPU",
72 .se_cmp = sort__cpu_cmp, 69 .se_cmp = sort__cpu_cmp,
73 .se_snprintf = hist_entry__cpu_snprintf, 70 .se_snprintf = hist_entry__cpu_snprintf,
74 .se_width = &cpus__col_width, 71 .se_width_idx = HISTC_CPU,
75}; 72};
76 73
77struct sort_dimension { 74struct sort_dimension {
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 560c855417e4..46e531d09e8b 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -36,12 +36,14 @@ extern struct sort_entry sort_comm;
36extern struct sort_entry sort_dso; 36extern struct sort_entry sort_dso;
37extern struct sort_entry sort_sym; 37extern struct sort_entry sort_sym;
38extern struct sort_entry sort_parent; 38extern struct sort_entry sort_parent;
39extern unsigned int dsos__col_width;
40extern unsigned int comms__col_width;
41extern unsigned int threads__col_width;
42extern unsigned int cpus__col_width;
43extern enum sort_type sort__first_dimension; 39extern enum sort_type sort__first_dimension;
44 40
41/**
42 * struct hist_entry - histogram entry
43 *
44 * @row_offset - offset from the first callchain expanded to appear on screen
45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding
46 */
45struct hist_entry { 47struct hist_entry {
46 struct rb_node rb_node; 48 struct rb_node rb_node;
47 u64 period; 49 u64 period;
@@ -54,6 +56,12 @@ struct hist_entry {
54 u64 ip; 56 u64 ip;
55 s32 cpu; 57 s32 cpu;
56 u32 nr_events; 58 u32 nr_events;
59
60 /* XXX These two should move to some tree widget lib */
61 u16 row_offset;
62 u16 nr_rows;
63
64 bool init_have_children;
57 char level; 65 char level;
58 u8 filtered; 66 u8 filtered;
59 struct symbol *parent; 67 struct symbol *parent;
@@ -87,7 +95,7 @@ struct sort_entry {
87 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *); 95 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
88 int (*se_snprintf)(struct hist_entry *self, char *bf, size_t size, 96 int (*se_snprintf)(struct hist_entry *self, char *bf, size_t size,
89 unsigned int width); 97 unsigned int width);
90 unsigned int *se_width; 98 u8 se_width_idx;
91 bool elide; 99 bool elide;
92}; 100};
93 101
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 971d0a05d6b4..94cdf68440cd 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -12,6 +12,7 @@
12#include <fcntl.h> 12#include <fcntl.h>
13#include <unistd.h> 13#include <unistd.h>
14#include "build-id.h" 14#include "build-id.h"
15#include "debug.h"
15#include "symbol.h" 16#include "symbol.h"
16#include "strlist.h" 17#include "strlist.h"
17 18
@@ -25,6 +26,8 @@
25#define NT_GNU_BUILD_ID 3 26#define NT_GNU_BUILD_ID 3
26#endif 27#endif
27 28
29static bool dso__build_id_equal(const struct dso *self, u8 *build_id);
30static int elf_read_build_id(Elf *elf, void *bf, size_t size);
28static void dsos__add(struct list_head *head, struct dso *dso); 31static void dsos__add(struct list_head *head, struct dso *dso);
29static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 32static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
30static int dso__load_kernel_sym(struct dso *self, struct map *map, 33static int dso__load_kernel_sym(struct dso *self, struct map *map,
@@ -40,6 +43,14 @@ struct symbol_conf symbol_conf = {
40 .try_vmlinux_path = true, 43 .try_vmlinux_path = true,
41}; 44};
42 45
46int dso__name_len(const struct dso *self)
47{
48 if (verbose)
49 return self->long_name_len;
50
51 return self->short_name_len;
52}
53
43bool dso__loaded(const struct dso *self, enum map_type type) 54bool dso__loaded(const struct dso *self, enum map_type type)
44{ 55{
45 return self->loaded & (1 << type); 56 return self->loaded & (1 << type);
@@ -215,7 +226,9 @@ void dso__delete(struct dso *self)
215 int i; 226 int i;
216 for (i = 0; i < MAP__NR_TYPES; ++i) 227 for (i = 0; i < MAP__NR_TYPES; ++i)
217 symbols__delete(&self->symbols[i]); 228 symbols__delete(&self->symbols[i]);
218 if (self->long_name != self->name) 229 if (self->sname_alloc)
230 free((char *)self->short_name);
231 if (self->lname_alloc)
219 free(self->long_name); 232 free(self->long_name);
220 free(self); 233 free(self);
221} 234}
@@ -953,7 +966,8 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
953} 966}
954 967
955static int dso__load_sym(struct dso *self, struct map *map, const char *name, 968static int dso__load_sym(struct dso *self, struct map *map, const char *name,
956 int fd, symbol_filter_t filter, int kmodule) 969 int fd, symbol_filter_t filter, int kmodule,
970 int want_symtab)
957{ 971{
958 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; 972 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
959 struct map *curr_map = map; 973 struct map *curr_map = map;
@@ -973,17 +987,32 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
973 987
974 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 988 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
975 if (elf == NULL) { 989 if (elf == NULL) {
976 pr_err("%s: cannot read %s ELF file.\n", __func__, name); 990 pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
977 goto out_close; 991 goto out_close;
978 } 992 }
979 993
980 if (gelf_getehdr(elf, &ehdr) == NULL) { 994 if (gelf_getehdr(elf, &ehdr) == NULL) {
981 pr_err("%s: cannot get elf header.\n", __func__); 995 pr_debug("%s: cannot get elf header.\n", __func__);
982 goto out_elf_end; 996 goto out_elf_end;
983 } 997 }
984 998
999 /* Always reject images with a mismatched build-id: */
1000 if (self->has_build_id) {
1001 u8 build_id[BUILD_ID_SIZE];
1002
1003 if (elf_read_build_id(elf, build_id,
1004 BUILD_ID_SIZE) != BUILD_ID_SIZE)
1005 goto out_elf_end;
1006
1007 if (!dso__build_id_equal(self, build_id))
1008 goto out_elf_end;
1009 }
1010
985 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 1011 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
986 if (sec == NULL) { 1012 if (sec == NULL) {
1013 if (want_symtab)
1014 goto out_elf_end;
1015
987 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 1016 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
988 if (sec == NULL) 1017 if (sec == NULL)
989 goto out_elf_end; 1018 goto out_elf_end;
@@ -1182,37 +1211,26 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
1182 */ 1211 */
1183#define NOTE_ALIGN(n) (((n) + 3) & -4U) 1212#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1184 1213
1185int filename__read_build_id(const char *filename, void *bf, size_t size) 1214static int elf_read_build_id(Elf *elf, void *bf, size_t size)
1186{ 1215{
1187 int fd, err = -1; 1216 int err = -1;
1188 GElf_Ehdr ehdr; 1217 GElf_Ehdr ehdr;
1189 GElf_Shdr shdr; 1218 GElf_Shdr shdr;
1190 Elf_Data *data; 1219 Elf_Data *data;
1191 Elf_Scn *sec; 1220 Elf_Scn *sec;
1192 Elf_Kind ek; 1221 Elf_Kind ek;
1193 void *ptr; 1222 void *ptr;
1194 Elf *elf;
1195 1223
1196 if (size < BUILD_ID_SIZE) 1224 if (size < BUILD_ID_SIZE)
1197 goto out; 1225 goto out;
1198 1226
1199 fd = open(filename, O_RDONLY);
1200 if (fd < 0)
1201 goto out;
1202
1203 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1204 if (elf == NULL) {
1205 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1206 goto out_close;
1207 }
1208
1209 ek = elf_kind(elf); 1227 ek = elf_kind(elf);
1210 if (ek != ELF_K_ELF) 1228 if (ek != ELF_K_ELF)
1211 goto out_elf_end; 1229 goto out;
1212 1230
1213 if (gelf_getehdr(elf, &ehdr) == NULL) { 1231 if (gelf_getehdr(elf, &ehdr) == NULL) {
1214 pr_err("%s: cannot get elf header.\n", __func__); 1232 pr_err("%s: cannot get elf header.\n", __func__);
1215 goto out_elf_end; 1233 goto out;
1216 } 1234 }
1217 1235
1218 sec = elf_section_by_name(elf, &ehdr, &shdr, 1236 sec = elf_section_by_name(elf, &ehdr, &shdr,
@@ -1221,12 +1239,12 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)
1221 sec = elf_section_by_name(elf, &ehdr, &shdr, 1239 sec = elf_section_by_name(elf, &ehdr, &shdr,
1222 ".notes", NULL); 1240 ".notes", NULL);
1223 if (sec == NULL) 1241 if (sec == NULL)
1224 goto out_elf_end; 1242 goto out;
1225 } 1243 }
1226 1244
1227 data = elf_getdata(sec, NULL); 1245 data = elf_getdata(sec, NULL);
1228 if (data == NULL) 1246 if (data == NULL)
1229 goto out_elf_end; 1247 goto out;
1230 1248
1231 ptr = data->d_buf; 1249 ptr = data->d_buf;
1232 while (ptr < (data->d_buf + data->d_size)) { 1250 while (ptr < (data->d_buf + data->d_size)) {
@@ -1248,7 +1266,31 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)
1248 } 1266 }
1249 ptr += descsz; 1267 ptr += descsz;
1250 } 1268 }
1251out_elf_end: 1269
1270out:
1271 return err;
1272}
1273
1274int filename__read_build_id(const char *filename, void *bf, size_t size)
1275{
1276 int fd, err = -1;
1277 Elf *elf;
1278
1279 if (size < BUILD_ID_SIZE)
1280 goto out;
1281
1282 fd = open(filename, O_RDONLY);
1283 if (fd < 0)
1284 goto out;
1285
1286 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1287 if (elf == NULL) {
1288 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1289 goto out_close;
1290 }
1291
1292 err = elf_read_build_id(elf, bf, size);
1293
1252 elf_end(elf); 1294 elf_end(elf);
1253out_close: 1295out_close:
1254 close(fd); 1296 close(fd);
@@ -1324,11 +1366,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1324{ 1366{
1325 int size = PATH_MAX; 1367 int size = PATH_MAX;
1326 char *name; 1368 char *name;
1327 u8 build_id[BUILD_ID_SIZE];
1328 int ret = -1; 1369 int ret = -1;
1329 int fd; 1370 int fd;
1330 struct machine *machine; 1371 struct machine *machine;
1331 const char *root_dir; 1372 const char *root_dir;
1373 int want_symtab;
1332 1374
1333 dso__set_loaded(self, map->type); 1375 dso__set_loaded(self, map->type);
1334 1376
@@ -1355,13 +1397,18 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1355 return ret; 1397 return ret;
1356 } 1398 }
1357 1399
1358 self->origin = DSO__ORIG_BUILD_ID_CACHE; 1400 /* Iterate over candidate debug images.
1359 if (dso__build_id_filename(self, name, size) != NULL) 1401 * On the first pass, only load images if they have a full symtab.
1360 goto open_file; 1402 * Failing that, do a second pass where we accept .dynsym also
1361more: 1403 */
1362 do { 1404 for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
1363 self->origin++; 1405 self->origin != DSO__ORIG_NOT_FOUND;
1406 self->origin++) {
1364 switch (self->origin) { 1407 switch (self->origin) {
1408 case DSO__ORIG_BUILD_ID_CACHE:
1409 if (dso__build_id_filename(self, name, size) == NULL)
1410 continue;
1411 break;
1365 case DSO__ORIG_FEDORA: 1412 case DSO__ORIG_FEDORA:
1366 snprintf(name, size, "/usr/lib/debug%s.debug", 1413 snprintf(name, size, "/usr/lib/debug%s.debug",
1367 self->long_name); 1414 self->long_name);
@@ -1370,21 +1417,20 @@ more:
1370 snprintf(name, size, "/usr/lib/debug%s", 1417 snprintf(name, size, "/usr/lib/debug%s",
1371 self->long_name); 1418 self->long_name);
1372 break; 1419 break;
1373 case DSO__ORIG_BUILDID: 1420 case DSO__ORIG_BUILDID: {
1374 if (filename__read_build_id(self->long_name, build_id, 1421 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1375 sizeof(build_id))) { 1422
1376 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1423 if (!self->has_build_id)
1377 build_id__sprintf(build_id, sizeof(build_id), 1424 continue;
1378 build_id_hex); 1425
1379 snprintf(name, size, 1426 build_id__sprintf(self->build_id,
1380 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1427 sizeof(self->build_id),
1381 build_id_hex, build_id_hex + 2); 1428 build_id_hex);
1382 if (self->has_build_id) 1429 snprintf(name, size,
1383 goto compare_build_id; 1430 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1384 break; 1431 build_id_hex, build_id_hex + 2);
1385 } 1432 }
1386 self->origin++; 1433 break;
1387 /* Fall thru */
1388 case DSO__ORIG_DSO: 1434 case DSO__ORIG_DSO:
1389 snprintf(name, size, "%s", self->long_name); 1435 snprintf(name, size, "%s", self->long_name);
1390 break; 1436 break;
@@ -1397,36 +1443,41 @@ more:
1397 break; 1443 break;
1398 1444
1399 default: 1445 default:
1400 goto out; 1446 /*
1447 * If we wanted a full symtab but no image had one,
1448 * relax our requirements and repeat the search.
1449 */
1450 if (want_symtab) {
1451 want_symtab = 0;
1452 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1453 } else
1454 continue;
1401 } 1455 }
1402 1456
1403 if (self->has_build_id) { 1457 /* Name is now the name of the next image to try */
1404 if (filename__read_build_id(name, build_id,
1405 sizeof(build_id)) < 0)
1406 goto more;
1407compare_build_id:
1408 if (!dso__build_id_equal(self, build_id))
1409 goto more;
1410 }
1411open_file:
1412 fd = open(name, O_RDONLY); 1458 fd = open(name, O_RDONLY);
1413 } while (fd < 0); 1459 if (fd < 0)
1460 continue;
1414 1461
1415 ret = dso__load_sym(self, map, name, fd, filter, 0); 1462 ret = dso__load_sym(self, map, name, fd, filter, 0,
1416 close(fd); 1463 want_symtab);
1464 close(fd);
1417 1465
1418 /* 1466 /*
1419 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 1467 * Some people seem to have debuginfo files _WITHOUT_ debug
1420 */ 1468 * info!?!?
1421 if (!ret) 1469 */
1422 goto more; 1470 if (!ret)
1471 continue;
1423 1472
1424 if (ret > 0) { 1473 if (ret > 0) {
1425 int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1474 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1426 if (nr_plt > 0) 1475 if (nr_plt > 0)
1427 ret += nr_plt; 1476 ret += nr_plt;
1477 break;
1478 }
1428 } 1479 }
1429out: 1480
1430 free(name); 1481 free(name);
1431 if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 1482 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1432 return 0; 1483 return 0;
@@ -1521,6 +1572,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self,
1521 if (long_name == NULL) 1572 if (long_name == NULL)
1522 goto failure; 1573 goto failure;
1523 dso__set_long_name(map->dso, long_name); 1574 dso__set_long_name(map->dso, long_name);
1575 map->dso->lname_alloc = 1;
1524 dso__kernel_module_get_build_id(map->dso, ""); 1576 dso__kernel_module_get_build_id(map->dso, "");
1525 } 1577 }
1526 } 1578 }
@@ -1684,36 +1736,12 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1684{ 1736{
1685 int err = -1, fd; 1737 int err = -1, fd;
1686 1738
1687 if (self->has_build_id) {
1688 u8 build_id[BUILD_ID_SIZE];
1689
1690 if (filename__read_build_id(vmlinux, build_id,
1691 sizeof(build_id)) < 0) {
1692 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1693 return -1;
1694 }
1695 if (!dso__build_id_equal(self, build_id)) {
1696 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1697 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1698
1699 build_id__sprintf(self->build_id,
1700 sizeof(self->build_id),
1701 expected_build_id);
1702 build_id__sprintf(build_id, sizeof(build_id),
1703 vmlinux_build_id);
1704 pr_debug("build_id in %s is %s while expected is %s, "
1705 "ignoring it\n", vmlinux, vmlinux_build_id,
1706 expected_build_id);
1707 return -1;
1708 }
1709 }
1710
1711 fd = open(vmlinux, O_RDONLY); 1739 fd = open(vmlinux, O_RDONLY);
1712 if (fd < 0) 1740 if (fd < 0)
1713 return -1; 1741 return -1;
1714 1742
1715 dso__set_loaded(self, map->type); 1743 dso__set_loaded(self, map->type);
1716 err = dso__load_sym(self, map, vmlinux, fd, filter, 0); 1744 err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0);
1717 close(fd); 1745 close(fd);
1718 1746
1719 if (err > 0) 1747 if (err > 0)
@@ -2217,6 +2245,15 @@ out_free_comm_list:
2217 return -1; 2245 return -1;
2218} 2246}
2219 2247
2248void symbol__exit(void)
2249{
2250 strlist__delete(symbol_conf.sym_list);
2251 strlist__delete(symbol_conf.dso_list);
2252 strlist__delete(symbol_conf.comm_list);
2253 vmlinux_path__exit();
2254 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
2255}
2256
2220int machines__create_kernel_maps(struct rb_root *self, pid_t pid) 2257int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
2221{ 2258{
2222 struct machine *machine = machines__findnew(self, pid); 2259 struct machine *machine = machines__findnew(self, pid);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 80e569bbdecc..33d53ce28958 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -68,7 +68,6 @@ struct symbol_conf {
68 show_nr_samples, 68 show_nr_samples,
69 use_callchain, 69 use_callchain,
70 exclude_other, 70 exclude_other,
71 full_paths,
72 show_cpu_utilization; 71 show_cpu_utilization;
73 const char *vmlinux_name, 72 const char *vmlinux_name,
74 *source_prefix, 73 *source_prefix,
@@ -102,6 +101,8 @@ struct ref_reloc_sym {
102struct map_symbol { 101struct map_symbol {
103 struct map *map; 102 struct map *map;
104 struct symbol *sym; 103 struct symbol *sym;
104 bool unfolded;
105 bool has_children;
105}; 106};
106 107
107struct addr_location { 108struct addr_location {
@@ -125,12 +126,14 @@ struct dso {
125 struct list_head node; 126 struct list_head node;
126 struct rb_root symbols[MAP__NR_TYPES]; 127 struct rb_root symbols[MAP__NR_TYPES];
127 struct rb_root symbol_names[MAP__NR_TYPES]; 128 struct rb_root symbol_names[MAP__NR_TYPES];
129 enum dso_kernel_type kernel;
128 u8 adjust_symbols:1; 130 u8 adjust_symbols:1;
129 u8 slen_calculated:1; 131 u8 slen_calculated:1;
130 u8 has_build_id:1; 132 u8 has_build_id:1;
131 enum dso_kernel_type kernel;
132 u8 hit:1; 133 u8 hit:1;
133 u8 annotate_warned:1; 134 u8 annotate_warned:1;
135 u8 sname_alloc:1;
136 u8 lname_alloc:1;
134 unsigned char origin; 137 unsigned char origin;
135 u8 sorted_by_name; 138 u8 sorted_by_name;
136 u8 loaded; 139 u8 loaded;
@@ -146,6 +149,8 @@ struct dso *dso__new(const char *name);
146struct dso *dso__new_kernel(const char *name); 149struct dso *dso__new_kernel(const char *name);
147void dso__delete(struct dso *self); 150void dso__delete(struct dso *self);
148 151
152int dso__name_len(const struct dso *self);
153
149bool dso__loaded(const struct dso *self, enum map_type type); 154bool dso__loaded(const struct dso *self, enum map_type type);
150bool dso__sorted_by_name(const struct dso *self, enum map_type type); 155bool dso__sorted_by_name(const struct dso *self, enum map_type type);
151 156
@@ -214,6 +219,7 @@ int machines__create_kernel_maps(struct rb_root *self, pid_t pid);
214int machines__create_guest_kernel_maps(struct rb_root *self); 219int machines__create_guest_kernel_maps(struct rb_root *self);
215 220
216int symbol__init(void); 221int symbol__init(void);
222void symbol__exit(void);
217bool symbol_type__is_a(char symbol_type, enum map_type map_type); 223bool symbol_type__is_a(char symbol_type, enum map_type map_type);
218 224
219size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp); 225size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 9a448b47400c..8c72d888e449 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -62,6 +62,13 @@ static struct thread *thread__new(pid_t pid)
62 return self; 62 return self;
63} 63}
64 64
65void thread__delete(struct thread *self)
66{
67 map_groups__exit(&self->mg);
68 free(self->comm);
69 free(self);
70}
71
65int thread__set_comm(struct thread *self, const char *comm) 72int thread__set_comm(struct thread *self, const char *comm)
66{ 73{
67 int err; 74 int err;
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index ee6bbcf277ca..688500ff826f 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -20,6 +20,8 @@ struct thread {
20 20
21struct perf_session; 21struct perf_session;
22 22
23void thread__delete(struct thread *self);
24
23int find_all_tid(int pid, pid_t ** all_tid); 25int find_all_tid(int pid, pid_t ** all_tid);
24int thread__set_comm(struct thread *self, const char *comm); 26int thread__set_comm(struct thread *self, const char *comm);
25int thread__comm_len(struct thread *self); 27int thread__comm_len(struct thread *self);