aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2017-10-03 12:30:24 -0400
committerIngo Molnar <mingo@kernel.org>2017-10-03 12:30:24 -0400
commit4b50239a769e78bbe362fc92c3f8bd5415a4a5f5 (patch)
tree951832e213945ede19cd676a04e5218e68afd074 /tools/perf
parenta47ba4d77e1236d214e5116b5631bc4c2d6e6369 (diff)
parentf6a9820d572bd8384d982357cbad214b3a6c04bb (diff)
Merge tag 'perf-core-for-mingo-4.15-20171003' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: - Multithread the synthesizing of PERF_RECORD_ events for pre-existing threads in 'perf top', speeding up that phase, greatly improving the user experience in systems such as Intel's Knights Mill (Kan Liang) - 'perf test' fixes for the perf_event_attr test case (Jiri Olsa, Thomas Richter) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-top.txt3
-rw-r--r--tools/perf/arch/s390/util/Build1
-rw-r--r--tools/perf/arch/s390/util/sym-handling.c29
-rw-r--r--tools/perf/builtin-kvm.c3
-rw-r--r--tools/perf/builtin-record.c2
-rw-r--r--tools/perf/builtin-top.c13
-rw-r--r--tools/perf/builtin-trace.c2
-rw-r--r--tools/perf/tests/attr.c2
-rw-r--r--tools/perf/tests/attr.py6
-rw-r--r--tools/perf/tests/attr/base-record2
-rw-r--r--tools/perf/tests/attr/test-record-group1
-rw-r--r--tools/perf/tests/attr/test-record-group-sampling2
-rw-r--r--tools/perf/tests/attr/test-record-group11
-rw-r--r--tools/perf/tests/attr/test-stat-group2
-rw-r--r--tools/perf/tests/attr/test-stat-group12
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c2
-rw-r--r--tools/perf/util/callchain.c35
-rw-r--r--tools/perf/util/comm.c18
-rw-r--r--tools/perf/util/event.c163
-rw-r--r--tools/perf/util/event.h3
-rw-r--r--tools/perf/util/evsel.c7
-rw-r--r--tools/perf/util/machine.c8
-rw-r--r--tools/perf/util/machine.h9
-rw-r--r--tools/perf/util/symbol-elf.c8
-rw-r--r--tools/perf/util/symbol.h3
-rw-r--r--tools/perf/util/syscalltbl.c2
-rw-r--r--tools/perf/util/thread.c53
-rw-r--r--tools/perf/util/thread.h3
-rw-r--r--tools/perf/util/top.h1
29 files changed, 278 insertions, 108 deletions
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index d864ea6fd367..4353262bc462 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -240,6 +240,9 @@ Default is to monitor all CPUS.
240--force:: 240--force::
241 Don't do ownership validation. 241 Don't do ownership validation.
242 242
243--num-thread-synthesize::
244 The number of threads to run when synthesizing events for existing processes.
245 By default, the number of threads equals to the number of online CPUs.
243 246
244INTERACTIVE PROMPTING KEYS 247INTERACTIVE PROMPTING KEYS
245-------------------------- 248--------------------------
diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build
index bd518b623d7a..5bd7b9260cc0 100644
--- a/tools/perf/arch/s390/util/Build
+++ b/tools/perf/arch/s390/util/Build
@@ -1,5 +1,4 @@
1libperf-y += header.o 1libperf-y += header.o
2libperf-y += sym-handling.o
3libperf-y += kvm-stat.o 2libperf-y += kvm-stat.o
4 3
5libperf-$(CONFIG_DWARF) += dwarf-regs.o 4libperf-$(CONFIG_DWARF) += dwarf-regs.o
diff --git a/tools/perf/arch/s390/util/sym-handling.c b/tools/perf/arch/s390/util/sym-handling.c
deleted file mode 100644
index e103f6e46afe..000000000000
--- a/tools/perf/arch/s390/util/sym-handling.c
+++ /dev/null
@@ -1,29 +0,0 @@
1/*
2 * Architecture specific ELF symbol handling and relocation mapping.
3 *
4 * Copyright 2017 IBM Corp.
5 * Author(s): Thomas Richter <tmricht@linux.vnet.ibm.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License (version 2 only)
9 * as published by the Free Software Foundation.
10 */
11
12#include "symbol.h"
13
14#ifdef HAVE_LIBELF_SUPPORT
15bool elf__needs_adjust_symbols(GElf_Ehdr ehdr)
16{
17 if (ehdr.e_type == ET_EXEC)
18 return false;
19 return ehdr.e_type == ET_REL || ehdr.e_type == ET_DYN;
20}
21
22void arch__adjust_sym_map_offset(GElf_Sym *sym,
23 GElf_Shdr *shdr __maybe_unused,
24 struct map *map)
25{
26 if (map->type == MAP__FUNCTION)
27 sym->st_value += map->start;
28}
29#endif
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index c747a1af49fe..721f4f91291a 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1441,7 +1441,8 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1441 perf_session__set_id_hdr_size(kvm->session); 1441 perf_session__set_id_hdr_size(kvm->session);
1442 ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true); 1442 ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true);
1443 machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target, 1443 machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target,
1444 kvm->evlist->threads, false, kvm->opts.proc_map_timeout); 1444 kvm->evlist->threads, false,
1445 kvm->opts.proc_map_timeout, 1);
1445 err = kvm_live_open_events(kvm); 1446 err = kvm_live_open_events(kvm);
1446 if (err) 1447 if (err)
1447 goto out; 1448 goto out;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 9b379f3a3d99..234fdf4734f6 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -863,7 +863,7 @@ static int record__synthesize(struct record *rec, bool tail)
863 863
864 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, 864 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
865 process_synthesized_event, opts->sample_address, 865 process_synthesized_event, opts->sample_address,
866 opts->proc_map_timeout); 866 opts->proc_map_timeout, 1);
867out: 867out:
868 return err; 868 return err;
869} 869}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ee954bde7e3e..477a8699f0b5 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -958,8 +958,16 @@ static int __cmd_top(struct perf_top *top)
958 if (perf_session__register_idle_thread(top->session) < 0) 958 if (perf_session__register_idle_thread(top->session) < 0)
959 goto out_delete; 959 goto out_delete;
960 960
961 if (top->nr_threads_synthesize > 1)
962 perf_set_multithreaded();
963
961 machine__synthesize_threads(&top->session->machines.host, &opts->target, 964 machine__synthesize_threads(&top->session->machines.host, &opts->target,
962 top->evlist->threads, false, opts->proc_map_timeout); 965 top->evlist->threads, false,
966 opts->proc_map_timeout,
967 top->nr_threads_synthesize);
968
969 if (top->nr_threads_synthesize > 1)
970 perf_set_singlethreaded();
963 971
964 if (perf_hpp_list.socket) { 972 if (perf_hpp_list.socket) {
965 ret = perf_env__read_cpu_topology_map(&perf_env); 973 ret = perf_env__read_cpu_topology_map(&perf_env);
@@ -1112,6 +1120,7 @@ int cmd_top(int argc, const char **argv)
1112 }, 1120 },
1113 .max_stack = sysctl_perf_event_max_stack, 1121 .max_stack = sysctl_perf_event_max_stack,
1114 .sym_pcnt_filter = 5, 1122 .sym_pcnt_filter = 5,
1123 .nr_threads_synthesize = UINT_MAX,
1115 }; 1124 };
1116 struct record_opts *opts = &top.record_opts; 1125 struct record_opts *opts = &top.record_opts;
1117 struct target *target = &opts->target; 1126 struct target *target = &opts->target;
@@ -1221,6 +1230,8 @@ int cmd_top(int argc, const char **argv)
1221 OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy, 1230 OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy,
1222 "Show entries in a hierarchy"), 1231 "Show entries in a hierarchy"),
1223 OPT_BOOLEAN(0, "force", &symbol_conf.force, "don't complain, do it"), 1232 OPT_BOOLEAN(0, "force", &symbol_conf.force, "don't complain, do it"),
1233 OPT_UINTEGER(0, "num-thread-synthesize", &top.nr_threads_synthesize,
1234 "number of thread to run event synthesize"),
1224 OPT_END() 1235 OPT_END()
1225 }; 1236 };
1226 const char * const top_usage[] = { 1237 const char * const top_usage[] = {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 967bd351b58d..afef6fe46c45 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1131,7 +1131,7 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1131 1131
1132 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target, 1132 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1133 evlist->threads, trace__tool_process, false, 1133 evlist->threads, trace__tool_process, false,
1134 trace->opts.proc_map_timeout); 1134 trace->opts.proc_map_timeout, 1);
1135 if (err) 1135 if (err)
1136 symbol__exit(); 1136 symbol__exit();
1137 1137
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index c9aafed7da15..25ede4472465 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -166,7 +166,7 @@ static int run_dir(const char *d, const char *perf)
166 snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s", 166 snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s",
167 d, d, perf, vcnt, v); 167 d, d, perf, vcnt, v);
168 168
169 return system(cmd); 169 return system(cmd) ? TEST_FAIL : TEST_OK;
170} 170}
171 171
172int test__attr(struct test *test __maybe_unused, int subtest __maybe_unused) 172int test__attr(struct test *test __maybe_unused, int subtest __maybe_unused)
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py
index 6bb50e82a3e3..a13cd780148e 100644
--- a/tools/perf/tests/attr.py
+++ b/tools/perf/tests/attr.py
@@ -237,6 +237,7 @@ class Test(object):
237 # events in result. Fail if there's not any. 237 # events in result. Fail if there's not any.
238 for exp_name, exp_event in expect.items(): 238 for exp_name, exp_event in expect.items():
239 exp_list = [] 239 exp_list = []
240 res_event = {}
240 log.debug(" matching [%s]" % exp_name) 241 log.debug(" matching [%s]" % exp_name)
241 for res_name, res_event in result.items(): 242 for res_name, res_event in result.items():
242 log.debug(" to [%s]" % res_name) 243 log.debug(" to [%s]" % res_name)
@@ -253,7 +254,10 @@ class Test(object):
253 if exp_event.optional(): 254 if exp_event.optional():
254 log.debug(" %s does not match, but is optional" % exp_name) 255 log.debug(" %s does not match, but is optional" % exp_name)
255 else: 256 else:
256 exp_event.diff(res_event) 257 if not res_event:
258 log.debug(" res_event is empty");
259 else:
260 exp_event.diff(res_event)
257 raise Fail(self, 'match failure'); 261 raise Fail(self, 'match failure');
258 262
259 match[exp_name] = exp_list 263 match[exp_name] = exp_list
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record
index 31e0b1da830b..37940665f736 100644
--- a/tools/perf/tests/attr/base-record
+++ b/tools/perf/tests/attr/base-record
@@ -23,7 +23,7 @@ comm=1
23freq=1 23freq=1
24inherit_stat=0 24inherit_stat=0
25enable_on_exec=1 25enable_on_exec=1
26task=0 26task=1
27watermark=0 27watermark=0
28precise_ip=0|1|2|3 28precise_ip=0|1|2|3
29mmap_data=0 29mmap_data=0
diff --git a/tools/perf/tests/attr/test-record-group b/tools/perf/tests/attr/test-record-group
index 6e7961f6f7a5..618ba1c17474 100644
--- a/tools/perf/tests/attr/test-record-group
+++ b/tools/perf/tests/attr/test-record-group
@@ -17,5 +17,6 @@ sample_type=327
17read_format=4 17read_format=4
18mmap=0 18mmap=0
19comm=0 19comm=0
20task=0
20enable_on_exec=0 21enable_on_exec=0
21disabled=0 22disabled=0
diff --git a/tools/perf/tests/attr/test-record-group-sampling b/tools/perf/tests/attr/test-record-group-sampling
index ef59afd6d635..f906b793196f 100644
--- a/tools/perf/tests/attr/test-record-group-sampling
+++ b/tools/perf/tests/attr/test-record-group-sampling
@@ -23,7 +23,7 @@ sample_type=343
23 23
24# PERF_FORMAT_ID | PERF_FORMAT_GROUP 24# PERF_FORMAT_ID | PERF_FORMAT_GROUP
25read_format=12 25read_format=12
26 26task=0
27mmap=0 27mmap=0
28comm=0 28comm=0
29enable_on_exec=0 29enable_on_exec=0
diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1
index 87a222d014d8..48e8bd12fe46 100644
--- a/tools/perf/tests/attr/test-record-group1
+++ b/tools/perf/tests/attr/test-record-group1
@@ -18,5 +18,6 @@ sample_type=327
18read_format=4 18read_format=4
19mmap=0 19mmap=0
20comm=0 20comm=0
21task=0
21enable_on_exec=0 22enable_on_exec=0
22disabled=0 23disabled=0
diff --git a/tools/perf/tests/attr/test-stat-group b/tools/perf/tests/attr/test-stat-group
index fdc1596a8862..e15d6946e9b3 100644
--- a/tools/perf/tests/attr/test-stat-group
+++ b/tools/perf/tests/attr/test-stat-group
@@ -6,6 +6,7 @@ ret = 1
6[event-1:base-stat] 6[event-1:base-stat]
7fd=1 7fd=1
8group_fd=-1 8group_fd=-1
9read_format=3|15
9 10
10[event-2:base-stat] 11[event-2:base-stat]
11fd=2 12fd=2
@@ -13,3 +14,4 @@ group_fd=1
13config=1 14config=1
14disabled=0 15disabled=0
15enable_on_exec=0 16enable_on_exec=0
17read_format=3|15
diff --git a/tools/perf/tests/attr/test-stat-group1 b/tools/perf/tests/attr/test-stat-group1
index 2a1f86e4a904..1746751123dc 100644
--- a/tools/perf/tests/attr/test-stat-group1
+++ b/tools/perf/tests/attr/test-stat-group1
@@ -6,6 +6,7 @@ ret = 1
6[event-1:base-stat] 6[event-1:base-stat]
7fd=1 7fd=1
8group_fd=-1 8group_fd=-1
9read_format=3|15
9 10
10[event-2:base-stat] 11[event-2:base-stat]
11fd=2 12fd=2
@@ -13,3 +14,4 @@ group_fd=1
13config=1 14config=1
14disabled=0 15disabled=0
15enable_on_exec=0 16enable_on_exec=0
17read_format=3|15
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c
index f94a4196e7c9..2a0068afe3bf 100644
--- a/tools/perf/tests/mmap-thread-lookup.c
+++ b/tools/perf/tests/mmap-thread-lookup.c
@@ -131,7 +131,7 @@ static int synth_all(struct machine *machine)
131{ 131{
132 return perf_event__synthesize_threads(NULL, 132 return perf_event__synthesize_threads(NULL,
133 perf_event__process, 133 perf_event__process,
134 machine, 0, 500); 134 machine, 0, 500, 1);
135} 135}
136 136
137static int synth_process(struct machine *machine) 137static int synth_process(struct machine *machine)
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 510b513e0f01..be09d77cade0 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -65,8 +65,6 @@ static int parse_callchain_mode(const char *value)
65 callchain_param.mode = CHAIN_FOLDED; 65 callchain_param.mode = CHAIN_FOLDED;
66 return 0; 66 return 0;
67 } 67 }
68
69 pr_err("Invalid callchain mode: %s\n", value);
70 return -1; 68 return -1;
71} 69}
72 70
@@ -82,8 +80,6 @@ static int parse_callchain_order(const char *value)
82 callchain_param.order_set = true; 80 callchain_param.order_set = true;
83 return 0; 81 return 0;
84 } 82 }
85
86 pr_err("Invalid callchain order: %s\n", value);
87 return -1; 83 return -1;
88} 84}
89 85
@@ -105,8 +101,6 @@ static int parse_callchain_sort_key(const char *value)
105 callchain_param.branch_callstack = 1; 101 callchain_param.branch_callstack = 1;
106 return 0; 102 return 0;
107 } 103 }
108
109 pr_err("Invalid callchain sort key: %s\n", value);
110 return -1; 104 return -1;
111} 105}
112 106
@@ -124,8 +118,6 @@ static int parse_callchain_value(const char *value)
124 callchain_param.value = CCVAL_COUNT; 118 callchain_param.value = CCVAL_COUNT;
125 return 0; 119 return 0;
126 } 120 }
127
128 pr_err("Invalid callchain config key: %s\n", value);
129 return -1; 121 return -1;
130} 122}
131 123
@@ -319,12 +311,27 @@ int perf_callchain_config(const char *var, const char *value)
319 311
320 return ret; 312 return ret;
321 } 313 }
322 if (!strcmp(var, "print-type")) 314 if (!strcmp(var, "print-type")){
323 return parse_callchain_mode(value); 315 int ret;
324 if (!strcmp(var, "order")) 316 ret = parse_callchain_mode(value);
325 return parse_callchain_order(value); 317 if (ret == -1)
326 if (!strcmp(var, "sort-key")) 318 pr_err("Invalid callchain mode: %s\n", value);
327 return parse_callchain_sort_key(value); 319 return ret;
320 }
321 if (!strcmp(var, "order")){
322 int ret;
323 ret = parse_callchain_order(value);
324 if (ret == -1)
325 pr_err("Invalid callchain order: %s\n", value);
326 return ret;
327 }
328 if (!strcmp(var, "sort-key")){
329 int ret;
330 ret = parse_callchain_sort_key(value);
331 if (ret == -1)
332 pr_err("Invalid callchain sort key: %s\n", value);
333 return ret;
334 }
328 if (!strcmp(var, "threshold")) { 335 if (!strcmp(var, "threshold")) {
329 callchain_param.min_percent = strtod(value, &endptr); 336 callchain_param.min_percent = strtod(value, &endptr);
330 if (value == endptr) { 337 if (value == endptr) {
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
index 7bc981b6bf29..756a9c14efbb 100644
--- a/tools/perf/util/comm.c
+++ b/tools/perf/util/comm.c
@@ -5,6 +5,7 @@
5#include <stdio.h> 5#include <stdio.h>
6#include <string.h> 6#include <string.h>
7#include <linux/refcount.h> 7#include <linux/refcount.h>
8#include "rwsem.h"
8 9
9struct comm_str { 10struct comm_str {
10 char *str; 11 char *str;
@@ -14,6 +15,7 @@ struct comm_str {
14 15
15/* Should perhaps be moved to struct machine */ 16/* Should perhaps be moved to struct machine */
16static struct rb_root comm_str_root; 17static struct rb_root comm_str_root;
18static struct rw_semaphore comm_str_lock = {.lock = PTHREAD_RWLOCK_INITIALIZER,};
17 19
18static struct comm_str *comm_str__get(struct comm_str *cs) 20static struct comm_str *comm_str__get(struct comm_str *cs)
19{ 21{
@@ -25,7 +27,9 @@ static struct comm_str *comm_str__get(struct comm_str *cs)
25static void comm_str__put(struct comm_str *cs) 27static void comm_str__put(struct comm_str *cs)
26{ 28{
27 if (cs && refcount_dec_and_test(&cs->refcnt)) { 29 if (cs && refcount_dec_and_test(&cs->refcnt)) {
30 down_write(&comm_str_lock);
28 rb_erase(&cs->rb_node, &comm_str_root); 31 rb_erase(&cs->rb_node, &comm_str_root);
32 up_write(&comm_str_lock);
29 zfree(&cs->str); 33 zfree(&cs->str);
30 free(cs); 34 free(cs);
31 } 35 }
@@ -50,7 +54,8 @@ static struct comm_str *comm_str__alloc(const char *str)
50 return cs; 54 return cs;
51} 55}
52 56
53static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root) 57static
58struct comm_str *__comm_str__findnew(const char *str, struct rb_root *root)
54{ 59{
55 struct rb_node **p = &root->rb_node; 60 struct rb_node **p = &root->rb_node;
56 struct rb_node *parent = NULL; 61 struct rb_node *parent = NULL;
@@ -81,6 +86,17 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
81 return new; 86 return new;
82} 87}
83 88
89static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
90{
91 struct comm_str *cs;
92
93 down_write(&comm_str_lock);
94 cs = __comm_str__findnew(str, root);
95 up_write(&comm_str_lock);
96
97 return cs;
98}
99
84struct comm *comm__new(const char *str, u64 timestamp, bool exec) 100struct comm *comm__new(const char *str, u64 timestamp, bool exec)
85{ 101{
86 struct comm *comm = zalloc(sizeof(*comm)); 102 struct comm *comm = zalloc(sizeof(*comm));
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 10366b87d0b5..47eff4767edb 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -678,23 +678,21 @@ out:
678 return err; 678 return err;
679} 679}
680 680
681int perf_event__synthesize_threads(struct perf_tool *tool, 681static int __perf_event__synthesize_threads(struct perf_tool *tool,
682 perf_event__handler_t process, 682 perf_event__handler_t process,
683 struct machine *machine, 683 struct machine *machine,
684 bool mmap_data, 684 bool mmap_data,
685 unsigned int proc_map_timeout) 685 unsigned int proc_map_timeout,
686 struct dirent **dirent,
687 int start,
688 int num)
686{ 689{
687 union perf_event *comm_event, *mmap_event, *fork_event; 690 union perf_event *comm_event, *mmap_event, *fork_event;
688 union perf_event *namespaces_event; 691 union perf_event *namespaces_event;
689 char proc_path[PATH_MAX];
690 struct dirent **dirent;
691 int err = -1; 692 int err = -1;
692 char *end; 693 char *end;
693 pid_t pid; 694 pid_t pid;
694 int n, i; 695 int i;
695
696 if (machine__is_default_guest(machine))
697 return 0;
698 696
699 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 697 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
700 if (comm_event == NULL) 698 if (comm_event == NULL)
@@ -714,34 +712,25 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
714 if (namespaces_event == NULL) 712 if (namespaces_event == NULL)
715 goto out_free_fork; 713 goto out_free_fork;
716 714
717 snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); 715 for (i = start; i < start + num; i++) {
718 n = scandir(proc_path, &dirent, 0, alphasort);
719
720 if (n < 0)
721 goto out_free_namespaces;
722
723 for (i = 0; i < n; i++) {
724 if (!isdigit(dirent[i]->d_name[0])) 716 if (!isdigit(dirent[i]->d_name[0]))
725 continue; 717 continue;
726 718
727 pid = (pid_t)strtol(dirent[i]->d_name, &end, 10); 719 pid = (pid_t)strtol(dirent[i]->d_name, &end, 10);
728 /* only interested in proper numerical dirents */ 720 /* only interested in proper numerical dirents */
729 if (!*end) { 721 if (*end)
730 /* 722 continue;
731 * We may race with exiting thread, so don't stop just because 723 /*
732 * one thread couldn't be synthesized. 724 * We may race with exiting thread, so don't stop just because
733 */ 725 * one thread couldn't be synthesized.
734 __event__synthesize_thread(comm_event, mmap_event, fork_event, 726 */
735 namespaces_event, pid, 1, process, 727 __event__synthesize_thread(comm_event, mmap_event, fork_event,
736 tool, machine, mmap_data, 728 namespaces_event, pid, 1, process,
737 proc_map_timeout); 729 tool, machine, mmap_data,
738 } 730 proc_map_timeout);
739 free(dirent[i]);
740 } 731 }
741 free(dirent);
742 err = 0; 732 err = 0;
743 733
744out_free_namespaces:
745 free(namespaces_event); 734 free(namespaces_event);
746out_free_fork: 735out_free_fork:
747 free(fork_event); 736 free(fork_event);
@@ -753,6 +742,118 @@ out:
753 return err; 742 return err;
754} 743}
755 744
745struct synthesize_threads_arg {
746 struct perf_tool *tool;
747 perf_event__handler_t process;
748 struct machine *machine;
749 bool mmap_data;
750 unsigned int proc_map_timeout;
751 struct dirent **dirent;
752 int num;
753 int start;
754};
755
756static void *synthesize_threads_worker(void *arg)
757{
758 struct synthesize_threads_arg *args = arg;
759
760 __perf_event__synthesize_threads(args->tool, args->process,
761 args->machine, args->mmap_data,
762 args->proc_map_timeout, args->dirent,
763 args->start, args->num);
764 return NULL;
765}
766
767int perf_event__synthesize_threads(struct perf_tool *tool,
768 perf_event__handler_t process,
769 struct machine *machine,
770 bool mmap_data,
771 unsigned int proc_map_timeout,
772 unsigned int nr_threads_synthesize)
773{
774 struct synthesize_threads_arg *args = NULL;
775 pthread_t *synthesize_threads = NULL;
776 char proc_path[PATH_MAX];
777 struct dirent **dirent;
778 int num_per_thread;
779 int m, n, i, j;
780 int thread_nr;
781 int base = 0;
782 int err = -1;
783
784
785 if (machine__is_default_guest(machine))
786 return 0;
787
788 snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
789 n = scandir(proc_path, &dirent, 0, alphasort);
790 if (n < 0)
791 return err;
792
793 if (nr_threads_synthesize == UINT_MAX)
794 thread_nr = sysconf(_SC_NPROCESSORS_ONLN);
795 else
796 thread_nr = nr_threads_synthesize;
797
798 if (thread_nr <= 1) {
799 err = __perf_event__synthesize_threads(tool, process,
800 machine, mmap_data,
801 proc_map_timeout,
802 dirent, base, n);
803 goto free_dirent;
804 }
805 if (thread_nr > n)
806 thread_nr = n;
807
808 synthesize_threads = calloc(sizeof(pthread_t), thread_nr);
809 if (synthesize_threads == NULL)
810 goto free_dirent;
811
812 args = calloc(sizeof(*args), thread_nr);
813 if (args == NULL)
814 goto free_threads;
815
816 num_per_thread = n / thread_nr;
817 m = n % thread_nr;
818 for (i = 0; i < thread_nr; i++) {
819 args[i].tool = tool;
820 args[i].process = process;
821 args[i].machine = machine;
822 args[i].mmap_data = mmap_data;
823 args[i].proc_map_timeout = proc_map_timeout;
824 args[i].dirent = dirent;
825 }
826 for (i = 0; i < m; i++) {
827 args[i].num = num_per_thread + 1;
828 args[i].start = i * args[i].num;
829 }
830 if (i != 0)
831 base = args[i-1].start + args[i-1].num;
832 for (j = i; j < thread_nr; j++) {
833 args[j].num = num_per_thread;
834 args[j].start = base + (j - i) * args[i].num;
835 }
836
837 for (i = 0; i < thread_nr; i++) {
838 if (pthread_create(&synthesize_threads[i], NULL,
839 synthesize_threads_worker, &args[i]))
840 goto out_join;
841 }
842 err = 0;
843out_join:
844 for (i = 0; i < thread_nr; i++)
845 pthread_join(synthesize_threads[i], NULL);
846 free(args);
847free_threads:
848 free(synthesize_threads);
849free_dirent:
850 for (i = 0; i < n; i++)
851 free(dirent[i]);
852 free(dirent);
853
854 return err;
855}
856
756struct process_symbol_args { 857struct process_symbol_args {
757 const char *name; 858 const char *name;
758 u64 start; 859 u64 start;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index ee7bcc898d35..d6cbb0a0d919 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -680,7 +680,8 @@ int perf_event__synthesize_cpu_map(struct perf_tool *tool,
680int perf_event__synthesize_threads(struct perf_tool *tool, 680int perf_event__synthesize_threads(struct perf_tool *tool,
681 perf_event__handler_t process, 681 perf_event__handler_t process,
682 struct machine *machine, bool mmap_data, 682 struct machine *machine, bool mmap_data,
683 unsigned int proc_map_timeout); 683 unsigned int proc_map_timeout,
684 unsigned int nr_threads_synthesize);
684int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 685int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
685 perf_event__handler_t process, 686 perf_event__handler_t process,
686 struct machine *machine); 687 struct machine *machine);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 7389746c0dc4..f894893c203d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -271,12 +271,17 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
271 return evsel; 271 return evsel;
272} 272}
273 273
274static bool perf_event_can_profile_kernel(void)
275{
276 return geteuid() == 0 || perf_event_paranoid() == -1;
277}
278
274struct perf_evsel *perf_evsel__new_cycles(bool precise) 279struct perf_evsel *perf_evsel__new_cycles(bool precise)
275{ 280{
276 struct perf_event_attr attr = { 281 struct perf_event_attr attr = {
277 .type = PERF_TYPE_HARDWARE, 282 .type = PERF_TYPE_HARDWARE,
278 .config = PERF_COUNT_HW_CPU_CYCLES, 283 .config = PERF_COUNT_HW_CPU_CYCLES,
279 .exclude_kernel = geteuid() != 0, 284 .exclude_kernel = !perf_event_can_profile_kernel(),
280 }; 285 };
281 struct perf_evsel *evsel; 286 struct perf_evsel *evsel;
282 287
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 585b4a3d64a4..7c3aa479201a 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -2218,12 +2218,16 @@ int machines__for_each_thread(struct machines *machines,
2218int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 2218int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
2219 struct target *target, struct thread_map *threads, 2219 struct target *target, struct thread_map *threads,
2220 perf_event__handler_t process, bool data_mmap, 2220 perf_event__handler_t process, bool data_mmap,
2221 unsigned int proc_map_timeout) 2221 unsigned int proc_map_timeout,
2222 unsigned int nr_threads_synthesize)
2222{ 2223{
2223 if (target__has_task(target)) 2224 if (target__has_task(target))
2224 return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap, proc_map_timeout); 2225 return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap, proc_map_timeout);
2225 else if (target__has_cpu(target)) 2226 else if (target__has_cpu(target))
2226 return perf_event__synthesize_threads(tool, process, machine, data_mmap, proc_map_timeout); 2227 return perf_event__synthesize_threads(tool, process,
2228 machine, data_mmap,
2229 proc_map_timeout,
2230 nr_threads_synthesize);
2227 /* command specified */ 2231 /* command specified */
2228 return 0; 2232 return 0;
2229} 2233}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index b1cd516f2025..c6a299ea506c 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -257,15 +257,18 @@ int machines__for_each_thread(struct machines *machines,
257int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 257int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
258 struct target *target, struct thread_map *threads, 258 struct target *target, struct thread_map *threads,
259 perf_event__handler_t process, bool data_mmap, 259 perf_event__handler_t process, bool data_mmap,
260 unsigned int proc_map_timeout); 260 unsigned int proc_map_timeout,
261 unsigned int nr_threads_synthesize);
261static inline 262static inline
262int machine__synthesize_threads(struct machine *machine, struct target *target, 263int machine__synthesize_threads(struct machine *machine, struct target *target,
263 struct thread_map *threads, bool data_mmap, 264 struct thread_map *threads, bool data_mmap,
264 unsigned int proc_map_timeout) 265 unsigned int proc_map_timeout,
266 unsigned int nr_threads_synthesize)
265{ 267{
266 return __machine__synthesize_threads(machine, NULL, target, threads, 268 return __machine__synthesize_threads(machine, NULL, target, threads,
267 perf_event__process, data_mmap, 269 perf_event__process, data_mmap,
268 proc_map_timeout); 270 proc_map_timeout,
271 nr_threads_synthesize);
269} 272}
270 273
271pid_t machine__get_current_tid(struct machine *machine, int cpu); 274pid_t machine__get_current_tid(struct machine *machine, int cpu);
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 5c39f420111e..9cf781f0d8a2 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -810,12 +810,6 @@ static u64 ref_reloc(struct kmap *kmap)
810void __weak arch__sym_update(struct symbol *s __maybe_unused, 810void __weak arch__sym_update(struct symbol *s __maybe_unused,
811 GElf_Sym *sym __maybe_unused) { } 811 GElf_Sym *sym __maybe_unused) { }
812 812
813void __weak arch__adjust_sym_map_offset(GElf_Sym *sym, GElf_Shdr *shdr,
814 struct map *map __maybe_unused)
815{
816 sym->st_value -= shdr->sh_addr - shdr->sh_offset;
817}
818
819int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 813int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
820 struct symsrc *runtime_ss, int kmodule) 814 struct symsrc *runtime_ss, int kmodule)
821{ 815{
@@ -996,7 +990,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
996 990
997 /* Adjust symbol to map to file offset */ 991 /* Adjust symbol to map to file offset */
998 if (adjust_kernel_syms) 992 if (adjust_kernel_syms)
999 arch__adjust_sym_map_offset(&sym, &shdr, map); 993 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1000 994
1001 if (strcmp(section_name, 995 if (strcmp(section_name,
1002 (curr_dso->short_name + 996 (curr_dso->short_name +
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 2bd6a1f01a1c..aad99e7e179b 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -344,9 +344,6 @@ int setup_intlist(struct intlist **list, const char *list_str,
344#ifdef HAVE_LIBELF_SUPPORT 344#ifdef HAVE_LIBELF_SUPPORT
345bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); 345bool elf__needs_adjust_symbols(GElf_Ehdr ehdr);
346void arch__sym_update(struct symbol *s, GElf_Sym *sym); 346void arch__sym_update(struct symbol *s, GElf_Sym *sym);
347void arch__adjust_sym_map_offset(GElf_Sym *sym,
348 GElf_Shdr *shdr __maybe_unused,
349 struct map *map __maybe_unused);
350#endif 347#endif
351 348
352#define SYMBOL_A 0 349#define SYMBOL_A 0
diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c
index 19e5db90394c..6eea7cff3d4e 100644
--- a/tools/perf/util/syscalltbl.c
+++ b/tools/perf/util/syscalltbl.c
@@ -15,9 +15,9 @@
15 15
16#include "syscalltbl.h" 16#include "syscalltbl.h"
17#include <stdlib.h> 17#include <stdlib.h>
18#include <linux/compiler.h>
18 19
19#ifdef HAVE_SYSCALL_TABLE 20#ifdef HAVE_SYSCALL_TABLE
20#include <linux/compiler.h>
21#include <string.h> 21#include <string.h>
22#include "string2.h" 22#include "string2.h"
23#include "util.h" 23#include "util.h"
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index c09bdb509d82..bf73117b4822 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -45,6 +45,8 @@ struct thread *thread__new(pid_t pid, pid_t tid)
45 thread->cpu = -1; 45 thread->cpu = -1;
46 INIT_LIST_HEAD(&thread->namespaces_list); 46 INIT_LIST_HEAD(&thread->namespaces_list);
47 INIT_LIST_HEAD(&thread->comm_list); 47 INIT_LIST_HEAD(&thread->comm_list);
48 init_rwsem(&thread->namespaces_lock);
49 init_rwsem(&thread->comm_lock);
48 50
49 comm_str = malloc(32); 51 comm_str = malloc(32);
50 if (!comm_str) 52 if (!comm_str)
@@ -83,18 +85,26 @@ void thread__delete(struct thread *thread)
83 map_groups__put(thread->mg); 85 map_groups__put(thread->mg);
84 thread->mg = NULL; 86 thread->mg = NULL;
85 } 87 }
88 down_write(&thread->namespaces_lock);
86 list_for_each_entry_safe(namespaces, tmp_namespaces, 89 list_for_each_entry_safe(namespaces, tmp_namespaces,
87 &thread->namespaces_list, list) { 90 &thread->namespaces_list, list) {
88 list_del(&namespaces->list); 91 list_del(&namespaces->list);
89 namespaces__free(namespaces); 92 namespaces__free(namespaces);
90 } 93 }
94 up_write(&thread->namespaces_lock);
95
96 down_write(&thread->comm_lock);
91 list_for_each_entry_safe(comm, tmp_comm, &thread->comm_list, list) { 97 list_for_each_entry_safe(comm, tmp_comm, &thread->comm_list, list) {
92 list_del(&comm->list); 98 list_del(&comm->list);
93 comm__free(comm); 99 comm__free(comm);
94 } 100 }
101 up_write(&thread->comm_lock);
102
95 unwind__finish_access(thread); 103 unwind__finish_access(thread);
96 nsinfo__zput(thread->nsinfo); 104 nsinfo__zput(thread->nsinfo);
97 105
106 exit_rwsem(&thread->namespaces_lock);
107 exit_rwsem(&thread->comm_lock);
98 free(thread); 108 free(thread);
99} 109}
100 110
@@ -125,8 +135,8 @@ struct namespaces *thread__namespaces(const struct thread *thread)
125 return list_first_entry(&thread->namespaces_list, struct namespaces, list); 135 return list_first_entry(&thread->namespaces_list, struct namespaces, list);
126} 136}
127 137
128int thread__set_namespaces(struct thread *thread, u64 timestamp, 138static int __thread__set_namespaces(struct thread *thread, u64 timestamp,
129 struct namespaces_event *event) 139 struct namespaces_event *event)
130{ 140{
131 struct namespaces *new, *curr = thread__namespaces(thread); 141 struct namespaces *new, *curr = thread__namespaces(thread);
132 142
@@ -149,6 +159,17 @@ int thread__set_namespaces(struct thread *thread, u64 timestamp,
149 return 0; 159 return 0;
150} 160}
151 161
162int thread__set_namespaces(struct thread *thread, u64 timestamp,
163 struct namespaces_event *event)
164{
165 int ret;
166
167 down_write(&thread->namespaces_lock);
168 ret = __thread__set_namespaces(thread, timestamp, event);
169 up_write(&thread->namespaces_lock);
170 return ret;
171}
172
152struct comm *thread__comm(const struct thread *thread) 173struct comm *thread__comm(const struct thread *thread)
153{ 174{
154 if (list_empty(&thread->comm_list)) 175 if (list_empty(&thread->comm_list))
@@ -170,8 +191,8 @@ struct comm *thread__exec_comm(const struct thread *thread)
170 return last; 191 return last;
171} 192}
172 193
173int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp, 194static int ____thread__set_comm(struct thread *thread, const char *str,
174 bool exec) 195 u64 timestamp, bool exec)
175{ 196{
176 struct comm *new, *curr = thread__comm(thread); 197 struct comm *new, *curr = thread__comm(thread);
177 198
@@ -195,6 +216,17 @@ int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
195 return 0; 216 return 0;
196} 217}
197 218
219int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
220 bool exec)
221{
222 int ret;
223
224 down_write(&thread->comm_lock);
225 ret = ____thread__set_comm(thread, str, timestamp, exec);
226 up_write(&thread->comm_lock);
227 return ret;
228}
229
198int thread__set_comm_from_proc(struct thread *thread) 230int thread__set_comm_from_proc(struct thread *thread)
199{ 231{
200 char path[64]; 232 char path[64];
@@ -212,7 +244,7 @@ int thread__set_comm_from_proc(struct thread *thread)
212 return err; 244 return err;
213} 245}
214 246
215const char *thread__comm_str(const struct thread *thread) 247static const char *__thread__comm_str(const struct thread *thread)
216{ 248{
217 const struct comm *comm = thread__comm(thread); 249 const struct comm *comm = thread__comm(thread);
218 250
@@ -222,6 +254,17 @@ const char *thread__comm_str(const struct thread *thread)
222 return comm__str(comm); 254 return comm__str(comm);
223} 255}
224 256
257const char *thread__comm_str(const struct thread *thread)
258{
259 const char *str;
260
261 down_read((struct rw_semaphore *)&thread->comm_lock);
262 str = __thread__comm_str(thread);
263 up_read((struct rw_semaphore *)&thread->comm_lock);
264
265 return str;
266}
267
225/* CHECKME: it should probably better return the max comm len from its comm list */ 268/* CHECKME: it should probably better return the max comm len from its comm list */
226int thread__comm_len(struct thread *thread) 269int thread__comm_len(struct thread *thread)
227{ 270{
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index cb1a5dd5c2b9..10555d6a0b86 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -9,6 +9,7 @@
9#include "symbol.h" 9#include "symbol.h"
10#include <strlist.h> 10#include <strlist.h>
11#include <intlist.h> 11#include <intlist.h>
12#include "rwsem.h"
12 13
13struct thread_stack; 14struct thread_stack;
14struct unwind_libunwind_ops; 15struct unwind_libunwind_ops;
@@ -29,7 +30,9 @@ struct thread {
29 int comm_len; 30 int comm_len;
30 bool dead; /* if set thread has exited */ 31 bool dead; /* if set thread has exited */
31 struct list_head namespaces_list; 32 struct list_head namespaces_list;
33 struct rw_semaphore namespaces_lock;
32 struct list_head comm_list; 34 struct list_head comm_list;
35 struct rw_semaphore comm_lock;
33 u64 db_id; 36 u64 db_id;
34 37
35 void *priv; 38 void *priv;
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 9bdfb78a9a35..f4296e1e3bb8 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -37,6 +37,7 @@ struct perf_top {
37 int sym_pcnt_filter; 37 int sym_pcnt_filter;
38 const char *sym_filter; 38 const char *sym_filter;
39 float min_percent; 39 float min_percent;
40 unsigned int nr_threads_synthesize;
40}; 41};
41 42
42#define CONSOLE_CLEAR "" 43#define CONSOLE_CLEAR ""