aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2014-04-22 14:28:23 -0400
committerIngo Molnar <mingo@kernel.org>2014-04-22 14:28:23 -0400
commita81fef347b32dea2b31275826afe1c93fa0d2d54 (patch)
tree88b5217cdee5126642e6f3db587fab1b1050ba65 /tools/perf
parent4a3dc121d3c370625575247bf714db3f601d83e9 (diff)
parentcff6bb46d477383092f46682a0d12e323e4b84d2 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf into perf/core
Pull perf/core improvements and fixes from Jiri Olsa: Infrastructure changes: * Making some code (cpu node map and report parse callchain callback) global to be usable by upcomming changes (Don Zickus) * Fix pmu object compilation error (Jiri Olsa) Signed-off-by: Jiri Olsa <jolsa@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/builtin-kmem.c78
-rw-r--r--tools/perf/builtin-report.c81
-rw-r--r--tools/perf/util/callchain.c78
-rw-r--r--tools/perf/util/callchain.h1
-rw-r--r--tools/perf/util/cpumap.c160
-rw-r--r--tools/perf/util/cpumap.h35
-rw-r--r--tools/perf/util/pmu.c6
7 files changed, 283 insertions, 156 deletions
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index bd91de07d2a9..f91fa4376f4b 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -14,6 +14,7 @@
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/trace-event.h" 15#include "util/trace-event.h"
16#include "util/data.h" 16#include "util/data.h"
17#include "util/cpumap.h"
17 18
18#include "util/debug.h" 19#include "util/debug.h"
19 20
@@ -31,9 +32,6 @@ static int caller_lines = -1;
31 32
32static bool raw_ip; 33static bool raw_ip;
33 34
34static int *cpunode_map;
35static int max_cpu_num;
36
37struct alloc_stat { 35struct alloc_stat {
38 u64 call_site; 36 u64 call_site;
39 u64 ptr; 37 u64 ptr;
@@ -55,76 +53,6 @@ static struct rb_root root_caller_sorted;
55static unsigned long total_requested, total_allocated; 53static unsigned long total_requested, total_allocated;
56static unsigned long nr_allocs, nr_cross_allocs; 54static unsigned long nr_allocs, nr_cross_allocs;
57 55
58#define PATH_SYS_NODE "/sys/devices/system/node"
59
60static int init_cpunode_map(void)
61{
62 FILE *fp;
63 int i, err = -1;
64
65 fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
66 if (!fp) {
67 max_cpu_num = 4096;
68 return 0;
69 }
70
71 if (fscanf(fp, "%d", &max_cpu_num) < 1) {
72 pr_err("Failed to read 'kernel_max' from sysfs");
73 goto out_close;
74 }
75
76 max_cpu_num++;
77
78 cpunode_map = calloc(max_cpu_num, sizeof(int));
79 if (!cpunode_map) {
80 pr_err("%s: calloc failed\n", __func__);
81 goto out_close;
82 }
83
84 for (i = 0; i < max_cpu_num; i++)
85 cpunode_map[i] = -1;
86
87 err = 0;
88out_close:
89 fclose(fp);
90 return err;
91}
92
93static int setup_cpunode_map(void)
94{
95 struct dirent *dent1, *dent2;
96 DIR *dir1, *dir2;
97 unsigned int cpu, mem;
98 char buf[PATH_MAX];
99
100 if (init_cpunode_map())
101 return -1;
102
103 dir1 = opendir(PATH_SYS_NODE);
104 if (!dir1)
105 return 0;
106
107 while ((dent1 = readdir(dir1)) != NULL) {
108 if (dent1->d_type != DT_DIR ||
109 sscanf(dent1->d_name, "node%u", &mem) < 1)
110 continue;
111
112 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
113 dir2 = opendir(buf);
114 if (!dir2)
115 continue;
116 while ((dent2 = readdir(dir2)) != NULL) {
117 if (dent2->d_type != DT_LNK ||
118 sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
119 continue;
120 cpunode_map[cpu] = mem;
121 }
122 closedir(dir2);
123 }
124 closedir(dir1);
125 return 0;
126}
127
128static int insert_alloc_stat(unsigned long call_site, unsigned long ptr, 56static int insert_alloc_stat(unsigned long call_site, unsigned long ptr,
129 int bytes_req, int bytes_alloc, int cpu) 57 int bytes_req, int bytes_alloc, int cpu)
130{ 58{
@@ -235,7 +163,7 @@ static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel,
235 int ret = perf_evsel__process_alloc_event(evsel, sample); 163 int ret = perf_evsel__process_alloc_event(evsel, sample);
236 164
237 if (!ret) { 165 if (!ret) {
238 int node1 = cpunode_map[sample->cpu], 166 int node1 = cpu__get_node(sample->cpu),
239 node2 = perf_evsel__intval(evsel, sample, "node"); 167 node2 = perf_evsel__intval(evsel, sample, "node");
240 168
241 if (node1 != node2) 169 if (node1 != node2)
@@ -772,7 +700,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
772 if (!strncmp(argv[0], "rec", 3)) { 700 if (!strncmp(argv[0], "rec", 3)) {
773 return __cmd_record(argc, argv); 701 return __cmd_record(argc, argv);
774 } else if (!strcmp(argv[0], "stat")) { 702 } else if (!strcmp(argv[0], "stat")) {
775 if (setup_cpunode_map()) 703 if (cpu__setup_cpunode_map())
776 return -1; 704 return -1;
777 705
778 if (list_empty(&caller_sort)) 706 if (list_empty(&caller_sort))
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index af8cb7a2c9b6..76e2bb6cf571 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -589,11 +589,9 @@ static int __cmd_report(struct report *rep)
589} 589}
590 590
591static int 591static int
592parse_callchain_opt(const struct option *opt, const char *arg, int unset) 592report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
593{ 593{
594 struct report *rep = (struct report *)opt->value; 594 struct report *rep = (struct report *)opt->value;
595 char *tok, *tok2;
596 char *endptr;
597 595
598 /* 596 /*
599 * --no-call-graph 597 * --no-call-graph
@@ -603,80 +601,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
603 return 0; 601 return 0;
604 } 602 }
605 603
606 symbol_conf.use_callchain = true; 604 return parse_callchain_report_opt(arg);
607
608 if (!arg)
609 return 0;
610
611 tok = strtok((char *)arg, ",");
612 if (!tok)
613 return -1;
614
615 /* get the output mode */
616 if (!strncmp(tok, "graph", strlen(arg)))
617 callchain_param.mode = CHAIN_GRAPH_ABS;
618
619 else if (!strncmp(tok, "flat", strlen(arg)))
620 callchain_param.mode = CHAIN_FLAT;
621
622 else if (!strncmp(tok, "fractal", strlen(arg)))
623 callchain_param.mode = CHAIN_GRAPH_REL;
624
625 else if (!strncmp(tok, "none", strlen(arg))) {
626 callchain_param.mode = CHAIN_NONE;
627 symbol_conf.use_callchain = false;
628
629 return 0;
630 }
631
632 else
633 return -1;
634
635 /* get the min percentage */
636 tok = strtok(NULL, ",");
637 if (!tok)
638 goto setup;
639
640 callchain_param.min_percent = strtod(tok, &endptr);
641 if (tok == endptr)
642 return -1;
643
644 /* get the print limit */
645 tok2 = strtok(NULL, ",");
646 if (!tok2)
647 goto setup;
648
649 if (tok2[0] != 'c') {
650 callchain_param.print_limit = strtoul(tok2, &endptr, 0);
651 tok2 = strtok(NULL, ",");
652 if (!tok2)
653 goto setup;
654 }
655
656 /* get the call chain order */
657 if (!strncmp(tok2, "caller", strlen("caller")))
658 callchain_param.order = ORDER_CALLER;
659 else if (!strncmp(tok2, "callee", strlen("callee")))
660 callchain_param.order = ORDER_CALLEE;
661 else
662 return -1;
663
664 /* Get the sort key */
665 tok2 = strtok(NULL, ",");
666 if (!tok2)
667 goto setup;
668 if (!strncmp(tok2, "function", strlen("function")))
669 callchain_param.key = CCKEY_FUNCTION;
670 else if (!strncmp(tok2, "address", strlen("address")))
671 callchain_param.key = CCKEY_ADDRESS;
672 else
673 return -1;
674setup:
675 if (callchain_register_param(&callchain_param) < 0) {
676 pr_err("Can't register callchain params\n");
677 return -1;
678 }
679 return 0;
680} 605}
681 606
682int 607int
@@ -788,7 +713,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
788 "Only display entries with parent-match"), 713 "Only display entries with parent-match"),
789 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 714 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
790 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). " 715 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
791 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt), 716 "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
792 OPT_INTEGER(0, "max-stack", &report.max_stack, 717 OPT_INTEGER(0, "max-stack", &report.max_stack,
793 "Set the maximum stack depth when parsing the callchain, " 718 "Set the maximum stack depth when parsing the callchain, "
794 "anything beyond the specified depth will be ignored. " 719 "anything beyond the specified depth will be ignored. "
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 8d9db454f1a9..9a42382b3921 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -25,6 +25,84 @@
25 25
26__thread struct callchain_cursor callchain_cursor; 26__thread struct callchain_cursor callchain_cursor;
27 27
28int
29parse_callchain_report_opt(const char *arg)
30{
31 char *tok, *tok2;
32 char *endptr;
33
34 symbol_conf.use_callchain = true;
35
36 if (!arg)
37 return 0;
38
39 tok = strtok((char *)arg, ",");
40 if (!tok)
41 return -1;
42
43 /* get the output mode */
44 if (!strncmp(tok, "graph", strlen(arg))) {
45 callchain_param.mode = CHAIN_GRAPH_ABS;
46
47 } else if (!strncmp(tok, "flat", strlen(arg))) {
48 callchain_param.mode = CHAIN_FLAT;
49 } else if (!strncmp(tok, "fractal", strlen(arg))) {
50 callchain_param.mode = CHAIN_GRAPH_REL;
51 } else if (!strncmp(tok, "none", strlen(arg))) {
52 callchain_param.mode = CHAIN_NONE;
53 symbol_conf.use_callchain = false;
54 return 0;
55 } else {
56 return -1;
57 }
58
59 /* get the min percentage */
60 tok = strtok(NULL, ",");
61 if (!tok)
62 goto setup;
63
64 callchain_param.min_percent = strtod(tok, &endptr);
65 if (tok == endptr)
66 return -1;
67
68 /* get the print limit */
69 tok2 = strtok(NULL, ",");
70 if (!tok2)
71 goto setup;
72
73 if (tok2[0] != 'c') {
74 callchain_param.print_limit = strtoul(tok2, &endptr, 0);
75 tok2 = strtok(NULL, ",");
76 if (!tok2)
77 goto setup;
78 }
79
80 /* get the call chain order */
81 if (!strncmp(tok2, "caller", strlen("caller")))
82 callchain_param.order = ORDER_CALLER;
83 else if (!strncmp(tok2, "callee", strlen("callee")))
84 callchain_param.order = ORDER_CALLEE;
85 else
86 return -1;
87
88 /* Get the sort key */
89 tok2 = strtok(NULL, ",");
90 if (!tok2)
91 goto setup;
92 if (!strncmp(tok2, "function", strlen("function")))
93 callchain_param.key = CCKEY_FUNCTION;
94 else if (!strncmp(tok2, "address", strlen("address")))
95 callchain_param.key = CCKEY_ADDRESS;
96 else
97 return -1;
98setup:
99 if (callchain_register_param(&callchain_param) < 0) {
100 pr_err("Can't register callchain params\n");
101 return -1;
102 }
103 return 0;
104}
105
28static void 106static void
29rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 107rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
30 enum chain_mode mode) 108 enum chain_mode mode)
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 8ad97e9b119f..dda4cf8b534c 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -157,4 +157,5 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
157int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); 157int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample);
158 158
159extern const char record_callchain_help[]; 159extern const char record_callchain_help[];
160int parse_callchain_report_opt(const char *arg);
160#endif /* __PERF_CALLCHAIN_H */ 161#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 7fe4994eeb63..c4e55b71010c 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -317,3 +317,163 @@ int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
317{ 317{
318 return cpu_map__build_map(cpus, corep, cpu_map__get_core); 318 return cpu_map__build_map(cpus, corep, cpu_map__get_core);
319} 319}
320
321/* setup simple routines to easily access node numbers given a cpu number */
322static int get_max_num(char *path, int *max)
323{
324 size_t num;
325 char *buf;
326 int err = 0;
327
328 if (filename__read_str(path, &buf, &num))
329 return -1;
330
331 buf[num] = '\0';
332
333 /* start on the right, to find highest node num */
334 while (--num) {
335 if ((buf[num] == ',') || (buf[num] == '-')) {
336 num++;
337 break;
338 }
339 }
340 if (sscanf(&buf[num], "%d", max) < 1) {
341 err = -1;
342 goto out;
343 }
344
345 /* convert from 0-based to 1-based */
346 (*max)++;
347
348out:
349 free(buf);
350 return err;
351}
352
353/* Determine highest possible cpu in the system for sparse allocation */
354static void set_max_cpu_num(void)
355{
356 const char *mnt;
357 char path[PATH_MAX];
358 int ret = -1;
359
360 /* set up default */
361 max_cpu_num = 4096;
362
363 mnt = sysfs__mountpoint();
364 if (!mnt)
365 goto out;
366
367 /* get the highest possible cpu number for a sparse allocation */
368 ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/possible", mnt);
369 if (ret == PATH_MAX) {
370 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
371 goto out;
372 }
373
374 ret = get_max_num(path, &max_cpu_num);
375
376out:
377 if (ret)
378 pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num);
379}
380
381/* Determine highest possible node in the system for sparse allocation */
382static void set_max_node_num(void)
383{
384 const char *mnt;
385 char path[PATH_MAX];
386 int ret = -1;
387
388 /* set up default */
389 max_node_num = 8;
390
391 mnt = sysfs__mountpoint();
392 if (!mnt)
393 goto out;
394
395 /* get the highest possible cpu number for a sparse allocation */
396 ret = snprintf(path, PATH_MAX, "%s/devices/system/node/possible", mnt);
397 if (ret == PATH_MAX) {
398 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
399 goto out;
400 }
401
402 ret = get_max_num(path, &max_node_num);
403
404out:
405 if (ret)
406 pr_err("Failed to read max nodes, using default of %d\n", max_node_num);
407}
408
409static int init_cpunode_map(void)
410{
411 int i;
412
413 set_max_cpu_num();
414 set_max_node_num();
415
416 cpunode_map = calloc(max_cpu_num, sizeof(int));
417 if (!cpunode_map) {
418 pr_err("%s: calloc failed\n", __func__);
419 return -1;
420 }
421
422 for (i = 0; i < max_cpu_num; i++)
423 cpunode_map[i] = -1;
424
425 return 0;
426}
427
428int cpu__setup_cpunode_map(void)
429{
430 struct dirent *dent1, *dent2;
431 DIR *dir1, *dir2;
432 unsigned int cpu, mem;
433 char buf[PATH_MAX];
434 char path[PATH_MAX];
435 const char *mnt;
436 int n;
437
438 /* initialize globals */
439 if (init_cpunode_map())
440 return -1;
441
442 mnt = sysfs__mountpoint();
443 if (!mnt)
444 return 0;
445
446 n = snprintf(path, PATH_MAX, "%s/devices/system/node", mnt);
447 if (n == PATH_MAX) {
448 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
449 return -1;
450 }
451
452 dir1 = opendir(path);
453 if (!dir1)
454 return 0;
455
456 /* walk tree and setup map */
457 while ((dent1 = readdir(dir1)) != NULL) {
458 if (dent1->d_type != DT_DIR || sscanf(dent1->d_name, "node%u", &mem) < 1)
459 continue;
460
461 n = snprintf(buf, PATH_MAX, "%s/%s", path, dent1->d_name);
462 if (n == PATH_MAX) {
463 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
464 continue;
465 }
466
467 dir2 = opendir(buf);
468 if (!dir2)
469 continue;
470 while ((dent2 = readdir(dir2)) != NULL) {
471 if (dent2->d_type != DT_LNK || sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
472 continue;
473 cpunode_map[cpu] = mem;
474 }
475 closedir(dir2);
476 }
477 closedir(dir1);
478 return 0;
479}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index b123bb9d6f55..61a654849002 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -4,6 +4,9 @@
4#include <stdio.h> 4#include <stdio.h>
5#include <stdbool.h> 5#include <stdbool.h>
6 6
7#include "perf.h"
8#include "util/debug.h"
9
7struct cpu_map { 10struct cpu_map {
8 int nr; 11 int nr;
9 int map[]; 12 int map[];
@@ -46,4 +49,36 @@ static inline bool cpu_map__empty(const struct cpu_map *map)
46 return map ? map->map[0] == -1 : true; 49 return map ? map->map[0] == -1 : true;
47} 50}
48 51
52int max_cpu_num;
53int max_node_num;
54int *cpunode_map;
55
56int cpu__setup_cpunode_map(void);
57
58static inline int cpu__max_node(void)
59{
60 if (unlikely(!max_node_num))
61 pr_debug("cpu_map not initialized\n");
62
63 return max_node_num;
64}
65
66static inline int cpu__max_cpu(void)
67{
68 if (unlikely(!max_cpu_num))
69 pr_debug("cpu_map not initialized\n");
70
71 return max_cpu_num;
72}
73
74static inline int cpu__get_node(int cpu)
75{
76 if (unlikely(cpunode_map == NULL)) {
77 pr_debug("cpu_map not initialized\n");
78 return -1;
79 }
80
81 return cpunode_map[cpu];
82}
83
49#endif /* __PERF_CPUMAP_H */ 84#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 00a7dcb2f55c..7a811eb61f75 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -284,17 +284,17 @@ static int pmu_aliases(const char *name, struct list_head *head)
284static int pmu_alias_terms(struct perf_pmu_alias *alias, 284static int pmu_alias_terms(struct perf_pmu_alias *alias,
285 struct list_head *terms) 285 struct list_head *terms)
286{ 286{
287 struct parse_events_term *term, *clone; 287 struct parse_events_term *term, *cloned;
288 LIST_HEAD(list); 288 LIST_HEAD(list);
289 int ret; 289 int ret;
290 290
291 list_for_each_entry(term, &alias->terms, list) { 291 list_for_each_entry(term, &alias->terms, list) {
292 ret = parse_events_term__clone(&clone, term); 292 ret = parse_events_term__clone(&cloned, term);
293 if (ret) { 293 if (ret) {
294 parse_events__free_terms(&list); 294 parse_events__free_terms(&list);
295 return ret; 295 return ret;
296 } 296 }
297 list_add_tail(&clone->list, &list); 297 list_add_tail(&cloned->list, &list);
298 } 298 }
299 list_splice(&list, terms); 299 list_splice(&list, terms);
300 return 0; 300 return 0;