diff options
| author | Ingo Molnar <mingo@kernel.org> | 2017-10-03 12:30:24 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2017-10-03 12:30:24 -0400 |
| commit | 4b50239a769e78bbe362fc92c3f8bd5415a4a5f5 (patch) | |
| tree | 951832e213945ede19cd676a04e5218e68afd074 /tools/perf | |
| parent | a47ba4d77e1236d214e5116b5631bc4c2d6e6369 (diff) | |
| parent | f6a9820d572bd8384d982357cbad214b3a6c04bb (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')
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 | ||
| 244 | INTERACTIVE PROMPTING KEYS | 247 | INTERACTIVE 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 @@ | |||
| 1 | libperf-y += header.o | 1 | libperf-y += header.o |
| 2 | libperf-y += sym-handling.o | ||
| 3 | libperf-y += kvm-stat.o | 2 | libperf-y += kvm-stat.o |
| 4 | 3 | ||
| 5 | libperf-$(CONFIG_DWARF) += dwarf-regs.o | 4 | libperf-$(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 | ||
| 15 | bool 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 | |||
| 22 | void 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); |
| 867 | out: | 867 | out: |
| 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 | ||
| 172 | int test__attr(struct test *test __maybe_unused, int subtest __maybe_unused) | 172 | int 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 | |||
| 23 | freq=1 | 23 | freq=1 |
| 24 | inherit_stat=0 | 24 | inherit_stat=0 |
| 25 | enable_on_exec=1 | 25 | enable_on_exec=1 |
| 26 | task=0 | 26 | task=1 |
| 27 | watermark=0 | 27 | watermark=0 |
| 28 | precise_ip=0|1|2|3 | 28 | precise_ip=0|1|2|3 |
| 29 | mmap_data=0 | 29 | mmap_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 | |||
| 17 | read_format=4 | 17 | read_format=4 |
| 18 | mmap=0 | 18 | mmap=0 |
| 19 | comm=0 | 19 | comm=0 |
| 20 | task=0 | ||
| 20 | enable_on_exec=0 | 21 | enable_on_exec=0 |
| 21 | disabled=0 | 22 | disabled=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 |
| 25 | read_format=12 | 25 | read_format=12 |
| 26 | 26 | task=0 | |
| 27 | mmap=0 | 27 | mmap=0 |
| 28 | comm=0 | 28 | comm=0 |
| 29 | enable_on_exec=0 | 29 | enable_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 | |||
| 18 | read_format=4 | 18 | read_format=4 |
| 19 | mmap=0 | 19 | mmap=0 |
| 20 | comm=0 | 20 | comm=0 |
| 21 | task=0 | ||
| 21 | enable_on_exec=0 | 22 | enable_on_exec=0 |
| 22 | disabled=0 | 23 | disabled=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] |
| 7 | fd=1 | 7 | fd=1 |
| 8 | group_fd=-1 | 8 | group_fd=-1 |
| 9 | read_format=3|15 | ||
| 9 | 10 | ||
| 10 | [event-2:base-stat] | 11 | [event-2:base-stat] |
| 11 | fd=2 | 12 | fd=2 |
| @@ -13,3 +14,4 @@ group_fd=1 | |||
| 13 | config=1 | 14 | config=1 |
| 14 | disabled=0 | 15 | disabled=0 |
| 15 | enable_on_exec=0 | 16 | enable_on_exec=0 |
| 17 | read_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] |
| 7 | fd=1 | 7 | fd=1 |
| 8 | group_fd=-1 | 8 | group_fd=-1 |
| 9 | read_format=3|15 | ||
| 9 | 10 | ||
| 10 | [event-2:base-stat] | 11 | [event-2:base-stat] |
| 11 | fd=2 | 12 | fd=2 |
| @@ -13,3 +14,4 @@ group_fd=1 | |||
| 13 | config=1 | 14 | config=1 |
| 14 | disabled=0 | 15 | disabled=0 |
| 15 | enable_on_exec=0 | 16 | enable_on_exec=0 |
| 17 | read_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 | ||
| 137 | static int synth_process(struct machine *machine) | 137 | static 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 | ||
| 9 | struct comm_str { | 10 | struct 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 */ |
| 16 | static struct rb_root comm_str_root; | 17 | static struct rb_root comm_str_root; |
| 18 | static struct rw_semaphore comm_str_lock = {.lock = PTHREAD_RWLOCK_INITIALIZER,}; | ||
| 17 | 19 | ||
| 18 | static struct comm_str *comm_str__get(struct comm_str *cs) | 20 | static 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) | |||
| 25 | static void comm_str__put(struct comm_str *cs) | 27 | static 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 | ||
| 53 | static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root) | 57 | static |
| 58 | struct 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 | ||
| 89 | static 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 | |||
| 84 | struct comm *comm__new(const char *str, u64 timestamp, bool exec) | 100 | struct 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 | ||
| 681 | int perf_event__synthesize_threads(struct perf_tool *tool, | 681 | static 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 | ||
| 744 | out_free_namespaces: | ||
| 745 | free(namespaces_event); | 734 | free(namespaces_event); |
| 746 | out_free_fork: | 735 | out_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 | ||
| 745 | struct 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 | |||
| 756 | static 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 | |||
| 767 | int 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; | ||
| 843 | out_join: | ||
| 844 | for (i = 0; i < thread_nr; i++) | ||
| 845 | pthread_join(synthesize_threads[i], NULL); | ||
| 846 | free(args); | ||
| 847 | free_threads: | ||
| 848 | free(synthesize_threads); | ||
| 849 | free_dirent: | ||
| 850 | for (i = 0; i < n; i++) | ||
| 851 | free(dirent[i]); | ||
| 852 | free(dirent); | ||
| 853 | |||
| 854 | return err; | ||
| 855 | } | ||
| 856 | |||
| 756 | struct process_symbol_args { | 857 | struct 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, | |||
| 680 | int perf_event__synthesize_threads(struct perf_tool *tool, | 680 | int 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); | ||
| 684 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | 685 | int 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 | ||
| 274 | static bool perf_event_can_profile_kernel(void) | ||
| 275 | { | ||
| 276 | return geteuid() == 0 || perf_event_paranoid() == -1; | ||
| 277 | } | ||
| 278 | |||
| 274 | struct perf_evsel *perf_evsel__new_cycles(bool precise) | 279 | struct 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, | |||
| 2218 | int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, | 2218 | int __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, | |||
| 257 | int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, | 257 | int __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); | ||
| 261 | static inline | 262 | static inline |
| 262 | int machine__synthesize_threads(struct machine *machine, struct target *target, | 263 | int 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 | ||
| 271 | pid_t machine__get_current_tid(struct machine *machine, int cpu); | 274 | pid_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) | |||
| 810 | void __weak arch__sym_update(struct symbol *s __maybe_unused, | 810 | void __weak arch__sym_update(struct symbol *s __maybe_unused, |
| 811 | GElf_Sym *sym __maybe_unused) { } | 811 | GElf_Sym *sym __maybe_unused) { } |
| 812 | 812 | ||
| 813 | void __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 | |||
| 819 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, | 813 | int 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 |
| 345 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); | 345 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); |
| 346 | void arch__sym_update(struct symbol *s, GElf_Sym *sym); | 346 | void arch__sym_update(struct symbol *s, GElf_Sym *sym); |
| 347 | void 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 | ||
| 128 | int thread__set_namespaces(struct thread *thread, u64 timestamp, | 138 | static 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 | ||
| 162 | int 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 | |||
| 152 | struct comm *thread__comm(const struct thread *thread) | 173 | struct 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 | ||
| 173 | int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp, | 194 | static 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 | ||
| 219 | int __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 | |||
| 198 | int thread__set_comm_from_proc(struct thread *thread) | 230 | int 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 | ||
| 215 | const char *thread__comm_str(const struct thread *thread) | 247 | static 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 | ||
| 257 | const 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 */ |
| 226 | int thread__comm_len(struct thread *thread) | 269 | int 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 | ||
| 13 | struct thread_stack; | 14 | struct thread_stack; |
| 14 | struct unwind_libunwind_ops; | 15 | struct 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 "[H[2J" | 43 | #define CONSOLE_CLEAR "[H[2J" |
