diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-30 14:15:14 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-30 14:15:14 -0500 |
commit | d8b91dde38f4c43bd0bbbf17a90f735b16aaff2c (patch) | |
tree | bd72dabf6e4b23e060fce429c87e60504f69de54 /tools/lib | |
parent | 5e7481a25e90b661d1dbbba18be3fd3dfe12ec6f (diff) | |
parent | e4c1091cb495d9cbec8956d642644a71a1689958 (diff) |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar:
"Kernel side changes:
- Clean up the x86 instruction decoder (Masami Hiramatsu)
- Add new uprobes optimization for PUSH instructions on x86 (Yonghong
Song)
- Add MSR_IA32_THERM_STATUS to the MSR events (Stephane Eranian)
- Fix misc bugs, update documentation, plus various cleanups (Jiri
Olsa)
There's a large number of tooling side improvements:
- Intel-PT/BTS improvements (Adrian Hunter)
- Numerous 'perf trace' improvements (Arnaldo Carvalho de Melo)
- Introduce an errno code to string facility (Hendrik Brueckner)
- Various build system improvements (Jiri Olsa)
- Add support for CoreSight trace decoding by making the perf tools
use the external openCSD (Mathieu Poirier, Tor Jeremiassen)
- Add ARM Statistical Profiling Extensions (SPE) support (Kim
Phillips)
- libtraceevent updates (Steven Rostedt)
- Intel vendor event JSON updates (Andi Kleen)
- Introduce 'perf report --mmaps' and 'perf report --tasks' to show
info present in 'perf.data' (Jiri Olsa, Arnaldo Carvalho de Melo)
- Add infrastructure to record first and last sample time to the
perf.data file header, so that when processing all samples in a
'perf record' session, such as when doing build-id processing, or
when specifically requesting that that info be recorded, use that
in 'perf report --time', that also got support for percent slices
in addition to absolute ones.
I.e. now it is possible to ask for the samples in the 10%-20% time
slice of a perf.data file (Jin Yao)
- Allow system wide 'perf stat --per-thread', sorting the result (Jin
Yao)
E.g.:
[root@jouet ~]# perf stat --per-thread --metrics IPC
^C
Performance counter stats for 'system wide':
make-22229 23,012,094,032 inst_retired.any # 0.8 IPC
cc1-22419 692,027,497 inst_retired.any # 0.8 IPC
gcc-22418 328,231,855 inst_retired.any # 0.9 IPC
cc1-22509 220,853,647 inst_retired.any # 0.8 IPC
gcc-22486 199,874,810 inst_retired.any # 1.0 IPC
as-22466 177,896,365 inst_retired.any # 0.9 IPC
cc1-22465 150,732,374 inst_retired.any # 0.8 IPC
gcc-22508 112,555,593 inst_retired.any # 0.9 IPC
cc1-22487 108,964,079 inst_retired.any # 0.7 IPC
qemu-system-x86-2697 21,330,550 inst_retired.any # 0.3 IPC
systemd-journal-551 20,642,951 inst_retired.any # 0.4 IPC
docker-containe-17651 9,552,892 inst_retired.any # 0.5 IPC
dockerd-current-9809 7,528,586 inst_retired.any # 0.5 IPC
make-22153 12,504,194,380 inst_retired.any # 0.8 IPC
python2-22429 12,081,290,954 inst_retired.any # 0.8 IPC
<SNIP>
python2-22429 15,026,328,103 cpu_clk_unhalted.thread
cc1-22419 826,660,193 cpu_clk_unhalted.thread
gcc-22418 365,321,295 cpu_clk_unhalted.thread
cc1-22509 279,169,362 cpu_clk_unhalted.thread
gcc-22486 210,156,950 cpu_clk_unhalted.thread
<SNIP>
5.638075538 seconds time elapsed
[root@jouet ~]#
- Improve shell auto-completion of perf events (Jin Yao)
- 'perf probe' improvements (Masami Hiramatsu)
- Improve PMU infrastructure to support amp64's ThunderX2
implementation defined core events (Ganapatrao Kulkarni)
- Various annotation related improvements and fixes (Thomas Richter)
- Clarify usage of 'overwrite' and 'backward' in the evlist/mmap
code, removing the 'overwrite' parameter from several functions as
it was always used it as 'false' (Wang Nan)
- Fix/improve 'perf record' reverse recording support (Wang Nan)
- Improve command line options documentation (Sihyeon Jang)
- Optimize sample parsing for ordering events, where we don't need to
parse all the PERF_SAMPLE_ bits, just the ones leading to the
timestamp needed to reorder events (Jiri Olsa)
- Generalize the annotation code to support other source information
besides objdump/DWARF obtained ones, starting with python scripts,
that will is slated to be merged soon (Jiri Olsa)
- ... and a lot more that I failed to list, see the shortlog and
changelog for details"
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (262 commits)
perf trace beauty flock: Move to separate object file
perf evlist: Remove fcntl.h from evlist.h
perf trace beauty futex: Beautify FUTEX_BITSET_MATCH_ANY
perf trace: Do not print from time delta for interrupted syscall lines
perf trace: Add --print-sample
perf bpf: Remove misplaced __maybe_unused attribute
MAINTAINERS: Adding entry for CoreSight trace decoding
perf tools: Add mechanic to synthesise CoreSight trace packets
perf tools: Add full support for CoreSight trace decoding
pert tools: Add queue management functionality
perf tools: Add functionality to communicate with the openCSD decoder
perf tools: Add support for decoding CoreSight trace data
perf tools: Add decoder mechanic to support dumping trace data
perf tools: Add processing of coresight metadata
perf tools: Add initial entry point for decoder CoreSight traces
perf tools: Integrating the CoreSight decoding library
perf vendor events intel: Update IvyTown files to V20
perf vendor events intel: Update IvyBridge files to V20
perf vendor events intel: Update BroadwellDE events to V7
perf vendor events intel: Update SkylakeX events to V1.06
...
Diffstat (limited to 'tools/lib')
-rw-r--r-- | tools/lib/traceevent/event-parse.c | 62 | ||||
-rw-r--r-- | tools/lib/traceevent/event-plugin.c | 24 | ||||
-rw-r--r-- | tools/lib/traceevent/kbuffer-parse.c | 4 | ||||
-rw-r--r-- | tools/lib/traceevent/parse-filter.c | 22 |
4 files changed, 76 insertions, 36 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 7ce724fc0544..e5f2acbb70cc 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -1094,7 +1094,7 @@ static enum event_type __read_token(char **tok) | |||
1094 | if (strcmp(*tok, "LOCAL_PR_FMT") == 0) { | 1094 | if (strcmp(*tok, "LOCAL_PR_FMT") == 0) { |
1095 | free(*tok); | 1095 | free(*tok); |
1096 | *tok = NULL; | 1096 | *tok = NULL; |
1097 | return force_token("\"\%s\" ", tok); | 1097 | return force_token("\"%s\" ", tok); |
1098 | } else if (strcmp(*tok, "STA_PR_FMT") == 0) { | 1098 | } else if (strcmp(*tok, "STA_PR_FMT") == 0) { |
1099 | free(*tok); | 1099 | free(*tok); |
1100 | *tok = NULL; | 1100 | *tok = NULL; |
@@ -3970,6 +3970,11 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3970 | val &= ~fval; | 3970 | val &= ~fval; |
3971 | } | 3971 | } |
3972 | } | 3972 | } |
3973 | if (val) { | ||
3974 | if (print && arg->flags.delim) | ||
3975 | trace_seq_puts(s, arg->flags.delim); | ||
3976 | trace_seq_printf(s, "0x%llx", val); | ||
3977 | } | ||
3973 | break; | 3978 | break; |
3974 | case PRINT_SYMBOL: | 3979 | case PRINT_SYMBOL: |
3975 | val = eval_num_arg(data, size, event, arg->symbol.field); | 3980 | val = eval_num_arg(data, size, event, arg->symbol.field); |
@@ -3980,6 +3985,8 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3980 | break; | 3985 | break; |
3981 | } | 3986 | } |
3982 | } | 3987 | } |
3988 | if (!flag) | ||
3989 | trace_seq_printf(s, "0x%llx", val); | ||
3983 | break; | 3990 | break; |
3984 | case PRINT_HEX: | 3991 | case PRINT_HEX: |
3985 | case PRINT_HEX_STR: | 3992 | case PRINT_HEX_STR: |
@@ -4293,6 +4300,26 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc | |||
4293 | goto process_again; | 4300 | goto process_again; |
4294 | case 'p': | 4301 | case 'p': |
4295 | ls = 1; | 4302 | ls = 1; |
4303 | if (isalnum(ptr[1])) { | ||
4304 | ptr++; | ||
4305 | /* Check for special pointers */ | ||
4306 | switch (*ptr) { | ||
4307 | case 's': | ||
4308 | case 'S': | ||
4309 | case 'f': | ||
4310 | case 'F': | ||
4311 | break; | ||
4312 | default: | ||
4313 | /* | ||
4314 | * Older kernels do not process | ||
4315 | * dereferenced pointers. | ||
4316 | * Only process if the pointer | ||
4317 | * value is a printable. | ||
4318 | */ | ||
4319 | if (isprint(*(char *)bptr)) | ||
4320 | goto process_string; | ||
4321 | } | ||
4322 | } | ||
4296 | /* fall through */ | 4323 | /* fall through */ |
4297 | case 'd': | 4324 | case 'd': |
4298 | case 'u': | 4325 | case 'u': |
@@ -4345,6 +4372,7 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc | |||
4345 | 4372 | ||
4346 | break; | 4373 | break; |
4347 | case 's': | 4374 | case 's': |
4375 | process_string: | ||
4348 | arg = alloc_arg(); | 4376 | arg = alloc_arg(); |
4349 | if (!arg) { | 4377 | if (!arg) { |
4350 | do_warning_event(event, "%s(%d): not enough memory!", | 4378 | do_warning_event(event, "%s(%d): not enough memory!", |
@@ -4949,21 +4977,27 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
4949 | else | 4977 | else |
4950 | ls = 2; | 4978 | ls = 2; |
4951 | 4979 | ||
4952 | if (*(ptr+1) == 'F' || *(ptr+1) == 'f' || | 4980 | if (isalnum(ptr[1])) |
4953 | *(ptr+1) == 'S' || *(ptr+1) == 's') { | ||
4954 | ptr++; | 4981 | ptr++; |
4982 | |||
4983 | if (arg->type == PRINT_BSTRING) { | ||
4984 | trace_seq_puts(s, arg->string.string); | ||
4985 | break; | ||
4986 | } | ||
4987 | |||
4988 | if (*ptr == 'F' || *ptr == 'f' || | ||
4989 | *ptr == 'S' || *ptr == 's') { | ||
4955 | show_func = *ptr; | 4990 | show_func = *ptr; |
4956 | } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') { | 4991 | } else if (*ptr == 'M' || *ptr == 'm') { |
4957 | print_mac_arg(s, *(ptr+1), data, size, event, arg); | 4992 | print_mac_arg(s, *ptr, data, size, event, arg); |
4958 | ptr++; | ||
4959 | arg = arg->next; | 4993 | arg = arg->next; |
4960 | break; | 4994 | break; |
4961 | } else if (*(ptr+1) == 'I' || *(ptr+1) == 'i') { | 4995 | } else if (*ptr == 'I' || *ptr == 'i') { |
4962 | int n; | 4996 | int n; |
4963 | 4997 | ||
4964 | n = print_ip_arg(s, ptr+1, data, size, event, arg); | 4998 | n = print_ip_arg(s, ptr, data, size, event, arg); |
4965 | if (n > 0) { | 4999 | if (n > 0) { |
4966 | ptr += n; | 5000 | ptr += n - 1; |
4967 | arg = arg->next; | 5001 | arg = arg->next; |
4968 | break; | 5002 | break; |
4969 | } | 5003 | } |
@@ -5532,8 +5566,14 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s, | |||
5532 | 5566 | ||
5533 | event = pevent_find_event_by_record(pevent, record); | 5567 | event = pevent_find_event_by_record(pevent, record); |
5534 | if (!event) { | 5568 | if (!event) { |
5535 | do_warning("ug! no event found for type %d", | 5569 | int i; |
5536 | trace_parse_common_type(pevent, record->data)); | 5570 | int type = trace_parse_common_type(pevent, record->data); |
5571 | |||
5572 | do_warning("ug! no event found for type %d", type); | ||
5573 | trace_seq_printf(s, "[UNKNOWN TYPE %d]", type); | ||
5574 | for (i = 0; i < record->size; i++) | ||
5575 | trace_seq_printf(s, " %02x", | ||
5576 | ((unsigned char *)record->data)[i]); | ||
5537 | return; | 5577 | return; |
5538 | } | 5578 | } |
5539 | 5579 | ||
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c index a16756ae3526..d542cb60ca1a 100644 --- a/tools/lib/traceevent/event-plugin.c +++ b/tools/lib/traceevent/event-plugin.c | |||
@@ -120,12 +120,12 @@ char **traceevent_plugin_list_options(void) | |||
120 | for (op = reg->options; op->name; op++) { | 120 | for (op = reg->options; op->name; op++) { |
121 | char *alias = op->plugin_alias ? op->plugin_alias : op->file; | 121 | char *alias = op->plugin_alias ? op->plugin_alias : op->file; |
122 | char **temp = list; | 122 | char **temp = list; |
123 | int ret; | ||
123 | 124 | ||
124 | name = malloc(strlen(op->name) + strlen(alias) + 2); | 125 | ret = asprintf(&name, "%s:%s", alias, op->name); |
125 | if (!name) | 126 | if (ret < 0) |
126 | goto err; | 127 | goto err; |
127 | 128 | ||
128 | sprintf(name, "%s:%s", alias, op->name); | ||
129 | list = realloc(list, count + 2); | 129 | list = realloc(list, count + 2); |
130 | if (!list) { | 130 | if (!list) { |
131 | list = temp; | 131 | list = temp; |
@@ -290,17 +290,14 @@ load_plugin(struct pevent *pevent, const char *path, | |||
290 | const char *alias; | 290 | const char *alias; |
291 | char *plugin; | 291 | char *plugin; |
292 | void *handle; | 292 | void *handle; |
293 | int ret; | ||
293 | 294 | ||
294 | plugin = malloc(strlen(path) + strlen(file) + 2); | 295 | ret = asprintf(&plugin, "%s/%s", path, file); |
295 | if (!plugin) { | 296 | if (ret < 0) { |
296 | warning("could not allocate plugin memory\n"); | 297 | warning("could not allocate plugin memory\n"); |
297 | return; | 298 | return; |
298 | } | 299 | } |
299 | 300 | ||
300 | strcpy(plugin, path); | ||
301 | strcat(plugin, "/"); | ||
302 | strcat(plugin, file); | ||
303 | |||
304 | handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL); | 301 | handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL); |
305 | if (!handle) { | 302 | if (!handle) { |
306 | warning("could not load plugin '%s'\n%s\n", | 303 | warning("could not load plugin '%s'\n%s\n", |
@@ -391,6 +388,7 @@ load_plugins(struct pevent *pevent, const char *suffix, | |||
391 | char *home; | 388 | char *home; |
392 | char *path; | 389 | char *path; |
393 | char *envdir; | 390 | char *envdir; |
391 | int ret; | ||
394 | 392 | ||
395 | if (pevent->flags & PEVENT_DISABLE_PLUGINS) | 393 | if (pevent->flags & PEVENT_DISABLE_PLUGINS) |
396 | return; | 394 | return; |
@@ -421,16 +419,12 @@ load_plugins(struct pevent *pevent, const char *suffix, | |||
421 | if (!home) | 419 | if (!home) |
422 | return; | 420 | return; |
423 | 421 | ||
424 | path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2); | 422 | ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR); |
425 | if (!path) { | 423 | if (ret < 0) { |
426 | warning("could not allocate plugin memory\n"); | 424 | warning("could not allocate plugin memory\n"); |
427 | return; | 425 | return; |
428 | } | 426 | } |
429 | 427 | ||
430 | strcpy(path, home); | ||
431 | strcat(path, "/"); | ||
432 | strcat(path, LOCAL_PLUGIN_DIR); | ||
433 | |||
434 | load_plugins_dir(pevent, suffix, path, load_plugin, data); | 428 | load_plugins_dir(pevent, suffix, path, load_plugin, data); |
435 | 429 | ||
436 | free(path); | 430 | free(path); |
diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c index c94e3641b046..ca424b157e46 100644 --- a/tools/lib/traceevent/kbuffer-parse.c +++ b/tools/lib/traceevent/kbuffer-parse.c | |||
@@ -24,8 +24,8 @@ | |||
24 | 24 | ||
25 | #include "kbuffer.h" | 25 | #include "kbuffer.h" |
26 | 26 | ||
27 | #define MISSING_EVENTS (1 << 31) | 27 | #define MISSING_EVENTS (1UL << 31) |
28 | #define MISSING_STORED (1 << 30) | 28 | #define MISSING_STORED (1UL << 30) |
29 | 29 | ||
30 | #define COMMIT_MASK ((1 << 27) - 1) | 30 | #define COMMIT_MASK ((1 << 27) - 1) |
31 | 31 | ||
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 315df0a70265..431e8b309f6e 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
@@ -287,12 +287,10 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
287 | sys_name = NULL; | 287 | sys_name = NULL; |
288 | } | 288 | } |
289 | 289 | ||
290 | reg = malloc(strlen(event_name) + 3); | 290 | ret = asprintf(®, "^%s$", event_name); |
291 | if (reg == NULL) | 291 | if (ret < 0) |
292 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | 292 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; |
293 | 293 | ||
294 | sprintf(reg, "^%s$", event_name); | ||
295 | |||
296 | ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); | 294 | ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); |
297 | free(reg); | 295 | free(reg); |
298 | 296 | ||
@@ -300,13 +298,12 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
300 | return PEVENT_ERRNO__INVALID_EVENT_NAME; | 298 | return PEVENT_ERRNO__INVALID_EVENT_NAME; |
301 | 299 | ||
302 | if (sys_name) { | 300 | if (sys_name) { |
303 | reg = malloc(strlen(sys_name) + 3); | 301 | ret = asprintf(®, "^%s$", sys_name); |
304 | if (reg == NULL) { | 302 | if (ret < 0) { |
305 | regfree(&ereg); | 303 | regfree(&ereg); |
306 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | 304 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; |
307 | } | 305 | } |
308 | 306 | ||
309 | sprintf(reg, "^%s$", sys_name); | ||
310 | ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); | 307 | ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); |
311 | free(reg); | 308 | free(reg); |
312 | if (ret) { | 309 | if (ret) { |
@@ -1634,6 +1631,7 @@ int pevent_filter_clear_trivial(struct event_filter *filter, | |||
1634 | case FILTER_TRIVIAL_FALSE: | 1631 | case FILTER_TRIVIAL_FALSE: |
1635 | if (filter_type->filter->boolean.value) | 1632 | if (filter_type->filter->boolean.value) |
1636 | continue; | 1633 | continue; |
1634 | break; | ||
1637 | case FILTER_TRIVIAL_TRUE: | 1635 | case FILTER_TRIVIAL_TRUE: |
1638 | if (!filter_type->filter->boolean.value) | 1636 | if (!filter_type->filter->boolean.value) |
1639 | continue; | 1637 | continue; |
@@ -1879,17 +1877,25 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r | |||
1879 | struct pevent *pevent; | 1877 | struct pevent *pevent; |
1880 | unsigned long long addr; | 1878 | unsigned long long addr; |
1881 | const char *val = NULL; | 1879 | const char *val = NULL; |
1880 | unsigned int size; | ||
1882 | char hex[64]; | 1881 | char hex[64]; |
1883 | 1882 | ||
1884 | /* If the field is not a string convert it */ | 1883 | /* If the field is not a string convert it */ |
1885 | if (arg->str.field->flags & FIELD_IS_STRING) { | 1884 | if (arg->str.field->flags & FIELD_IS_STRING) { |
1886 | val = record->data + arg->str.field->offset; | 1885 | val = record->data + arg->str.field->offset; |
1886 | size = arg->str.field->size; | ||
1887 | |||
1888 | if (arg->str.field->flags & FIELD_IS_DYNAMIC) { | ||
1889 | addr = *(unsigned int *)val; | ||
1890 | val = record->data + (addr & 0xffff); | ||
1891 | size = addr >> 16; | ||
1892 | } | ||
1887 | 1893 | ||
1888 | /* | 1894 | /* |
1889 | * We need to copy the data since we can't be sure the field | 1895 | * We need to copy the data since we can't be sure the field |
1890 | * is null terminated. | 1896 | * is null terminated. |
1891 | */ | 1897 | */ |
1892 | if (*(val + arg->str.field->size - 1)) { | 1898 | if (*(val + size - 1)) { |
1893 | /* copy it */ | 1899 | /* copy it */ |
1894 | memcpy(arg->str.buffer, val, arg->str.field->size); | 1900 | memcpy(arg->str.buffer, val, arg->str.field->size); |
1895 | /* the buffer is already NULL terminated */ | 1901 | /* the buffer is already NULL terminated */ |