Commit 928585536ff5a8f320e60efc60e2b7ef2a5f548d

Authored by Ingo Molnar

Merge branch 'perf/test' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/l…

…inux-2.6 into perf/core

Showing 24 changed files Side-by-side Diff

... ... @@ -396,6 +396,7 @@
396 396 LIB_H += util/debug.h
397 397 LIB_H += util/debugfs.h
398 398 LIB_H += util/event.h
  399 +LIB_H += util/evsel.h
399 400 LIB_H += util/exec_cmd.h
400 401 LIB_H += util/types.h
401 402 LIB_H += util/levenshtein.h
... ... @@ -404,6 +405,7 @@
404 405 LIB_H += util/parse-events.h
405 406 LIB_H += util/quote.h
406 407 LIB_H += util/util.h
  408 +LIB_H += util/xyarray.h
407 409 LIB_H += util/header.h
408 410 LIB_H += util/help.h
409 411 LIB_H += util/session.h
... ... @@ -433,6 +435,7 @@
433 435 LIB_OBJS += $(OUTPUT)util/debugfs.o
434 436 LIB_OBJS += $(OUTPUT)util/environment.o
435 437 LIB_OBJS += $(OUTPUT)util/event.o
  438 +LIB_OBJS += $(OUTPUT)util/evsel.o
436 439 LIB_OBJS += $(OUTPUT)util/exec_cmd.o
437 440 LIB_OBJS += $(OUTPUT)util/help.o
438 441 LIB_OBJS += $(OUTPUT)util/levenshtein.o
... ... @@ -470,6 +473,7 @@
470 473 LIB_OBJS += $(OUTPUT)util/hist.o
471 474 LIB_OBJS += $(OUTPUT)util/probe-event.o
472 475 LIB_OBJS += $(OUTPUT)util/util.o
  476 +LIB_OBJS += $(OUTPUT)util/xyarray.o
473 477 LIB_OBJS += $(OUTPUT)util/cpumap.o
474 478  
475 479 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
tools/perf/builtin-record.c
... ... @@ -18,6 +18,7 @@
18 18  
19 19 #include "util/header.h"
20 20 #include "util/event.h"
  21 +#include "util/evsel.h"
21 22 #include "util/debug.h"
22 23 #include "util/session.h"
23 24 #include "util/symbol.h"
24 25  
25 26  
... ... @@ -27,18 +28,18 @@
27 28 #include <sched.h>
28 29 #include <sys/mman.h>
29 30  
  31 +#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
  32 +
30 33 enum write_mode_t {
31 34 WRITE_FORCE,
32 35 WRITE_APPEND
33 36 };
34 37  
35   -static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
36   -
37 38 static u64 user_interval = ULLONG_MAX;
38 39 static u64 default_interval = 0;
39 40 static u64 sample_type;
40 41  
41   -static int nr_cpus = 0;
  42 +static struct cpu_map *cpus;
42 43 static unsigned int page_size;
43 44 static unsigned int mmap_pages = 128;
44 45 static unsigned int user_freq = UINT_MAX;
... ... @@ -53,8 +54,7 @@
53 54 static bool system_wide = false;
54 55 static pid_t target_pid = -1;
55 56 static pid_t target_tid = -1;
56   -static pid_t *all_tids = NULL;
57   -static int thread_num = 0;
  57 +static struct thread_map *threads;
58 58 static pid_t child_pid = -1;
59 59 static bool no_inherit = false;
60 60 static enum write_mode_t write_mode = WRITE_FORCE;
... ... @@ -81,7 +81,6 @@
81 81 static const char *cpu_list;
82 82  
83 83 struct mmap_data {
84   - int counter;
85 84 void *base;
86 85 unsigned int mask;
87 86 unsigned int prev;
88 87  
89 88  
... ... @@ -229,12 +228,12 @@
229 228 return h_attr;
230 229 }
231 230  
232   -static void create_counter(int counter, int cpu)
  231 +static void create_counter(struct perf_evsel *evsel, int cpu)
233 232 {
234   - char *filter = filters[counter];
235   - struct perf_event_attr *attr = attrs + counter;
  233 + char *filter = evsel->filter;
  234 + struct perf_event_attr *attr = &evsel->attr;
236 235 struct perf_header_attr *h_attr;
237   - int track = !counter; /* only the first counter needs these */
  236 + int track = !evsel->idx; /* only the first counter needs these */
238 237 int thread_index;
239 238 int ret;
240 239 struct {
241 240  
242 241  
... ... @@ -318,12 +317,11 @@
318 317 retry_sample_id:
319 318 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
320 319  
321   - for (thread_index = 0; thread_index < thread_num; thread_index++) {
  320 + for (thread_index = 0; thread_index < threads->nr; thread_index++) {
322 321 try_again:
323   - fd[nr_cpu][counter][thread_index] = sys_perf_event_open(attr,
324   - all_tids[thread_index], cpu, group_fd, 0);
  322 + FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0);
325 323  
326   - if (fd[nr_cpu][counter][thread_index] < 0) {
  324 + if (FD(evsel, nr_cpu, thread_index) < 0) {
327 325 int err = errno;
328 326  
329 327 if (err == EPERM || err == EACCES)
... ... @@ -360,7 +358,7 @@
360 358 }
361 359 printf("\n");
362 360 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
363   - fd[nr_cpu][counter][thread_index], strerror(err));
  361 + FD(evsel, nr_cpu, thread_index), strerror(err));
364 362  
365 363 #if defined(__i386__) || defined(__x86_64__)
366 364 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
... ... @@ -374,7 +372,7 @@
374 372 exit(-1);
375 373 }
376 374  
377   - h_attr = get_header_attr(attr, counter);
  375 + h_attr = get_header_attr(attr, evsel->idx);
378 376 if (h_attr == NULL)
379 377 die("nomem\n");
380 378  
... ... @@ -385,7 +383,7 @@
385 383 }
386 384 }
387 385  
388   - if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) {
  386 + if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) {
389 387 perror("Unable to read perf file descriptor");
390 388 exit(-1);
391 389 }
392 390  
393 391  
394 392  
395 393  
396 394  
397 395  
... ... @@ -395,43 +393,44 @@
395 393 exit(-1);
396 394 }
397 395  
398   - assert(fd[nr_cpu][counter][thread_index] >= 0);
399   - fcntl(fd[nr_cpu][counter][thread_index], F_SETFL, O_NONBLOCK);
  396 + assert(FD(evsel, nr_cpu, thread_index) >= 0);
  397 + fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK);
400 398  
401 399 /*
402 400 * First counter acts as the group leader:
403 401 */
404 402 if (group && group_fd == -1)
405   - group_fd = fd[nr_cpu][counter][thread_index];
  403 + group_fd = FD(evsel, nr_cpu, thread_index);
406 404  
407   - if (counter || thread_index) {
408   - ret = ioctl(fd[nr_cpu][counter][thread_index],
409   - PERF_EVENT_IOC_SET_OUTPUT,
410   - fd[nr_cpu][0][0]);
  405 + if (evsel->idx || thread_index) {
  406 + struct perf_evsel *first;
  407 + first = list_entry(evsel_list.next, struct perf_evsel, node);
  408 + ret = ioctl(FD(evsel, nr_cpu, thread_index),
  409 + PERF_EVENT_IOC_SET_OUTPUT,
  410 + FD(first, nr_cpu, 0));
411 411 if (ret) {
412 412 error("failed to set output: %d (%s)\n", errno,
413 413 strerror(errno));
414 414 exit(-1);
415 415 }
416 416 } else {
417   - mmap_array[nr_cpu].counter = counter;
418 417 mmap_array[nr_cpu].prev = 0;
419 418 mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
420 419 mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
421   - PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter][thread_index], 0);
  420 + PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0);
422 421 if (mmap_array[nr_cpu].base == MAP_FAILED) {
423 422 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
424 423 exit(-1);
425 424 }
426 425  
427   - event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index];
  426 + event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index);
428 427 event_array[nr_poll].events = POLLIN;
429 428 nr_poll++;
430 429 }
431 430  
432 431 if (filter != NULL) {
433   - ret = ioctl(fd[nr_cpu][counter][thread_index],
434   - PERF_EVENT_IOC_SET_FILTER, filter);
  432 + ret = ioctl(FD(evsel, nr_cpu, thread_index),
  433 + PERF_EVENT_IOC_SET_FILTER, filter);
435 434 if (ret) {
436 435 error("failed to set filter with %d (%s)\n", errno,
437 436 strerror(errno));
438 437  
439 438  
... ... @@ -446,12 +445,13 @@
446 445  
447 446 static void open_counters(int cpu)
448 447 {
449   - int counter;
  448 + struct perf_evsel *pos;
450 449  
451 450 group_fd = -1;
452   - for (counter = 0; counter < nr_counters; counter++)
453   - create_counter(counter, cpu);
454 451  
  452 + list_for_each_entry(pos, &evsel_list, node)
  453 + create_counter(pos, cpu);
  454 +
455 455 nr_cpu++;
456 456 }
457 457  
... ... @@ -537,7 +537,7 @@
537 537  
538 538 static int __cmd_record(int argc, const char **argv)
539 539 {
540   - int i, counter;
  540 + int i;
541 541 struct stat st;
542 542 int flags;
543 543 int err;
... ... @@ -604,7 +604,7 @@
604 604 goto out_delete_session;
605 605 }
606 606  
607   - if (have_tracepoints(attrs, nr_counters))
  607 + if (have_tracepoints(&evsel_list))
608 608 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
609 609  
610 610 /*
... ... @@ -652,7 +652,7 @@
652 652 }
653 653  
654 654 if (!system_wide && target_tid == -1 && target_pid == -1)
655   - all_tids[0] = child_pid;
  655 + threads->map[0] = child_pid;
656 656  
657 657 close(child_ready_pipe[1]);
658 658 close(go_pipe[0]);
659 659  
... ... @@ -666,17 +666,11 @@
666 666 close(child_ready_pipe[0]);
667 667 }
668 668  
669   - nr_cpus = read_cpu_map(cpu_list);
670   - if (nr_cpus < 1) {
671   - perror("failed to collect number of CPUs");
672   - return -1;
673   - }
674   -
675 669 if (!system_wide && no_inherit && !cpu_list) {
676 670 open_counters(-1);
677 671 } else {
678   - for (i = 0; i < nr_cpus; i++)
679   - open_counters(cpumap[i]);
  672 + for (i = 0; i < cpus->nr; i++)
  673 + open_counters(cpus->map[i]);
680 674 }
681 675  
682 676 perf_session__set_sample_type(session, sample_type);
... ... @@ -711,7 +705,7 @@
711 705 return err;
712 706 }
713 707  
714   - if (have_tracepoints(attrs, nr_counters)) {
  708 + if (have_tracepoints(&evsel_list)) {
715 709 /*
716 710 * FIXME err <= 0 here actually means that
717 711 * there were no tracepoints so its not really
... ... @@ -720,8 +714,7 @@
720 714 * return this more properly and also
721 715 * propagate errors that now are calling die()
722 716 */
723   - err = event__synthesize_tracing_data(output, attrs,
724   - nr_counters,
  717 + err = event__synthesize_tracing_data(output, &evsel_list,
725 718 process_synthesized_event,
726 719 session);
727 720 if (err <= 0) {
728 721  
729 722  
... ... @@ -795,13 +788,13 @@
795 788  
796 789 if (done) {
797 790 for (i = 0; i < nr_cpu; i++) {
798   - for (counter = 0;
799   - counter < nr_counters;
800   - counter++) {
  791 + struct perf_evsel *pos;
  792 +
  793 + list_for_each_entry(pos, &evsel_list, node) {
801 794 for (thread = 0;
802   - thread < thread_num;
  795 + thread < threads->nr;
803 796 thread++)
804   - ioctl(fd[i][counter][thread],
  797 + ioctl(FD(pos, i, thread),
805 798 PERF_EVENT_IOC_DISABLE);
806 799 }
807 800 }
... ... @@ -887,7 +880,8 @@
887 880  
888 881 int cmd_record(int argc, const char **argv, const char *prefix __used)
889 882 {
890   - int i, j, err = -ENOMEM;
  883 + int err = -ENOMEM;
  884 + struct perf_evsel *pos;
891 885  
892 886 argc = parse_options(argc, argv, record_options, record_usage,
893 887 PARSE_OPT_STOP_AT_NON_OPTION);
894 888  
895 889  
896 890  
897 891  
898 892  
... ... @@ -910,38 +904,32 @@
910 904 if (no_buildid_cache || no_buildid)
911 905 disable_buildid_cache();
912 906  
913   - if (!nr_counters) {
914   - nr_counters = 1;
915   - attrs[0].type = PERF_TYPE_HARDWARE;
916   - attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
  907 + if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) {
  908 + pr_err("Not enough memory for event selector list\n");
  909 + goto out_symbol_exit;
917 910 }
918 911  
919   - if (target_pid != -1) {
  912 + if (target_pid != -1)
920 913 target_tid = target_pid;
921   - thread_num = find_all_tid(target_pid, &all_tids);
922   - if (thread_num <= 0) {
923   - fprintf(stderr, "Can't find all threads of pid %d\n",
924   - target_pid);
925   - usage_with_options(record_usage, record_options);
926   - }
927   - } else {
928   - all_tids=malloc(sizeof(pid_t));
929   - if (!all_tids)
930   - goto out_symbol_exit;
931 914  
932   - all_tids[0] = target_tid;
933   - thread_num = 1;
  915 + threads = thread_map__new(target_pid, target_tid);
  916 + if (threads == NULL) {
  917 + pr_err("Problems finding threads of monitor\n");
  918 + usage_with_options(record_usage, record_options);
934 919 }
935 920  
936   - for (i = 0; i < MAX_NR_CPUS; i++) {
937   - for (j = 0; j < MAX_COUNTERS; j++) {
938   - fd[i][j] = malloc(sizeof(int)*thread_num);
939   - if (!fd[i][j])
940   - goto out_free_fd;
941   - }
  921 + cpus = cpu_map__new(cpu_list);
  922 + if (cpus == NULL) {
  923 + perror("failed to parse CPUs map");
  924 + return -1;
942 925 }
943   - event_array = malloc(
944   - sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
  926 +
  927 + list_for_each_entry(pos, &evsel_list, node) {
  928 + if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
  929 + goto out_free_fd;
  930 + }
  931 + event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS *
  932 + MAX_COUNTERS * threads->nr));
945 933 if (!event_array)
946 934 goto out_free_fd;
947 935  
... ... @@ -968,12 +956,8 @@
968 956 out_free_event_array:
969 957 free(event_array);
970 958 out_free_fd:
971   - for (i = 0; i < MAX_NR_CPUS; i++) {
972   - for (j = 0; j < MAX_COUNTERS; j++)
973   - free(fd[i][j]);
974   - }
975   - free(all_tids);
976   - all_tids = NULL;
  959 + thread_map__delete(threads);
  960 + threads = NULL;
977 961 out_symbol_exit:
978 962 symbol__exit();
979 963 return err;
tools/perf/builtin-stat.c
... ... @@ -43,6 +43,7 @@
43 43 #include "util/parse-options.h"
44 44 #include "util/parse-events.h"
45 45 #include "util/event.h"
  46 +#include "util/evsel.h"
46 47 #include "util/debug.h"
47 48 #include "util/header.h"
48 49 #include "util/cpumap.h"
... ... @@ -71,7 +72,7 @@
71 72 };
72 73  
73 74 static bool system_wide = false;
74   -static int nr_cpus = 0;
  75 +static struct cpu_map *cpus;
75 76 static int run_idx = 0;
76 77  
77 78 static int run_count = 1;
... ... @@ -80,8 +81,7 @@
80 81 static bool no_aggr = false;
81 82 static pid_t target_pid = -1;
82 83 static pid_t target_tid = -1;
83   -static pid_t *all_tids = NULL;
84   -static int thread_num = 0;
  84 +static struct thread_map *threads;
85 85 static pid_t child_pid = -1;
86 86 static bool null_run = false;
87 87 static bool big_num = true;
... ... @@ -90,17 +90,6 @@
90 90 static const char *csv_sep = NULL;
91 91 static bool csv_output = false;
92 92  
93   -
94   -static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
95   -
96   -static int event_scaled[MAX_COUNTERS];
97   -
98   -static struct {
99   - u64 val;
100   - u64 ena;
101   - u64 run;
102   -} cpu_counts[MAX_NR_CPUS][MAX_COUNTERS];
103   -
104 93 static volatile int done = 0;
105 94  
106 95 struct stats
... ... @@ -108,6 +97,22 @@
108 97 double n, mean, M2;
109 98 };
110 99  
  100 +struct perf_stat {
  101 + struct stats res_stats[3];
  102 +};
  103 +
  104 +static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
  105 +{
  106 + evsel->priv = zalloc(sizeof(struct perf_stat));
  107 + return evsel->priv == NULL ? -ENOMEM : 0;
  108 +}
  109 +
  110 +static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
  111 +{
  112 + free(evsel->priv);
  113 + evsel->priv = NULL;
  114 +}
  115 +
111 116 static void update_stats(struct stats *stats, u64 val)
112 117 {
113 118 double delta;
114 119  
115 120  
116 121  
117 122  
118 123  
119 124  
120 125  
... ... @@ -147,75 +152,38 @@
147 152 return sqrt(variance_mean);
148 153 }
149 154  
150   -struct stats event_res_stats[MAX_COUNTERS][3];
151 155 struct stats runtime_nsecs_stats[MAX_NR_CPUS];
152 156 struct stats runtime_cycles_stats[MAX_NR_CPUS];
153 157 struct stats runtime_branches_stats[MAX_NR_CPUS];
154 158 struct stats walltime_nsecs_stats;
155 159  
156   -#define MATCH_EVENT(t, c, counter) \
157   - (attrs[counter].type == PERF_TYPE_##t && \
158   - attrs[counter].config == PERF_COUNT_##c)
159   -
160   -#define ERR_PERF_OPEN \
161   -"counter %d, sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information."
162   -
163   -static int create_perf_stat_counter(int counter, bool *perm_err)
  160 +static int create_perf_stat_counter(struct perf_evsel *evsel)
164 161 {
165   - struct perf_event_attr *attr = attrs + counter;
166   - int thread;
167   - int ncreated = 0;
  162 + struct perf_event_attr *attr = &evsel->attr;
168 163  
169 164 if (scale)
170 165 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
171 166 PERF_FORMAT_TOTAL_TIME_RUNNING;
172 167  
173   - if (system_wide) {
174   - int cpu;
  168 + if (system_wide)
  169 + return perf_evsel__open_per_cpu(evsel, cpus);
175 170  
176   - for (cpu = 0; cpu < nr_cpus; cpu++) {
177   - fd[cpu][counter][0] = sys_perf_event_open(attr,
178   - -1, cpumap[cpu], -1, 0);
179   - if (fd[cpu][counter][0] < 0) {
180   - if (errno == EPERM || errno == EACCES)
181   - *perm_err = true;
182   - error(ERR_PERF_OPEN, counter,
183   - fd[cpu][counter][0], strerror(errno));
184   - } else {
185   - ++ncreated;
186   - }
187   - }
188   - } else {
189   - attr->inherit = !no_inherit;
190   - if (target_pid == -1 && target_tid == -1) {
191   - attr->disabled = 1;
192   - attr->enable_on_exec = 1;
193   - }
194   - for (thread = 0; thread < thread_num; thread++) {
195   - fd[0][counter][thread] = sys_perf_event_open(attr,
196   - all_tids[thread], -1, -1, 0);
197   - if (fd[0][counter][thread] < 0) {
198   - if (errno == EPERM || errno == EACCES)
199   - *perm_err = true;
200   - error(ERR_PERF_OPEN, counter,
201   - fd[0][counter][thread],
202   - strerror(errno));
203   - } else {
204   - ++ncreated;
205   - }
206   - }
  171 + attr->inherit = !no_inherit;
  172 + if (target_pid == -1 && target_tid == -1) {
  173 + attr->disabled = 1;
  174 + attr->enable_on_exec = 1;
207 175 }
208 176  
209   - return ncreated;
  177 + return perf_evsel__open_per_thread(evsel, threads);
210 178 }
211 179  
212 180 /*
213 181 * Does the counter have nsecs as a unit?
214 182 */
215   -static inline int nsec_counter(int counter)
  183 +static inline int nsec_counter(struct perf_evsel *evsel)
216 184 {
217   - if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) ||
218   - MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
  185 + if (perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK) ||
  186 + perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
219 187 return 1;
220 188  
221 189 return 0;
222 190  
223 191  
224 192  
225 193  
... ... @@ -225,54 +193,17 @@
225 193 * Read out the results of a single counter:
226 194 * aggregate counts across CPUs in system-wide mode
227 195 */
228   -static void read_counter_aggr(int counter)
  196 +static int read_counter_aggr(struct perf_evsel *counter)
229 197 {
230   - u64 count[3], single_count[3];
231   - int cpu;
232   - size_t res, nv;
233   - int scaled;
234   - int i, thread;
  198 + struct perf_stat *ps = counter->priv;
  199 + u64 *count = counter->counts->aggr.values;
  200 + int i;
235 201  
236   - count[0] = count[1] = count[2] = 0;
  202 + if (__perf_evsel__read(counter, cpus->nr, threads->nr, scale) < 0)
  203 + return -1;
237 204  
238   - nv = scale ? 3 : 1;
239   - for (cpu = 0; cpu < nr_cpus; cpu++) {
240   - for (thread = 0; thread < thread_num; thread++) {
241   - if (fd[cpu][counter][thread] < 0)
242   - continue;
243   -
244   - res = read(fd[cpu][counter][thread],
245   - single_count, nv * sizeof(u64));
246   - assert(res == nv * sizeof(u64));
247   -
248   - close(fd[cpu][counter][thread]);
249   - fd[cpu][counter][thread] = -1;
250   -
251   - count[0] += single_count[0];
252   - if (scale) {
253   - count[1] += single_count[1];
254   - count[2] += single_count[2];
255   - }
256   - }
257   - }
258   -
259   - scaled = 0;
260   - if (scale) {
261   - if (count[2] == 0) {
262   - event_scaled[counter] = -1;
263   - count[0] = 0;
264   - return;
265   - }
266   -
267   - if (count[2] < count[1]) {
268   - event_scaled[counter] = 1;
269   - count[0] = (unsigned long long)
270   - ((double)count[0] * count[1] / count[2] + 0.5);
271   - }
272   - }
273   -
274 205 for (i = 0; i < 3; i++)
275   - update_stats(&event_res_stats[counter][i], count[i]);
  206 + update_stats(&ps->res_stats[i], count[i]);
276 207  
277 208 if (verbose) {
278 209 fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter),
279 210  
280 211  
281 212  
282 213  
283 214  
284 215  
285 216  
286 217  
287 218  
288 219  
289 220  
290 221  
291 222  
292 223  
293 224  
294 225  
... ... @@ -282,74 +213,51 @@
282 213 /*
283 214 * Save the full runtime - to allow normalization during printout:
284 215 */
285   - if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
  216 + if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK))
286 217 update_stats(&runtime_nsecs_stats[0], count[0]);
287   - if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
  218 + if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
288 219 update_stats(&runtime_cycles_stats[0], count[0]);
289   - if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter))
  220 + if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
290 221 update_stats(&runtime_branches_stats[0], count[0]);
  222 +
  223 + return 0;
291 224 }
292 225  
293 226 /*
294 227 * Read out the results of a single counter:
295 228 * do not aggregate counts across CPUs in system-wide mode
296 229 */
297   -static void read_counter(int counter)
  230 +static int read_counter(struct perf_evsel *counter)
298 231 {
299   - u64 count[3];
  232 + u64 *count;
300 233 int cpu;
301   - size_t res, nv;
302 234  
303   - count[0] = count[1] = count[2] = 0;
  235 + for (cpu = 0; cpu < cpus->nr; cpu++) {
  236 + if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
  237 + return -1;
304 238  
305   - nv = scale ? 3 : 1;
  239 + count = counter->counts->cpu[cpu].values;
306 240  
307   - for (cpu = 0; cpu < nr_cpus; cpu++) {
308   -
309   - if (fd[cpu][counter][0] < 0)
310   - continue;
311   -
312   - res = read(fd[cpu][counter][0], count, nv * sizeof(u64));
313   -
314   - assert(res == nv * sizeof(u64));
315   -
316   - close(fd[cpu][counter][0]);
317   - fd[cpu][counter][0] = -1;
318   -
319   - if (scale) {
320   - if (count[2] == 0) {
321   - count[0] = 0;
322   - } else if (count[2] < count[1]) {
323   - count[0] = (unsigned long long)
324   - ((double)count[0] * count[1] / count[2] + 0.5);
325   - }
326   - }
327   - cpu_counts[cpu][counter].val = count[0]; /* scaled count */
328   - cpu_counts[cpu][counter].ena = count[1];
329   - cpu_counts[cpu][counter].run = count[2];
330   -
331   - if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
  241 + if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK))
332 242 update_stats(&runtime_nsecs_stats[cpu], count[0]);
333   - if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
  243 + if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
334 244 update_stats(&runtime_cycles_stats[cpu], count[0]);
335   - if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter))
  245 + if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
336 246 update_stats(&runtime_branches_stats[cpu], count[0]);
337 247 }
  248 +
  249 + return 0;
338 250 }
339 251  
340 252 static int run_perf_stat(int argc __used, const char **argv)
341 253 {
342 254 unsigned long long t0, t1;
  255 + struct perf_evsel *counter;
343 256 int status = 0;
344   - int counter, ncreated = 0;
345 257 int child_ready_pipe[2], go_pipe[2];
346   - bool perm_err = false;
347 258 const bool forks = (argc > 0);
348 259 char buf;
349 260  
350   - if (!system_wide)
351   - nr_cpus = 1;
352   -
353 261 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
354 262 perror("failed to create pipes");
355 263 exit(1);
... ... @@ -389,7 +297,7 @@
389 297 }
390 298  
391 299 if (target_tid == -1 && target_pid == -1 && !system_wide)
392   - all_tids[0] = child_pid;
  300 + threads->map[0] = child_pid;
393 301  
394 302 /*
395 303 * Wait for the child to be ready to exec.
... ... @@ -401,19 +309,23 @@
401 309 close(child_ready_pipe[0]);
402 310 }
403 311  
404   - for (counter = 0; counter < nr_counters; counter++)
405   - ncreated += create_perf_stat_counter(counter, &perm_err);
406   -
407   - if (ncreated < nr_counters) {
408   - if (perm_err)
409   - error("You may not have permission to collect %sstats.\n"
410   - "\t Consider tweaking"
411   - " /proc/sys/kernel/perf_event_paranoid or running as root.",
412   - system_wide ? "system-wide " : "");
413   - die("Not all events could be opened.\n");
414   - if (child_pid != -1)
415   - kill(child_pid, SIGTERM);
416   - return -1;
  312 + list_for_each_entry(counter, &evsel_list, node) {
  313 + if (create_perf_stat_counter(counter) < 0) {
  314 + if (errno == -EPERM || errno == -EACCES) {
  315 + error("You may not have permission to collect %sstats.\n"
  316 + "\t Consider tweaking"
  317 + " /proc/sys/kernel/perf_event_paranoid or running as root.",
  318 + system_wide ? "system-wide " : "");
  319 + } else {
  320 + error("open_counter returned with %d (%s). "
  321 + "/bin/dmesg may provide additional information.\n",
  322 + errno, strerror(errno));
  323 + }
  324 + if (child_pid != -1)
  325 + kill(child_pid, SIGTERM);
  326 + die("Not all events could be opened.\n");
  327 + return -1;
  328 + }
417 329 }
418 330  
419 331 /*
420 332  
421 333  
422 334  
423 335  
424 336  
425 337  
426 338  
427 339  
428 340  
... ... @@ -433,25 +345,33 @@
433 345 update_stats(&walltime_nsecs_stats, t1 - t0);
434 346  
435 347 if (no_aggr) {
436   - for (counter = 0; counter < nr_counters; counter++)
  348 + list_for_each_entry(counter, &evsel_list, node) {
437 349 read_counter(counter);
  350 + perf_evsel__close_fd(counter, cpus->nr, 1);
  351 + }
438 352 } else {
439   - for (counter = 0; counter < nr_counters; counter++)
  353 + list_for_each_entry(counter, &evsel_list, node) {
440 354 read_counter_aggr(counter);
  355 + perf_evsel__close_fd(counter, cpus->nr, threads->nr);
  356 + }
441 357 }
  358 +
442 359 return WEXITSTATUS(status);
443 360 }
444 361  
445   -static void print_noise(int counter, double avg)
  362 +static void print_noise(struct perf_evsel *evsel, double avg)
446 363 {
  364 + struct perf_stat *ps;
  365 +
447 366 if (run_count == 1)
448 367 return;
449 368  
  369 + ps = evsel->priv;
450 370 fprintf(stderr, " ( +- %7.3f%% )",
451   - 100 * stddev_stats(&event_res_stats[counter][0]) / avg);
  371 + 100 * stddev_stats(&ps->res_stats[0]) / avg);
452 372 }
453 373  
454   -static void nsec_printout(int cpu, int counter, double avg)
  374 +static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
455 375 {
456 376 double msecs = avg / 1e6;
457 377 char cpustr[16] = { '\0', };
458 378  
459 379  
460 380  
461 381  
... ... @@ -460,20 +380,19 @@
460 380 if (no_aggr)
461 381 sprintf(cpustr, "CPU%*d%s",
462 382 csv_output ? 0 : -4,
463   - cpumap[cpu], csv_sep);
  383 + cpus->map[cpu], csv_sep);
464 384  
465   - fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(counter));
  385 + fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel));
466 386  
467 387 if (csv_output)
468 388 return;
469 389  
470   - if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) {
  390 + if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
471 391 fprintf(stderr, " # %10.3f CPUs ",
472 392 avg / avg_stats(&walltime_nsecs_stats));
473   - }
474 393 }
475 394  
476   -static void abs_printout(int cpu, int counter, double avg)
  395 +static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
477 396 {
478 397 double total, ratio = 0.0;
479 398 char cpustr[16] = { '\0', };
480 399  
481 400  
482 401  
... ... @@ -489,23 +408,23 @@
489 408 if (no_aggr)
490 409 sprintf(cpustr, "CPU%*d%s",
491 410 csv_output ? 0 : -4,
492   - cpumap[cpu], csv_sep);
  411 + cpus->map[cpu], csv_sep);
493 412 else
494 413 cpu = 0;
495 414  
496   - fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(counter));
  415 + fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel));
497 416  
498 417 if (csv_output)
499 418 return;
500 419  
501   - if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
  420 + if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
502 421 total = avg_stats(&runtime_cycles_stats[cpu]);
503 422  
504 423 if (total)
505 424 ratio = avg / total;
506 425  
507 426 fprintf(stderr, " # %10.3f IPC ", ratio);
508   - } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) &&
  427 + } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
509 428 runtime_branches_stats[cpu].n != 0) {
510 429 total = avg_stats(&runtime_branches_stats[cpu]);
511 430  
512 431  
... ... @@ -528,10 +447,11 @@
528 447 * Print out the results of a single counter:
529 448 * aggregated counts in system-wide mode
530 449 */
531   -static void print_counter_aggr(int counter)
  450 +static void print_counter_aggr(struct perf_evsel *counter)
532 451 {
533   - double avg = avg_stats(&event_res_stats[counter][0]);
534   - int scaled = event_scaled[counter];
  452 + struct perf_stat *ps = counter->priv;
  453 + double avg = avg_stats(&ps->res_stats[0]);
  454 + int scaled = counter->counts->scaled;
535 455  
536 456 if (scaled == -1) {
537 457 fprintf(stderr, "%*s%s%-24s\n",
... ... @@ -555,8 +475,8 @@
555 475 if (scaled) {
556 476 double avg_enabled, avg_running;
557 477  
558   - avg_enabled = avg_stats(&event_res_stats[counter][1]);
559   - avg_running = avg_stats(&event_res_stats[counter][2]);
  478 + avg_enabled = avg_stats(&ps->res_stats[1]);
  479 + avg_running = avg_stats(&ps->res_stats[2]);
560 480  
561 481 fprintf(stderr, " (scaled from %.2f%%)",
562 482 100 * avg_running / avg_enabled);
563 483  
564 484  
... ... @@ -569,19 +489,19 @@
569 489 * Print out the results of a single counter:
570 490 * does not use aggregated count in system-wide
571 491 */
572   -static void print_counter(int counter)
  492 +static void print_counter(struct perf_evsel *counter)
573 493 {
574 494 u64 ena, run, val;
575 495 int cpu;
576 496  
577   - for (cpu = 0; cpu < nr_cpus; cpu++) {
578   - val = cpu_counts[cpu][counter].val;
579   - ena = cpu_counts[cpu][counter].ena;
580   - run = cpu_counts[cpu][counter].run;
  497 + for (cpu = 0; cpu < cpus->nr; cpu++) {
  498 + val = counter->counts->cpu[cpu].val;
  499 + ena = counter->counts->cpu[cpu].ena;
  500 + run = counter->counts->cpu[cpu].run;
581 501 if (run == 0 || ena == 0) {
582 502 fprintf(stderr, "CPU%*d%s%*s%s%-24s",
583 503 csv_output ? 0 : -4,
584   - cpumap[cpu], csv_sep,
  504 + cpus->map[cpu], csv_sep,
585 505 csv_output ? 0 : 18,
586 506 "<not counted>", csv_sep,
587 507 event_name(counter));
... ... @@ -609,7 +529,8 @@
609 529  
610 530 static void print_stat(int argc, const char **argv)
611 531 {
612   - int i, counter;
  532 + struct perf_evsel *counter;
  533 + int i;
613 534  
614 535 fflush(stdout);
615 536  
616 537  
... ... @@ -632,10 +553,10 @@
632 553 }
633 554  
634 555 if (no_aggr) {
635   - for (counter = 0; counter < nr_counters; counter++)
  556 + list_for_each_entry(counter, &evsel_list, node)
636 557 print_counter(counter);
637 558 } else {
638   - for (counter = 0; counter < nr_counters; counter++)
  559 + list_for_each_entry(counter, &evsel_list, node)
639 560 print_counter_aggr(counter);
640 561 }
641 562  
... ... @@ -720,8 +641,8 @@
720 641  
721 642 int cmd_stat(int argc, const char **argv, const char *prefix __used)
722 643 {
723   - int status;
724   - int i,j;
  644 + struct perf_evsel *pos;
  645 + int status = -ENOMEM;
725 646  
726 647 setlocale(LC_ALL, "");
727 648  
728 649  
729 650  
730 651  
731 652  
732 653  
733 654  
734 655  
... ... @@ -757,41 +678,45 @@
757 678  
758 679 /* Set attrs and nr_counters if no event is selected and !null_run */
759 680 if (!null_run && !nr_counters) {
760   - memcpy(attrs, default_attrs, sizeof(default_attrs));
  681 + size_t c;
  682 +
761 683 nr_counters = ARRAY_SIZE(default_attrs);
  684 +
  685 + for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) {
  686 + pos = perf_evsel__new(default_attrs[c].type,
  687 + default_attrs[c].config,
  688 + nr_counters);
  689 + if (pos == NULL)
  690 + goto out;
  691 + list_add(&pos->node, &evsel_list);
  692 + }
762 693 }
763 694  
764   - if (system_wide)
765   - nr_cpus = read_cpu_map(cpu_list);
766   - else
767   - nr_cpus = 1;
  695 + if (target_pid != -1)
  696 + target_tid = target_pid;
768 697  
769   - if (nr_cpus < 1)
  698 + threads = thread_map__new(target_pid, target_tid);
  699 + if (threads == NULL) {
  700 + pr_err("Problems finding threads of monitor\n");
770 701 usage_with_options(stat_usage, options);
  702 + }
771 703  
772   - if (target_pid != -1) {
773   - target_tid = target_pid;
774   - thread_num = find_all_tid(target_pid, &all_tids);
775   - if (thread_num <= 0) {
776   - fprintf(stderr, "Can't find all threads of pid %d\n",
777   - target_pid);
778   - usage_with_options(stat_usage, options);
779   - }
780   - } else {
781   - all_tids=malloc(sizeof(pid_t));
782   - if (!all_tids)
783   - return -ENOMEM;
  704 + if (system_wide)
  705 + cpus = cpu_map__new(cpu_list);
  706 + else
  707 + cpus = cpu_map__dummy_new();
784 708  
785   - all_tids[0] = target_tid;
786   - thread_num = 1;
  709 + if (cpus == NULL) {
  710 + perror("failed to parse CPUs map");
  711 + usage_with_options(stat_usage, options);
  712 + return -1;
787 713 }
788 714  
789   - for (i = 0; i < MAX_NR_CPUS; i++) {
790   - for (j = 0; j < MAX_COUNTERS; j++) {
791   - fd[i][j] = malloc(sizeof(int)*thread_num);
792   - if (!fd[i][j])
793   - return -ENOMEM;
794   - }
  715 + list_for_each_entry(pos, &evsel_list, node) {
  716 + if (perf_evsel__alloc_stat_priv(pos) < 0 ||
  717 + perf_evsel__alloc_counts(pos, cpus->nr) < 0 ||
  718 + perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
  719 + goto out_free_fd;
795 720 }
796 721  
797 722 /*
... ... @@ -814,7 +739,12 @@
814 739  
815 740 if (status != -1)
816 741 print_stat(argc, argv);
817   -
  742 +out_free_fd:
  743 + list_for_each_entry(pos, &evsel_list, node)
  744 + perf_evsel__free_stat_priv(pos);
  745 +out:
  746 + thread_map__delete(threads);
  747 + threads = NULL;
818 748 return status;
819 749 }
tools/perf/builtin-test.c
... ... @@ -234,6 +234,85 @@
234 234 return err;
235 235 }
236 236  
  237 +#include "util/evsel.h"
  238 +#include <sys/types.h>
  239 +
  240 +static int trace_event__id(const char *event_name)
  241 +{
  242 + char *filename;
  243 + int err = -1, fd;
  244 +
  245 + if (asprintf(&filename,
  246 + "/sys/kernel/debug/tracing/events/syscalls/%s/id",
  247 + event_name) < 0)
  248 + return -1;
  249 +
  250 + fd = open(filename, O_RDONLY);
  251 + if (fd >= 0) {
  252 + char id[16];
  253 + if (read(fd, id, sizeof(id)) > 0)
  254 + err = atoi(id);
  255 + close(fd);
  256 + }
  257 +
  258 + free(filename);
  259 + return err;
  260 +}
  261 +
  262 +static int test__open_syscall_event(void)
  263 +{
  264 + int err = -1, fd;
  265 + struct thread_map *threads;
  266 + struct perf_evsel *evsel;
  267 + unsigned int nr_open_calls = 111, i;
  268 + int id = trace_event__id("sys_enter_open");
  269 +
  270 + if (id < 0) {
  271 + pr_debug("trace_event__id(\"sys_enter_open\") ");
  272 + return -1;
  273 + }
  274 +
  275 + threads = thread_map__new(-1, getpid());
  276 + if (threads == NULL) {
  277 + pr_debug("thread_map__new ");
  278 + return -1;
  279 + }
  280 +
  281 + evsel = perf_evsel__new(PERF_TYPE_TRACEPOINT, id, 0);
  282 + if (evsel == NULL) {
  283 + pr_debug("perf_evsel__new ");
  284 + goto out_thread_map_delete;
  285 + }
  286 +
  287 + if (perf_evsel__open_per_thread(evsel, threads) < 0) {
  288 + pr_debug("perf_evsel__open_per_thread ");
  289 + goto out_evsel_delete;
  290 + }
  291 +
  292 + for (i = 0; i < nr_open_calls; ++i) {
  293 + fd = open("/etc/passwd", O_RDONLY);
  294 + close(fd);
  295 + }
  296 +
  297 + if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
  298 + pr_debug("perf_evsel__open_read_on_cpu ");
  299 + goto out_close_fd;
  300 + }
  301 +
  302 + if (evsel->counts->cpu[0].val != nr_open_calls)
  303 + pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %Ld ",
  304 + nr_open_calls, evsel->counts->cpu[0].val);
  305 +
  306 + err = 0;
  307 +out_close_fd:
  308 + perf_evsel__close_fd(evsel, 1, threads->nr);
  309 +out_evsel_delete:
  310 + perf_evsel__delete(evsel);
  311 +out_thread_map_delete:
  312 + thread_map__delete(threads);
  313 + return err;
  314 +}
  315 +
237 316 static struct test {
238 317 const char *desc;
239 318 int (*func)(void);
... ... @@ -241,6 +320,10 @@
241 320 {
242 321 .desc = "vmlinux symtab matches kallsyms",
243 322 .func = test__vmlinux_matches_kallsyms,
  323 + },
  324 + {
  325 + .desc = "detect open syscall event",
  326 + .func = test__open_syscall_event,
244 327 },
245 328 {
246 329 .func = NULL,
tools/perf/builtin-top.c
... ... @@ -21,6 +21,7 @@
21 21 #include "perf.h"
22 22  
23 23 #include "util/color.h"
  24 +#include "util/evsel.h"
24 25 #include "util/session.h"
25 26 #include "util/symbol.h"
26 27 #include "util/thread.h"
... ... @@ -29,6 +30,7 @@
29 30 #include "util/parse-options.h"
30 31 #include "util/parse-events.h"
31 32 #include "util/cpumap.h"
  33 +#include "util/xyarray.h"
32 34  
33 35 #include "util/debug.h"
34 36  
... ... @@ -55,7 +57,7 @@
55 57 #include <linux/unistd.h>
56 58 #include <linux/types.h>
57 59  
58   -static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
  60 +#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
59 61  
60 62 static bool system_wide = false;
61 63  
62 64  
... ... @@ -66,10 +68,9 @@
66 68  
67 69 static int target_pid = -1;
68 70 static int target_tid = -1;
69   -static pid_t *all_tids = NULL;
70   -static int thread_num = 0;
  71 +static struct thread_map *threads;
71 72 static bool inherit = false;
72   -static int nr_cpus = 0;
  73 +static struct cpu_map *cpus;
73 74 static int realtime_prio = 0;
74 75 static bool group = false;
75 76 static unsigned int page_size;
... ... @@ -100,6 +101,7 @@
100 101 struct sym_entry *sym_filter_entry_sched = NULL;
101 102 static int sym_pcnt_filter = 5;
102 103 static int sym_counter = 0;
  104 +static struct perf_evsel *sym_evsel = NULL;
103 105 static int display_weighted = -1;
104 106 static const char *cpu_list;
105 107  
... ... @@ -353,7 +355,7 @@
353 355 return;
354 356  
355 357 symbol = sym_entry__symbol(syme);
356   - printf("Showing %s for %s\n", event_name(sym_counter), symbol->name);
  358 + printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name);
357 359 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
358 360  
359 361 pthread_mutex_lock(&syme->src->lock);
... ... @@ -460,7 +462,8 @@
460 462 static void print_sym_table(void)
461 463 {
462 464 int printed = 0, j;
463   - int counter, snap = !display_weighted ? sym_counter : 0;
  465 + struct perf_evsel *counter;
  466 + int snap = !display_weighted ? sym_counter : 0;
464 467 float samples_per_sec = samples/delay_secs;
465 468 float ksamples_per_sec = kernel_samples/delay_secs;
466 469 float us_samples_per_sec = (us_samples)/delay_secs;
... ... @@ -532,7 +535,9 @@
532 535 }
533 536  
534 537 if (nr_counters == 1 || !display_weighted) {
535   - printf("%Ld", (u64)attrs[0].sample_period);
  538 + struct perf_evsel *first;
  539 + first = list_entry(evsel_list.next, struct perf_evsel, node);
  540 + printf("%Ld", first->attr.sample_period);
536 541 if (freq)
537 542 printf("Hz ");
538 543 else
... ... @@ -540,9 +545,9 @@
540 545 }
541 546  
542 547 if (!display_weighted)
543   - printf("%s", event_name(sym_counter));
544   - else for (counter = 0; counter < nr_counters; counter++) {
545   - if (counter)
  548 + printf("%s", event_name(sym_evsel));
  549 + else list_for_each_entry(counter, &evsel_list, node) {
  550 + if (counter->idx)
546 551 printf("/");
547 552  
548 553 printf("%s", event_name(counter));
549 554  
... ... @@ -558,12 +563,12 @@
558 563 printf(" (all");
559 564  
560 565 if (cpu_list)
561   - printf(", CPU%s: %s)\n", nr_cpus > 1 ? "s" : "", cpu_list);
  566 + printf(", CPU%s: %s)\n", cpus->nr > 1 ? "s" : "", cpu_list);
562 567 else {
563 568 if (target_tid != -1)
564 569 printf(")\n");
565 570 else
566   - printf(", %d CPU%s)\n", nr_cpus, nr_cpus > 1 ? "s" : "");
  571 + printf(", %d CPU%s)\n", cpus->nr, cpus->nr > 1 ? "s" : "");
567 572 }
568 573  
569 574 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
... ... @@ -739,7 +744,7 @@
739 744 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries);
740 745  
741 746 if (nr_counters > 1)
742   - fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter));
  747 + fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel));
743 748  
744 749 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
745 750  
746 751  
747 752  
748 753  
749 754  
750 755  
751 756  
... ... @@ -826,19 +831,23 @@
826 831 break;
827 832 case 'E':
828 833 if (nr_counters > 1) {
829   - int i;
830   -
831 834 fprintf(stderr, "\nAvailable events:");
832   - for (i = 0; i < nr_counters; i++)
833   - fprintf(stderr, "\n\t%d %s", i, event_name(i));
834 835  
  836 + list_for_each_entry(sym_evsel, &evsel_list, node)
  837 + fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel));
  838 +
835 839 prompt_integer(&sym_counter, "Enter details event counter");
836 840  
837 841 if (sym_counter >= nr_counters) {
838   - fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0));
  842 + sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node);
839 843 sym_counter = 0;
  844 + fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel));
840 845 sleep(1);
  846 + break;
841 847 }
  848 + list_for_each_entry(sym_evsel, &evsel_list, node)
  849 + if (sym_evsel->idx == sym_counter)
  850 + break;
842 851 } else sym_counter = 0;
843 852 break;
844 853 case 'f':
... ... @@ -978,7 +987,8 @@
978 987  
979 988 static void event__process_sample(const event_t *self,
980 989 struct sample_data *sample,
981   - struct perf_session *session, int counter)
  990 + struct perf_session *session,
  991 + struct perf_evsel *evsel)
982 992 {
983 993 u64 ip = self->ip.ip;
984 994 struct sym_entry *syme;
985 995  
... ... @@ -1071,9 +1081,9 @@
1071 1081  
1072 1082 syme = symbol__priv(al.sym);
1073 1083 if (!syme->skip) {
1074   - syme->count[counter]++;
  1084 + syme->count[evsel->idx]++;
1075 1085 syme->origin = origin;
1076   - record_precise_ip(syme, counter, ip);
  1086 + record_precise_ip(syme, evsel->idx, ip);
1077 1087 pthread_mutex_lock(&active_symbols_lock);
1078 1088 if (list_empty(&syme->node) || !syme->node.next)
1079 1089 __list_insert_active_sym(syme);
1080 1090  
... ... @@ -1082,12 +1092,24 @@
1082 1092 }
1083 1093  
1084 1094 struct mmap_data {
1085   - int counter;
1086 1095 void *base;
1087 1096 int mask;
1088 1097 unsigned int prev;
1089 1098 };
1090 1099  
  1100 +static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel,
  1101 + int ncpus, int nthreads)
  1102 +{
  1103 + evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data));
  1104 + return evsel->priv != NULL ? 0 : -ENOMEM;
  1105 +}
  1106 +
  1107 +static void perf_evsel__free_mmap(struct perf_evsel *evsel)
  1108 +{
  1109 + xyarray__delete(evsel->priv);
  1110 + evsel->priv = NULL;
  1111 +}
  1112 +
1091 1113 static unsigned int mmap_read_head(struct mmap_data *md)
1092 1114 {
1093 1115 struct perf_event_mmap_page *pc = md->base;
1094 1116  
... ... @@ -1100,8 +1122,11 @@
1100 1122 }
1101 1123  
1102 1124 static void perf_session__mmap_read_counter(struct perf_session *self,
1103   - struct mmap_data *md)
  1125 + struct perf_evsel *evsel,
  1126 + int cpu, int thread_idx)
1104 1127 {
  1128 + struct xyarray *mmap_array = evsel->priv;
  1129 + struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx);
1105 1130 unsigned int head = mmap_read_head(md);
1106 1131 unsigned int old = md->prev;
1107 1132 unsigned char *data = md->base + page_size;
... ... @@ -1155,7 +1180,7 @@
1155 1180  
1156 1181 event__parse_sample(event, self, &sample);
1157 1182 if (event->header.type == PERF_RECORD_SAMPLE)
1158   - event__process_sample(event, &sample, self, md->counter);
  1183 + event__process_sample(event, &sample, self, evsel);
1159 1184 else
1160 1185 event__process(event, &sample, self);
1161 1186 old += size;
1162 1187  
1163 1188  
1164 1189  
1165 1190  
1166 1191  
1167 1192  
1168 1193  
1169 1194  
1170 1195  
... ... @@ -1165,36 +1190,39 @@
1165 1190 }
1166 1191  
1167 1192 static struct pollfd *event_array;
1168   -static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
1169 1193  
1170 1194 static void perf_session__mmap_read(struct perf_session *self)
1171 1195 {
1172   - int i, counter, thread_index;
  1196 + struct perf_evsel *counter;
  1197 + int i, thread_index;
1173 1198  
1174   - for (i = 0; i < nr_cpus; i++) {
1175   - for (counter = 0; counter < nr_counters; counter++)
  1199 + for (i = 0; i < cpus->nr; i++) {
  1200 + list_for_each_entry(counter, &evsel_list, node) {
1176 1201 for (thread_index = 0;
1177   - thread_index < thread_num;
  1202 + thread_index < threads->nr;
1178 1203 thread_index++) {
1179 1204 perf_session__mmap_read_counter(self,
1180   - &mmap_array[i][counter][thread_index]);
  1205 + counter, i, thread_index);
1181 1206 }
  1207 + }
1182 1208 }
1183 1209 }
1184 1210  
1185 1211 int nr_poll;
1186 1212 int group_fd;
1187 1213  
1188   -static void start_counter(int i, int counter)
  1214 +static void start_counter(int i, struct perf_evsel *evsel)
1189 1215 {
  1216 + struct xyarray *mmap_array = evsel->priv;
  1217 + struct mmap_data *mm;
1190 1218 struct perf_event_attr *attr;
1191 1219 int cpu = -1;
1192 1220 int thread_index;
1193 1221  
1194 1222 if (target_tid == -1)
1195   - cpu = cpumap[i];
  1223 + cpu = cpus->map[i];
1196 1224  
1197   - attr = attrs + counter;
  1225 + attr = &evsel->attr;
1198 1226  
1199 1227 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1200 1228  
1201 1229  
1202 1230  
... ... @@ -1207,12 +1235,12 @@
1207 1235 attr->inherit = (cpu < 0) && inherit;
1208 1236 attr->mmap = 1;
1209 1237  
1210   - for (thread_index = 0; thread_index < thread_num; thread_index++) {
  1238 + for (thread_index = 0; thread_index < threads->nr; thread_index++) {
1211 1239 try_again:
1212   - fd[i][counter][thread_index] = sys_perf_event_open(attr,
1213   - all_tids[thread_index], cpu, group_fd, 0);
  1240 + FD(evsel, i, thread_index) = sys_perf_event_open(attr,
  1241 + threads->map[thread_index], cpu, group_fd, 0);
1214 1242  
1215   - if (fd[i][counter][thread_index] < 0) {
  1243 + if (FD(evsel, i, thread_index) < 0) {
1216 1244 int err = errno;
1217 1245  
1218 1246 if (err == EPERM || err == EACCES)
1219 1247  
1220 1248  
1221 1249  
1222 1250  
... ... @@ -1236,29 +1264,29 @@
1236 1264 }
1237 1265 printf("\n");
1238 1266 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
1239   - fd[i][counter][thread_index], strerror(err));
  1267 + FD(evsel, i, thread_index), strerror(err));
1240 1268 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
1241 1269 exit(-1);
1242 1270 }
1243   - assert(fd[i][counter][thread_index] >= 0);
1244   - fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK);
  1271 + assert(FD(evsel, i, thread_index) >= 0);
  1272 + fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK);
1245 1273  
1246 1274 /*
1247 1275 * First counter acts as the group leader:
1248 1276 */
1249 1277 if (group && group_fd == -1)
1250   - group_fd = fd[i][counter][thread_index];
  1278 + group_fd = FD(evsel, i, thread_index);
1251 1279  
1252   - event_array[nr_poll].fd = fd[i][counter][thread_index];
  1280 + event_array[nr_poll].fd = FD(evsel, i, thread_index);
1253 1281 event_array[nr_poll].events = POLLIN;
1254 1282 nr_poll++;
1255 1283  
1256   - mmap_array[i][counter][thread_index].counter = counter;
1257   - mmap_array[i][counter][thread_index].prev = 0;
1258   - mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1;
1259   - mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size,
1260   - PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0);
1261   - if (mmap_array[i][counter][thread_index].base == MAP_FAILED)
  1284 + mm = xyarray__entry(mmap_array, i, thread_index);
  1285 + mm->prev = 0;
  1286 + mm->mask = mmap_pages*page_size - 1;
  1287 + mm->base = mmap(NULL, (mmap_pages+1)*page_size,
  1288 + PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0);
  1289 + if (mm->base == MAP_FAILED)
1262 1290 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1263 1291 }
1264 1292 }
... ... @@ -1266,8 +1294,8 @@
1266 1294 static int __cmd_top(void)
1267 1295 {
1268 1296 pthread_t thread;
1269   - int i, counter;
1270   - int ret;
  1297 + struct perf_evsel *counter;
  1298 + int i, ret;
1271 1299 /*
1272 1300 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1273 1301 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1274 1302  
... ... @@ -1281,9 +1309,9 @@
1281 1309 else
1282 1310 event__synthesize_threads(event__process, session);
1283 1311  
1284   - for (i = 0; i < nr_cpus; i++) {
  1312 + for (i = 0; i < cpus->nr; i++) {
1285 1313 group_fd = -1;
1286   - for (counter = 0; counter < nr_counters; counter++)
  1314 + list_for_each_entry(counter, &evsel_list, node)
1287 1315 start_counter(i, counter);
1288 1316 }
1289 1317  
... ... @@ -1372,8 +1400,8 @@
1372 1400  
1373 1401 int cmd_top(int argc, const char **argv, const char *prefix __used)
1374 1402 {
1375   - int counter;
1376   - int i,j;
  1403 + struct perf_evsel *pos;
  1404 + int status = -ENOMEM;
1377 1405  
1378 1406 page_size = sysconf(_SC_PAGE_SIZE);
1379 1407  
1380 1408  
1381 1409  
1382 1410  
... ... @@ -1381,34 +1409,17 @@
1381 1409 if (argc)
1382 1410 usage_with_options(top_usage, options);
1383 1411  
1384   - if (target_pid != -1) {
  1412 + if (target_pid != -1)
1385 1413 target_tid = target_pid;
1386   - thread_num = find_all_tid(target_pid, &all_tids);
1387   - if (thread_num <= 0) {
1388   - fprintf(stderr, "Can't find all threads of pid %d\n",
1389   - target_pid);
1390   - usage_with_options(top_usage, options);
1391   - }
1392   - } else {
1393   - all_tids=malloc(sizeof(pid_t));
1394   - if (!all_tids)
1395   - return -ENOMEM;
1396 1414  
1397   - all_tids[0] = target_tid;
1398   - thread_num = 1;
  1415 + threads = thread_map__new(target_pid, target_tid);
  1416 + if (threads == NULL) {
  1417 + pr_err("Problems finding threads of monitor\n");
  1418 + usage_with_options(top_usage, options);
1399 1419 }
1400 1420  
1401   - for (i = 0; i < MAX_NR_CPUS; i++) {
1402   - for (j = 0; j < MAX_COUNTERS; j++) {
1403   - fd[i][j] = malloc(sizeof(int)*thread_num);
1404   - mmap_array[i][j] = zalloc(
1405   - sizeof(struct mmap_data)*thread_num);
1406   - if (!fd[i][j] || !mmap_array[i][j])
1407   - return -ENOMEM;
1408   - }
1409   - }
1410   - event_array = malloc(
1411   - sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
  1421 + event_array = malloc((sizeof(struct pollfd) *
  1422 + MAX_NR_CPUS * MAX_COUNTERS * threads->nr));
1412 1423 if (!event_array)
1413 1424 return -ENOMEM;
1414 1425  
1415 1426  
... ... @@ -1419,16 +1430,11 @@
1419 1430 cpu_list = NULL;
1420 1431 }
1421 1432  
1422   - if (!nr_counters)
1423   - nr_counters = 1;
  1433 + if (!nr_counters && perf_evsel_list__create_default() < 0) {
  1434 + pr_err("Not enough memory for event selector list\n");
  1435 + return -ENOMEM;
  1436 + }
1424 1437  
1425   - symbol_conf.priv_size = (sizeof(struct sym_entry) +
1426   - (nr_counters + 1) * sizeof(unsigned long));
1427   -
1428   - symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1429   - if (symbol__init() < 0)
1430   - return -1;
1431   -
1432 1438 if (delay_secs < 1)
1433 1439 delay_secs = 1;
1434 1440  
1435 1441  
1436 1442  
1437 1443  
... ... @@ -1444,23 +1450,33 @@
1444 1450 exit(EXIT_FAILURE);
1445 1451 }
1446 1452  
1447   - /*
1448   - * Fill in the ones not specifically initialized via -c:
1449   - */
1450   - for (counter = 0; counter < nr_counters; counter++) {
1451   - if (attrs[counter].sample_period)
  1453 + if (target_tid != -1)
  1454 + cpus = cpu_map__dummy_new();
  1455 + else
  1456 + cpus = cpu_map__new(cpu_list);
  1457 +
  1458 + if (cpus == NULL)
  1459 + usage_with_options(top_usage, options);
  1460 +
  1461 + list_for_each_entry(pos, &evsel_list, node) {
  1462 + if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 ||
  1463 + perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
  1464 + goto out_free_fd;
  1465 + /*
  1466 + * Fill in the ones not specifically initialized via -c:
  1467 + */
  1468 + if (pos->attr.sample_period)
1452 1469 continue;
1453 1470  
1454   - attrs[counter].sample_period = default_interval;
  1471 + pos->attr.sample_period = default_interval;
1455 1472 }
1456 1473  
1457   - if (target_tid != -1)
1458   - nr_cpus = 1;
1459   - else
1460   - nr_cpus = read_cpu_map(cpu_list);
  1474 + symbol_conf.priv_size = (sizeof(struct sym_entry) +
  1475 + (nr_counters + 1) * sizeof(unsigned long));
1461 1476  
1462   - if (nr_cpus < 1)
1463   - usage_with_options(top_usage, options);
  1477 + symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
  1478 + if (symbol__init() < 0)
  1479 + return -1;
1464 1480  
1465 1481 get_term_dimensions(&winsize);
1466 1482 if (print_entries == 0) {
... ... @@ -1468,6 +1484,11 @@
1468 1484 signal(SIGWINCH, sig_winch_handler);
1469 1485 }
1470 1486  
1471   - return __cmd_top();
  1487 + status = __cmd_top();
  1488 +out_free_fd:
  1489 + list_for_each_entry(pos, &evsel_list, node)
  1490 + perf_evsel__free_mmap(pos);
  1491 +
  1492 + return status;
1472 1493 }
... ... @@ -286,6 +286,8 @@
286 286 status = p->fn(argc, argv, prefix);
287 287 exit_browser(status);
288 288  
  289 + perf_evsel_list__delete();
  290 +
289 291 if (status)
290 292 return status & 0xff;
291 293  
tools/perf/util/cpumap.c
... ... @@ -4,32 +4,53 @@
4 4 #include <assert.h>
5 5 #include <stdio.h>
6 6  
7   -int cpumap[MAX_NR_CPUS];
8   -
9   -static int default_cpu_map(void)
  7 +static struct cpu_map *cpu_map__default_new(void)
10 8 {
11   - int nr_cpus, i;
  9 + struct cpu_map *cpus;
  10 + int nr_cpus;
12 11  
13 12 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
14   - assert(nr_cpus <= MAX_NR_CPUS);
15   - assert((int)nr_cpus >= 0);
  13 + if (nr_cpus < 0)
  14 + return NULL;
16 15  
17   - for (i = 0; i < nr_cpus; ++i)
18   - cpumap[i] = i;
  16 + cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int));
  17 + if (cpus != NULL) {
  18 + int i;
  19 + for (i = 0; i < nr_cpus; ++i)
  20 + cpus->map[i] = i;
19 21  
20   - return nr_cpus;
  22 + cpus->nr = nr_cpus;
  23 + }
  24 +
  25 + return cpus;
21 26 }
22 27  
23   -static int read_all_cpu_map(void)
  28 +static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
24 29 {
  30 + size_t payload_size = nr_cpus * sizeof(int);
  31 + struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size);
  32 +
  33 + if (cpus != NULL) {
  34 + cpus->nr = nr_cpus;
  35 + memcpy(cpus->map, tmp_cpus, payload_size);
  36 + }
  37 +
  38 + return cpus;
  39 +}
  40 +
  41 +static struct cpu_map *cpu_map__read_all_cpu_map(void)
  42 +{
  43 + struct cpu_map *cpus = NULL;
25 44 FILE *onlnf;
26 45 int nr_cpus = 0;
  46 + int *tmp_cpus = NULL, *tmp;
  47 + int max_entries = 0;
27 48 int n, cpu, prev;
28 49 char sep;
29 50  
30 51 onlnf = fopen("/sys/devices/system/cpu/online", "r");
31 52 if (!onlnf)
32   - return default_cpu_map();
  53 + return cpu_map__default_new();
33 54  
34 55 sep = 0;
35 56 prev = -1;
36 57  
37 58  
... ... @@ -38,12 +59,28 @@
38 59 if (n <= 0)
39 60 break;
40 61 if (prev >= 0) {
41   - assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS);
  62 + int new_max = nr_cpus + cpu - prev - 1;
  63 +
  64 + if (new_max >= max_entries) {
  65 + max_entries = new_max + MAX_NR_CPUS / 2;
  66 + tmp = realloc(tmp_cpus, max_entries * sizeof(int));
  67 + if (tmp == NULL)
  68 + goto out_free_tmp;
  69 + tmp_cpus = tmp;
  70 + }
  71 +
42 72 while (++prev < cpu)
43   - cpumap[nr_cpus++] = prev;
  73 + tmp_cpus[nr_cpus++] = prev;
44 74 }
45   - assert (nr_cpus < MAX_NR_CPUS);
46   - cpumap[nr_cpus++] = cpu;
  75 + if (nr_cpus == max_entries) {
  76 + max_entries += MAX_NR_CPUS;
  77 + tmp = realloc(tmp_cpus, max_entries * sizeof(int));
  78 + if (tmp == NULL)
  79 + goto out_free_tmp;
  80 + tmp_cpus = tmp;
  81 + }
  82 +
  83 + tmp_cpus[nr_cpus++] = cpu;
47 84 if (n == 2 && sep == '-')
48 85 prev = cpu;
49 86 else
50 87  
51 88  
52 89  
53 90  
54 91  
55 92  
... ... @@ -51,24 +88,31 @@
51 88 if (n == 1 || sep == '\n')
52 89 break;
53 90 }
54   - fclose(onlnf);
55   - if (nr_cpus > 0)
56   - return nr_cpus;
57 91  
58   - return default_cpu_map();
  92 + if (nr_cpus > 0)
  93 + cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
  94 + else
  95 + cpus = cpu_map__default_new();
  96 +out_free_tmp:
  97 + free(tmp_cpus);
  98 + fclose(onlnf);
  99 + return cpus;
59 100 }
60 101  
61   -int read_cpu_map(const char *cpu_list)
  102 +struct cpu_map *cpu_map__new(const char *cpu_list)
62 103 {
  104 + struct cpu_map *cpus = NULL;
63 105 unsigned long start_cpu, end_cpu = 0;
64 106 char *p = NULL;
65 107 int i, nr_cpus = 0;
  108 + int *tmp_cpus = NULL, *tmp;
  109 + int max_entries = 0;
66 110  
67 111 if (!cpu_list)
68   - return read_all_cpu_map();
  112 + return cpu_map__read_all_cpu_map();
69 113  
70 114 if (!isdigit(*cpu_list))
71   - goto invalid;
  115 + goto out;
72 116  
73 117 while (isdigit(*cpu_list)) {
74 118 p = NULL;
75 119  
76 120  
77 121  
78 122  
... ... @@ -94,22 +138,43 @@
94 138 for (; start_cpu <= end_cpu; start_cpu++) {
95 139 /* check for duplicates */
96 140 for (i = 0; i < nr_cpus; i++)
97   - if (cpumap[i] == (int)start_cpu)
  141 + if (tmp_cpus[i] == (int)start_cpu)
98 142 goto invalid;
99 143  
100   - assert(nr_cpus < MAX_NR_CPUS);
101   - cpumap[nr_cpus++] = (int)start_cpu;
  144 + if (nr_cpus == max_entries) {
  145 + max_entries += MAX_NR_CPUS;
  146 + tmp = realloc(tmp_cpus, max_entries * sizeof(int));
  147 + if (tmp == NULL)
  148 + goto invalid;
  149 + tmp_cpus = tmp;
  150 + }
  151 + tmp_cpus[nr_cpus++] = (int)start_cpu;
102 152 }
103 153 if (*p)
104 154 ++p;
105 155  
106 156 cpu_list = p;
107 157 }
108   - if (nr_cpus > 0)
109   - return nr_cpus;
110 158  
111   - return default_cpu_map();
  159 + if (nr_cpus > 0)
  160 + cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
  161 + else
  162 + cpus = cpu_map__default_new();
112 163 invalid:
113   - return -1;
  164 + free(tmp_cpus);
  165 +out:
  166 + return cpus;
  167 +}
  168 +
  169 +struct cpu_map *cpu_map__dummy_new(void)
  170 +{
  171 + struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
  172 +
  173 + if (cpus != NULL) {
  174 + cpus->nr = 1;
  175 + cpus->map[0] = -1;
  176 + }
  177 +
  178 + return cpus;
114 179 }
tools/perf/util/cpumap.h
1 1 #ifndef __PERF_CPUMAP_H
2 2 #define __PERF_CPUMAP_H
3 3  
4   -extern int read_cpu_map(const char *cpu_list);
5   -extern int cpumap[];
  4 +struct cpu_map {
  5 + int nr;
  6 + int map[];
  7 +};
  8 +
  9 +struct cpu_map *cpu_map__new(const char *cpu_list);
  10 +struct cpu_map *cpu_map__dummy_new(void);
  11 +void *cpu_map__delete(struct cpu_map *map);
6 12  
7 13 #endif /* __PERF_CPUMAP_H */
tools/perf/util/evsel.c
  1 +#include "evsel.h"
  2 +#include "../perf.h"
  3 +#include "util.h"
  4 +#include "cpumap.h"
  5 +#include "thread.h"
  6 +
  7 +#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
  8 +
  9 +struct perf_evsel *perf_evsel__new(u32 type, u64 config, int idx)
  10 +{
  11 + struct perf_evsel *evsel = zalloc(sizeof(*evsel));
  12 +
  13 + if (evsel != NULL) {
  14 + evsel->idx = idx;
  15 + evsel->attr.type = type;
  16 + evsel->attr.config = config;
  17 + INIT_LIST_HEAD(&evsel->node);
  18 + }
  19 +
  20 + return evsel;
  21 +}
  22 +
  23 +int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
  24 +{
  25 + evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
  26 + return evsel->fd != NULL ? 0 : -ENOMEM;
  27 +}
  28 +
  29 +int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
  30 +{
  31 + evsel->counts = zalloc((sizeof(*evsel->counts) +
  32 + (ncpus * sizeof(struct perf_counts_values))));
  33 + return evsel->counts != NULL ? 0 : -ENOMEM;
  34 +}
  35 +
  36 +void perf_evsel__free_fd(struct perf_evsel *evsel)
  37 +{
  38 + xyarray__delete(evsel->fd);
  39 + evsel->fd = NULL;
  40 +}
  41 +
  42 +void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
  43 +{
  44 + int cpu, thread;
  45 +
  46 + for (cpu = 0; cpu < ncpus; cpu++)
  47 + for (thread = 0; thread < nthreads; ++thread) {
  48 + close(FD(evsel, cpu, thread));
  49 + FD(evsel, cpu, thread) = -1;
  50 + }
  51 +}
  52 +
  53 +void perf_evsel__delete(struct perf_evsel *evsel)
  54 +{
  55 + assert(list_empty(&evsel->node));
  56 + xyarray__delete(evsel->fd);
  57 + free(evsel);
  58 +}
  59 +
  60 +int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
  61 + int cpu, int thread, bool scale)
  62 +{
  63 + struct perf_counts_values count;
  64 + size_t nv = scale ? 3 : 1;
  65 +
  66 + if (FD(evsel, cpu, thread) < 0)
  67 + return -EINVAL;
  68 +
  69 + if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
  70 + return -ENOMEM;
  71 +
  72 + if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
  73 + return -errno;
  74 +
  75 + if (scale) {
  76 + if (count.run == 0)
  77 + count.val = 0;
  78 + else if (count.run < count.ena)
  79 + count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
  80 + } else
  81 + count.ena = count.run = 0;
  82 +
  83 + evsel->counts->cpu[cpu] = count;
  84 + return 0;
  85 +}
  86 +
  87 +int __perf_evsel__read(struct perf_evsel *evsel,
  88 + int ncpus, int nthreads, bool scale)
  89 +{
  90 + size_t nv = scale ? 3 : 1;
  91 + int cpu, thread;
  92 + struct perf_counts_values *aggr = &evsel->counts->aggr, count;
  93 +
  94 + aggr->val = 0;
  95 +
  96 + for (cpu = 0; cpu < ncpus; cpu++) {
  97 + for (thread = 0; thread < nthreads; thread++) {
  98 + if (FD(evsel, cpu, thread) < 0)
  99 + continue;
  100 +
  101 + if (readn(FD(evsel, cpu, thread),
  102 + &count, nv * sizeof(u64)) < 0)
  103 + return -errno;
  104 +
  105 + aggr->val += count.val;
  106 + if (scale) {
  107 + aggr->ena += count.ena;
  108 + aggr->run += count.run;
  109 + }
  110 + }
  111 + }
  112 +
  113 + evsel->counts->scaled = 0;
  114 + if (scale) {
  115 + if (aggr->run == 0) {
  116 + evsel->counts->scaled = -1;
  117 + aggr->val = 0;
  118 + return 0;
  119 + }
  120 +
  121 + if (aggr->run < aggr->ena) {
  122 + evsel->counts->scaled = 1;
  123 + aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
  124 + }
  125 + } else
  126 + aggr->ena = aggr->run = 0;
  127 +
  128 + return 0;
  129 +}
  130 +
  131 +int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus)
  132 +{
  133 + int cpu;
  134 +
  135 + if (evsel->fd == NULL && perf_evsel__alloc_fd(evsel, cpus->nr, 1) < 0)
  136 + return -1;
  137 +
  138 + for (cpu = 0; cpu < cpus->nr; cpu++) {
  139 + FD(evsel, cpu, 0) = sys_perf_event_open(&evsel->attr, -1,
  140 + cpus->map[cpu], -1, 0);
  141 + if (FD(evsel, cpu, 0) < 0)
  142 + goto out_close;
  143 + }
  144 +
  145 + return 0;
  146 +
  147 +out_close:
  148 + while (--cpu >= 0) {
  149 + close(FD(evsel, cpu, 0));
  150 + FD(evsel, cpu, 0) = -1;
  151 + }
  152 + return -1;
  153 +}
  154 +
  155 +int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads)
  156 +{
  157 + int thread;
  158 +
  159 + if (evsel->fd == NULL && perf_evsel__alloc_fd(evsel, 1, threads->nr))
  160 + return -1;
  161 +
  162 + for (thread = 0; thread < threads->nr; thread++) {
  163 + FD(evsel, 0, thread) = sys_perf_event_open(&evsel->attr,
  164 + threads->map[thread], -1, -1, 0);
  165 + if (FD(evsel, 0, thread) < 0)
  166 + goto out_close;
  167 + }
  168 +
  169 + return 0;
  170 +
  171 +out_close:
  172 + while (--thread >= 0) {
  173 + close(FD(evsel, 0, thread));
  174 + FD(evsel, 0, thread) = -1;
  175 + }
  176 + return -1;
  177 +}
  178 +
  179 +int perf_evsel__open(struct perf_evsel *evsel,
  180 + struct cpu_map *cpus, struct thread_map *threads)
  181 +{
  182 + if (threads == NULL)
  183 + return perf_evsel__open_per_cpu(evsel, cpus);
  184 +
  185 + return perf_evsel__open_per_thread(evsel, threads);
  186 +}
tools/perf/util/evsel.h
  1 +#ifndef __PERF_EVSEL_H
  2 +#define __PERF_EVSEL_H 1
  3 +
  4 +#include <linux/list.h>
  5 +#include <stdbool.h>
  6 +#include <linux/perf_event.h>
  7 +#include "types.h"
  8 +#include "xyarray.h"
  9 +
  10 +struct perf_counts_values {
  11 + union {
  12 + struct {
  13 + u64 val;
  14 + u64 ena;
  15 + u64 run;
  16 + };
  17 + u64 values[3];
  18 + };
  19 +};
  20 +
  21 +struct perf_counts {
  22 + s8 scaled;
  23 + struct perf_counts_values aggr;
  24 + struct perf_counts_values cpu[];
  25 +};
  26 +
  27 +struct perf_evsel {
  28 + struct list_head node;
  29 + struct perf_event_attr attr;
  30 + char *filter;
  31 + struct xyarray *fd;
  32 + struct perf_counts *counts;
  33 + int idx;
  34 + void *priv;
  35 +};
  36 +
  37 +struct cpu_map;
  38 +struct thread_map;
  39 +
  40 +struct perf_evsel *perf_evsel__new(u32 type, u64 config, int idx);
  41 +void perf_evsel__delete(struct perf_evsel *evsel);
  42 +
  43 +int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
  44 +int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
  45 +void perf_evsel__free_fd(struct perf_evsel *evsel);
  46 +void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
  47 +
  48 +int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus);
  49 +int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads);
  50 +int perf_evsel__open(struct perf_evsel *evsel,
  51 + struct cpu_map *cpus, struct thread_map *threads);
  52 +
  53 +#define perf_evsel__match(evsel, t, c) \
  54 + (evsel->attr.type == PERF_TYPE_##t && \
  55 + evsel->attr.config == PERF_COUNT_##c)
  56 +
  57 +int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
  58 + int cpu, int thread, bool scale);
  59 +
  60 +/**
  61 + * perf_evsel__read_on_cpu - Read out the results on a CPU and thread
  62 + *
  63 + * @evsel - event selector to read value
  64 + * @cpu - CPU of interest
  65 + * @thread - thread of interest
  66 + */
  67 +static inline int perf_evsel__read_on_cpu(struct perf_evsel *evsel,
  68 + int cpu, int thread)
  69 +{
  70 + return __perf_evsel__read_on_cpu(evsel, cpu, thread, false);
  71 +}
  72 +
  73 +/**
  74 + * perf_evsel__read_on_cpu_scaled - Read out the results on a CPU and thread, scaled
  75 + *
  76 + * @evsel - event selector to read value
  77 + * @cpu - CPU of interest
  78 + * @thread - thread of interest
  79 + */
  80 +static inline int perf_evsel__read_on_cpu_scaled(struct perf_evsel *evsel,
  81 + int cpu, int thread)
  82 +{
  83 + return __perf_evsel__read_on_cpu(evsel, cpu, thread, true);
  84 +}
  85 +
  86 +int __perf_evsel__read(struct perf_evsel *evsel, int ncpus, int nthreads,
  87 + bool scale);
  88 +
  89 +/**
  90 + * perf_evsel__read - Read the aggregate results on all CPUs
  91 + *
  92 + * @evsel - event selector to read value
  93 + * @ncpus - Number of cpus affected, from zero
  94 + * @nthreads - Number of threads affected, from zero
  95 + */
  96 +static inline int perf_evsel__read(struct perf_evsel *evsel,
  97 + int ncpus, int nthreads)
  98 +{
  99 + return __perf_evsel__read(evsel, ncpus, nthreads, false);
  100 +}
  101 +
  102 +/**
  103 + * perf_evsel__read_scaled - Read the aggregate results on all CPUs, scaled
  104 + *
  105 + * @evsel - event selector to read value
  106 + * @ncpus - Number of cpus affected, from zero
  107 + * @nthreads - Number of threads affected, from zero
  108 + */
  109 +static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
  110 + int ncpus, int nthreads)
  111 +{
  112 + return __perf_evsel__read(evsel, ncpus, nthreads, true);
  113 +}
  114 +
  115 +#endif /* __PERF_EVSEL_H */
tools/perf/util/header.c
... ... @@ -463,7 +463,7 @@
463 463  
464 464 /* Write trace info */
465 465 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
466   - read_tracing_data(fd, attrs, nr_counters);
  466 + read_tracing_data(fd, &evsel_list);
467 467 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
468 468 }
469 469  
... ... @@ -606,7 +606,7 @@
606 606 static int perf_header__getbuffer64(struct perf_header *self,
607 607 int fd, void *buf, size_t size)
608 608 {
609   - if (do_read(fd, buf, size) <= 0)
  609 + if (readn(fd, buf, size) <= 0)
610 610 return -1;
611 611  
612 612 if (self->needs_swap)
... ... @@ -662,7 +662,7 @@
662 662 {
663 663 lseek(fd, 0, SEEK_SET);
664 664  
665   - if (do_read(fd, self, sizeof(*self)) <= 0 ||
  665 + if (readn(fd, self, sizeof(*self)) <= 0 ||
666 666 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
667 667 return -1;
668 668  
... ... @@ -823,7 +823,7 @@
823 823 struct perf_header *ph, int fd,
824 824 bool repipe)
825 825 {
826   - if (do_read(fd, self, sizeof(*self)) <= 0 ||
  826 + if (readn(fd, self, sizeof(*self)) <= 0 ||
827 827 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
828 828 return -1;
829 829  
... ... @@ -1133,8 +1133,7 @@
1133 1133 return 0;
1134 1134 }
1135 1135  
1136   -int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
1137   - int nb_events,
  1136 +int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
1138 1137 event__handler_t process,
1139 1138 struct perf_session *session __unused)
1140 1139 {
... ... @@ -1145,7 +1144,7 @@
1145 1144 memset(&ev, 0, sizeof(ev));
1146 1145  
1147 1146 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1148   - size = read_tracing_data_size(fd, pattrs, nb_events);
  1147 + size = read_tracing_data_size(fd, pattrs);
1149 1148 if (size <= 0)
1150 1149 return size;
1151 1150 aligned_size = ALIGN(size, sizeof(u64));
... ... @@ -1155,7 +1154,7 @@
1155 1154  
1156 1155 process(&ev, NULL, session);
1157 1156  
1158   - err = read_tracing_data(fd, pattrs, nb_events);
  1157 + err = read_tracing_data(fd, pattrs);
1159 1158 write_padded(fd, NULL, 0, padding);
1160 1159  
1161 1160 return aligned_size;
tools/perf/util/header.h
... ... @@ -113,8 +113,7 @@
113 113 int event__process_event_type(event_t *self,
114 114 struct perf_session *session);
115 115  
116   -int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
117   - int nb_events,
  116 +int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
118 117 event__handler_t process,
119 118 struct perf_session *session);
120 119 int event__process_tracing_data(event_t *self,
tools/perf/util/parse-events.c
1 1 #include "../../../include/linux/hw_breakpoint.h"
2 2 #include "util.h"
3 3 #include "../perf.h"
  4 +#include "evsel.h"
4 5 #include "parse-options.h"
5 6 #include "parse-events.h"
6 7 #include "exec_cmd.h"
... ... @@ -12,8 +13,7 @@
12 13  
13 14 int nr_counters;
14 15  
15   -struct perf_event_attr attrs[MAX_COUNTERS];
16   -char *filters[MAX_COUNTERS];
  16 +LIST_HEAD(evsel_list);
17 17  
18 18 struct event_symbol {
19 19 u8 type;
20 20  
... ... @@ -266,10 +266,10 @@
266 266 return name;
267 267 }
268 268  
269   -const char *event_name(int counter)
  269 +const char *event_name(struct perf_evsel *evsel)
270 270 {
271   - u64 config = attrs[counter].config;
272   - int type = attrs[counter].type;
  271 + u64 config = evsel->attr.config;
  272 + int type = evsel->attr.type;
273 273  
274 274 return __event_name(type, config);
275 275 }
... ... @@ -814,9 +814,6 @@
814 814 return -1;
815 815  
816 816 for (;;) {
817   - if (nr_counters == MAX_COUNTERS)
818   - return -1;
819   -
820 817 memset(&attr, 0, sizeof(attr));
821 818 ret = parse_event_symbols(&str, &attr);
822 819 if (ret == EVT_FAILED)
... ... @@ -826,8 +823,13 @@
826 823 return -1;
827 824  
828 825 if (ret != EVT_HANDLED_ALL) {
829   - attrs[nr_counters] = attr;
830   - nr_counters++;
  826 + struct perf_evsel *evsel;
  827 + evsel = perf_evsel__new(attr.type, attr.config,
  828 + nr_counters);
  829 + if (evsel == NULL)
  830 + return -1;
  831 + list_add_tail(&evsel->node, &evsel_list);
  832 + ++nr_counters;
831 833 }
832 834  
833 835 if (*str == 0)
834 836  
835 837  
836 838  
... ... @@ -844,21 +846,22 @@
844 846 int parse_filter(const struct option *opt __used, const char *str,
845 847 int unset __used)
846 848 {
847   - int i = nr_counters - 1;
848   - int len = strlen(str);
  849 + struct perf_evsel *last = NULL;
849 850  
850   - if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
  851 + if (!list_empty(&evsel_list))
  852 + last = list_entry(evsel_list.prev, struct perf_evsel, node);
  853 +
  854 + if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
851 855 fprintf(stderr,
852 856 "-F option should follow a -e tracepoint option\n");
853 857 return -1;
854 858 }
855 859  
856   - filters[i] = malloc(len + 1);
857   - if (!filters[i]) {
  860 + last->filter = strdup(str);
  861 + if (last->filter == NULL) {
858 862 fprintf(stderr, "not enough memory to hold filter string\n");
859 863 return -1;
860 864 }
861   - strcpy(filters[i], str);
862 865  
863 866 return 0;
864 867 }
... ... @@ -966,5 +969,28 @@
966 969 print_tracepoint_events();
967 970  
968 971 exit(129);
  972 +}
  973 +
  974 +int perf_evsel_list__create_default(void)
  975 +{
  976 + struct perf_evsel *evsel = perf_evsel__new(PERF_TYPE_HARDWARE,
  977 + PERF_COUNT_HW_CPU_CYCLES, 0);
  978 + if (evsel == NULL)
  979 + return -ENOMEM;
  980 +
  981 + list_add(&evsel->node, &evsel_list);
  982 + ++nr_counters;
  983 + return 0;
  984 +}
  985 +
  986 +void perf_evsel_list__delete(void)
  987 +{
  988 + struct perf_evsel *pos, *n;
  989 +
  990 + list_for_each_entry_safe(pos, n, &evsel_list, node) {
  991 + list_del_init(&pos->node);
  992 + perf_evsel__delete(pos);
  993 + }
  994 + nr_counters = 0;
969 995 }
tools/perf/util/parse-events.h
... ... @@ -4,6 +4,16 @@
4 4 * Parse symbolic events/counts passed in as options:
5 5 */
6 6  
  7 +#include <linux/perf_event.h>
  8 +
  9 +struct list_head;
  10 +struct perf_evsel;
  11 +
  12 +extern struct list_head evsel_list;
  13 +
  14 +int perf_evsel_list__create_default(void);
  15 +void perf_evsel_list__delete(void);
  16 +
7 17 struct option;
8 18  
9 19 struct tracepoint_path {
10 20  
... ... @@ -13,14 +23,11 @@
13 23 };
14 24  
15 25 extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
16   -extern bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events);
  26 +extern bool have_tracepoints(struct list_head *evsel_list);
17 27  
18 28 extern int nr_counters;
19 29  
20   -extern struct perf_event_attr attrs[MAX_COUNTERS];
21   -extern char *filters[MAX_COUNTERS];
22   -
23   -extern const char *event_name(int ctr);
  30 +const char *event_name(struct perf_evsel *event);
24 31 extern const char *__event_name(int type, u64 config);
25 32  
26 33 extern int parse_events(const struct option *opt, const char *str, int unset);
... ... @@ -32,7 +39,6 @@
32 39  
33 40 extern char debugfs_path[];
34 41 extern int valid_debugfs_mount(const char *debugfs);
35   -
36 42  
37 43 #endif /* __PERF_PARSE_EVENTS_H */
tools/perf/util/session.c
... ... @@ -838,23 +838,6 @@
838 838 return thread;
839 839 }
840 840  
841   -int do_read(int fd, void *buf, size_t size)
842   -{
843   - void *buf_start = buf;
844   -
845   - while (size) {
846   - int ret = read(fd, buf, size);
847   -
848   - if (ret <= 0)
849   - return ret;
850   -
851   - size -= ret;
852   - buf += ret;
853   - }
854   -
855   - return buf - buf_start;
856   -}
857   -
858 841 #define session_done() (*(volatile int *)(&session_done))
859 842 volatile int session_done;
860 843  
... ... @@ -872,7 +855,7 @@
872 855  
873 856 head = 0;
874 857 more:
875   - err = do_read(self->fd, &event, sizeof(struct perf_event_header));
  858 + err = readn(self->fd, &event, sizeof(struct perf_event_header));
876 859 if (err <= 0) {
877 860 if (err == 0)
878 861 goto done;
... ... @@ -892,8 +875,7 @@
892 875 p += sizeof(struct perf_event_header);
893 876  
894 877 if (size - sizeof(struct perf_event_header)) {
895   - err = do_read(self->fd, p,
896   - size - sizeof(struct perf_event_header));
  878 + err = readn(self->fd, p, size - sizeof(struct perf_event_header));
897 879 if (err <= 0) {
898 880 if (err == 0) {
899 881 pr_err("unexpected end of event stream\n");
tools/perf/util/session.h
... ... @@ -109,7 +109,6 @@
109 109  
110 110 int perf_session__create_kernel_maps(struct perf_session *self);
111 111  
112   -int do_read(int fd, void *buf, size_t size);
113 112 void perf_session__update_sample_type(struct perf_session *self);
114 113 void perf_session__set_sample_id_all(struct perf_session *session, bool value);
115 114 void perf_session__set_sample_type(struct perf_session *session, u64 type);
tools/perf/util/thread.c
... ... @@ -16,35 +16,50 @@
16 16 return 1;
17 17 }
18 18  
19   -int find_all_tid(int pid, pid_t ** all_tid)
  19 +struct thread_map *thread_map__new_by_pid(pid_t pid)
20 20 {
  21 + struct thread_map *threads;
21 22 char name[256];
22 23 int items;
23 24 struct dirent **namelist = NULL;
24   - int ret = 0;
25 25 int i;
26 26  
27 27 sprintf(name, "/proc/%d/task", pid);
28 28 items = scandir(name, &namelist, filter, NULL);
29 29 if (items <= 0)
30   - return -ENOENT;
31   - *all_tid = malloc(sizeof(pid_t) * items);
32   - if (!*all_tid) {
33   - ret = -ENOMEM;
34   - goto failure;
  30 + return NULL;
  31 +
  32 + threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
  33 + if (threads != NULL) {
  34 + for (i = 0; i < items; i++)
  35 + threads->map[i] = atoi(namelist[i]->d_name);
  36 + threads->nr = items;
35 37 }
36 38  
37   - for (i = 0; i < items; i++)
38   - (*all_tid)[i] = atoi(namelist[i]->d_name);
39   -
40   - ret = items;
41   -
42   -failure:
43 39 for (i=0; i<items; i++)
44 40 free(namelist[i]);
45 41 free(namelist);
46 42  
47   - return ret;
  43 + return threads;
  44 +}
  45 +
  46 +struct thread_map *thread_map__new_by_tid(pid_t tid)
  47 +{
  48 + struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
  49 +
  50 + if (threads != NULL) {
  51 + threads->map[0] = tid;
  52 + threads->nr = 1;
  53 + }
  54 +
  55 + return threads;
  56 +}
  57 +
  58 +struct thread_map *thread_map__new(pid_t pid, pid_t tid)
  59 +{
  60 + if (pid != -1)
  61 + return thread_map__new_by_pid(pid);
  62 + return thread_map__new_by_tid(tid);
48 63 }
49 64  
50 65 static struct thread *thread__new(pid_t pid)
tools/perf/util/thread.h
... ... @@ -18,11 +18,24 @@
18 18 int comm_len;
19 19 };
20 20  
  21 +struct thread_map {
  22 + int nr;
  23 + int map[];
  24 +};
  25 +
21 26 struct perf_session;
22 27  
23 28 void thread__delete(struct thread *self);
24 29  
25   -int find_all_tid(int pid, pid_t ** all_tid);
  30 +struct thread_map *thread_map__new_by_pid(pid_t pid);
  31 +struct thread_map *thread_map__new_by_tid(pid_t tid);
  32 +struct thread_map *thread_map__new(pid_t pid, pid_t tid);
  33 +
  34 +static inline void thread_map__delete(struct thread_map *threads)
  35 +{
  36 + free(threads);
  37 +}
  38 +
26 39 int thread__set_comm(struct thread *self, const char *comm);
27 40 int thread__comm_len(struct thread *self);
28 41 struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
tools/perf/util/trace-event-info.c
... ... @@ -34,11 +34,13 @@
34 34 #include <ctype.h>
35 35 #include <errno.h>
36 36 #include <stdbool.h>
  37 +#include <linux/list.h>
37 38 #include <linux/kernel.h>
38 39  
39 40 #include "../perf.h"
40 41 #include "trace-event.h"
41 42 #include "debugfs.h"
  43 +#include "evsel.h"
42 44  
43 45 #define VERSION "0.5"
44 46  
45 47  
46 48  
47 49  
... ... @@ -469,16 +471,17 @@
469 471 }
470 472  
471 473 static struct tracepoint_path *
472   -get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
  474 +get_tracepoints_path(struct list_head *pattrs)
473 475 {
474 476 struct tracepoint_path path, *ppath = &path;
475   - int i, nr_tracepoints = 0;
  477 + struct perf_evsel *pos;
  478 + int nr_tracepoints = 0;
476 479  
477   - for (i = 0; i < nb_events; i++) {
478   - if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
  480 + list_for_each_entry(pos, pattrs, node) {
  481 + if (pos->attr.type != PERF_TYPE_TRACEPOINT)
479 482 continue;
480 483 ++nr_tracepoints;
481   - ppath->next = tracepoint_id_to_path(pattrs[i].config);
  484 + ppath->next = tracepoint_id_to_path(pos->attr.config);
482 485 if (!ppath->next)
483 486 die("%s\n", "No memory to alloc tracepoints list");
484 487 ppath = ppath->next;
485 488  
486 489  
487 490  
488 491  
... ... @@ -487,21 +490,21 @@
487 490 return nr_tracepoints > 0 ? path.next : NULL;
488 491 }
489 492  
490   -bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events)
  493 +bool have_tracepoints(struct list_head *pattrs)
491 494 {
492   - int i;
  495 + struct perf_evsel *pos;
493 496  
494   - for (i = 0; i < nb_events; i++)
495   - if (pattrs[i].type == PERF_TYPE_TRACEPOINT)
  497 + list_for_each_entry(pos, pattrs, node)
  498 + if (pos->attr.type == PERF_TYPE_TRACEPOINT)
496 499 return true;
497 500  
498 501 return false;
499 502 }
500 503  
501   -int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
  504 +int read_tracing_data(int fd, struct list_head *pattrs)
502 505 {
503 506 char buf[BUFSIZ];
504   - struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events);
  507 + struct tracepoint_path *tps = get_tracepoints_path(pattrs);
505 508  
506 509 /*
507 510 * What? No tracepoints? No sense writing anything here, bail out.
508 511  
... ... @@ -545,14 +548,13 @@
545 548 return 0;
546 549 }
547 550  
548   -ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs,
549   - int nb_events)
  551 +ssize_t read_tracing_data_size(int fd, struct list_head *pattrs)
550 552 {
551 553 ssize_t size;
552 554 int err = 0;
553 555  
554 556 calc_data_size = 1;
555   - err = read_tracing_data(fd, pattrs, nb_events);
  557 + err = read_tracing_data(fd, pattrs);
556 558 size = calc_data_size - 1;
557 559 calc_data_size = 0;
558 560  
tools/perf/util/trace-event.h
... ... @@ -262,9 +262,8 @@
262 262 void *raw_field_ptr(struct event *event, const char *name, void *data);
263 263 unsigned long long eval_flag(const char *flag);
264 264  
265   -int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
266   -ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs,
267   - int nb_events);
  265 +int read_tracing_data(int fd, struct list_head *pattrs);
  266 +ssize_t read_tracing_data_size(int fd, struct list_head *pattrs);
268 267  
269 268 /* taken from kernel/trace/trace.h */
270 269 enum trace_flag_type {
tools/perf/util/util.c
... ... @@ -114,4 +114,21 @@
114 114  
115 115 return value;
116 116 }
  117 +
  118 +int readn(int fd, void *buf, size_t n)
  119 +{
  120 + void *buf_start = buf;
  121 +
  122 + while (n) {
  123 + int ret = read(fd, buf, n);
  124 +
  125 + if (ret <= 0)
  126 + return ret;
  127 +
  128 + n -= ret;
  129 + buf += ret;
  130 + }
  131 +
  132 + return buf - buf_start;
  133 +}
tools/perf/util/util.h
... ... @@ -265,6 +265,7 @@
265 265 bool strglobmatch(const char *str, const char *pat);
266 266 bool strlazymatch(const char *str, const char *pat);
267 267 unsigned long convert_unit(unsigned long value, char *unit);
  268 +int readn(int fd, void *buf, size_t size);
268 269  
269 270 #define _STR(x) #x
270 271 #define STR(x) _STR(x)
tools/perf/util/xyarray.c
  1 +#include "xyarray.h"
  2 +#include "util.h"
  3 +
  4 +struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size)
  5 +{
  6 + size_t row_size = ylen * entry_size;
  7 + struct xyarray *xy = zalloc(sizeof(*xy) + xlen * row_size);
  8 +
  9 + if (xy != NULL) {
  10 + xy->entry_size = entry_size;
  11 + xy->row_size = row_size;
  12 + }
  13 +
  14 + return xy;
  15 +}
  16 +
  17 +void xyarray__delete(struct xyarray *xy)
  18 +{
  19 + free(xy);
  20 +}
tools/perf/util/xyarray.h
  1 +#ifndef _PERF_XYARRAY_H_
  2 +#define _PERF_XYARRAY_H_ 1
  3 +
  4 +#include <sys/types.h>
  5 +
  6 +struct xyarray {
  7 + size_t row_size;
  8 + size_t entry_size;
  9 + char contents[];
  10 +};
  11 +
  12 +struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size);
  13 +void xyarray__delete(struct xyarray *xy);
  14 +
  15 +static inline void *xyarray__entry(struct xyarray *xy, int x, int y)
  16 +{
  17 + return &xy->contents[x * xy->row_size + y * xy->entry_size];
  18 +}
  19 +
  20 +#endif /* _PERF_XYARRAY_H_ */