Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf fixes from Ingo Molnar:
"This is larger than usual: the main reason are the ARM symbol lookup
speedups that came in late and were hard to resist.

There's also a kprobes fix and various tooling fixes, plus the minimal
re-enablement of the mmap2 support interface"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (36 commits)
x86/kprobes: Fix build errors and blacklist context_track_user
perf tests: Add test for closing dso objects on EMFILE error
perf tests: Add test for caching dso file descriptors
perf tests: Allow reuse of test_file function
perf tests: Spawn child for each test
perf tools: Add dso__data_* interface descriptons
perf tools: Allow to close dso fd in case of open failure
perf tools: Add file size check and factor dso__data_read_offset
perf tools: Cache dso data file descriptor
perf tools: Add global count of opened dso objects
perf tools: Add global list of opened dso objects
perf tools: Add data_fd into dso object
perf tools: Separate dso data related variables
perf tools: Cache register accesses for unwind processing
perf record: Fix to honor user freq/interval properly
perf timechart: Reflow documentation
perf probe: Improve error messages in --line option
perf probe: Improve an error message of perf probe --vars mode
perf probe: Show error code and description in verbose mode
perf probe: Improve error message for unknown member of data structure
...

+1249 -126
+4 -3
arch/x86/kernel/traps.c
··· 343 343 if (poke_int3_handler(regs)) 344 344 return; 345 345 346 + prev_state = exception_enter(); 346 347 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP 347 348 if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, 348 349 SIGTRAP) == NOTIFY_STOP) ··· 352 351 353 352 #ifdef CONFIG_KPROBES 354 353 if (kprobe_int3_handler(regs)) 355 - return; 354 + goto exit; 356 355 #endif 357 - prev_state = exception_enter(); 358 356 359 357 if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, 360 358 SIGTRAP) == NOTIFY_STOP) ··· 433 433 unsigned long dr6; 434 434 int si_code; 435 435 436 + prev_state = exception_enter(); 437 + 436 438 get_debugreg(dr6, 6); 437 439 438 440 /* Filter out all the reserved bits which are preset to 1 */ ··· 467 465 if (kprobe_debug_handler(regs)) 468 466 goto exit; 469 467 #endif 470 - prev_state = exception_enter(); 471 468 472 469 if (notify_die(DIE_DEBUG, "debug", regs, (long)&dr6, error_code, 473 470 SIGTRAP) == NOTIFY_STOP)
+1
include/uapi/linux/perf_event.h
··· 705 705 * u32 min; 706 706 * u64 ino; 707 707 * u64 ino_generation; 708 + * u32 prot, flags; 708 709 * char filename[]; 709 710 * struct sample_id sample_id; 710 711 * };
+3
kernel/context_tracking.c
··· 19 19 #include <linux/sched.h> 20 20 #include <linux/hardirq.h> 21 21 #include <linux/export.h> 22 + #include <linux/kprobes.h> 22 23 23 24 #define CREATE_TRACE_POINTS 24 25 #include <trace/events/context_tracking.h> ··· 105 104 } 106 105 local_irq_restore(flags); 107 106 } 107 + NOKPROBE_SYMBOL(context_tracking_user_enter); 108 108 109 109 #ifdef CONFIG_PREEMPT 110 110 /** ··· 183 181 } 184 182 local_irq_restore(flags); 185 183 } 184 + NOKPROBE_SYMBOL(context_tracking_user_exit); 186 185 187 186 /** 188 187 * __context_tracking_task_switch - context switch the syscall callbacks
+33 -4
kernel/events/core.c
··· 40 40 #include <linux/mm_types.h> 41 41 #include <linux/cgroup.h> 42 42 #include <linux/module.h> 43 + #include <linux/mman.h> 43 44 44 45 #include "internal.h" 45 46 ··· 5129 5128 int maj, min; 5130 5129 u64 ino; 5131 5130 u64 ino_generation; 5131 + u32 prot, flags; 5132 5132 5133 5133 struct { 5134 5134 struct perf_event_header header; ··· 5171 5169 mmap_event->event_id.header.size += sizeof(mmap_event->min); 5172 5170 mmap_event->event_id.header.size += sizeof(mmap_event->ino); 5173 5171 mmap_event->event_id.header.size += sizeof(mmap_event->ino_generation); 5172 + mmap_event->event_id.header.size += sizeof(mmap_event->prot); 5173 + mmap_event->event_id.header.size += sizeof(mmap_event->flags); 5174 5174 } 5175 5175 5176 5176 perf_event_header__init_id(&mmap_event->event_id.header, &sample, event); ··· 5191 5187 perf_output_put(&handle, mmap_event->min); 5192 5188 perf_output_put(&handle, mmap_event->ino); 5193 5189 perf_output_put(&handle, mmap_event->ino_generation); 5190 + perf_output_put(&handle, mmap_event->prot); 5191 + perf_output_put(&handle, mmap_event->flags); 5194 5192 } 5195 5193 5196 5194 __output_copy(&handle, mmap_event->file_name, ··· 5211 5205 struct file *file = vma->vm_file; 5212 5206 int maj = 0, min = 0; 5213 5207 u64 ino = 0, gen = 0; 5208 + u32 prot = 0, flags = 0; 5214 5209 unsigned int size; 5215 5210 char tmp[16]; 5216 5211 char *buf = NULL; ··· 5242 5235 gen = inode->i_generation; 5243 5236 maj = MAJOR(dev); 5244 5237 min = MINOR(dev); 5238 + 5239 + if (vma->vm_flags & VM_READ) 5240 + prot |= PROT_READ; 5241 + if (vma->vm_flags & VM_WRITE) 5242 + prot |= PROT_WRITE; 5243 + if (vma->vm_flags & VM_EXEC) 5244 + prot |= PROT_EXEC; 5245 + 5246 + if (vma->vm_flags & VM_MAYSHARE) 5247 + flags = MAP_SHARED; 5248 + else 5249 + flags = MAP_PRIVATE; 5250 + 5251 + if (vma->vm_flags & VM_DENYWRITE) 5252 + flags |= MAP_DENYWRITE; 5253 + if (vma->vm_flags & VM_MAYEXEC) 5254 + flags |= MAP_EXECUTABLE; 5255 + if (vma->vm_flags & VM_LOCKED) 5256 + flags |= MAP_LOCKED; 5257 + if (vma->vm_flags & VM_HUGETLB) 5258 + flags |= MAP_HUGETLB; 5259 + 5245 5260 goto got_name; 5246 5261 } else { 5247 5262 name = (char *)arch_vma_name(vma); ··· 5304 5275 mmap_event->min = min; 5305 5276 mmap_event->ino = ino; 5306 5277 mmap_event->ino_generation = gen; 5278 + mmap_event->prot = prot; 5279 + mmap_event->flags = flags; 5307 5280 5308 5281 if (!(vma->vm_flags & VM_EXEC)) 5309 5282 mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_DATA; ··· 5346 5315 /* .min (attr_mmap2 only) */ 5347 5316 /* .ino (attr_mmap2 only) */ 5348 5317 /* .ino_generation (attr_mmap2 only) */ 5318 + /* .prot (attr_mmap2 only) */ 5319 + /* .flags (attr_mmap2 only) */ 5349 5320 }; 5350 5321 5351 5322 perf_event_mmap_event(&mmap_event); ··· 6929 6896 ret = copy_from_user(attr, uattr, size); 6930 6897 if (ret) 6931 6898 return -EFAULT; 6932 - 6933 - /* disabled for now */ 6934 - if (attr->mmap2) 6935 - return -EINVAL; 6936 6899 6937 6900 if (attr->__reserved_1) 6938 6901 return -EINVAL;
+113
tools/lib/traceevent/event-parse.c
··· 765 765 case PRINT_BSTRING: 766 766 free(arg->string.string); 767 767 break; 768 + case PRINT_BITMASK: 769 + free(arg->bitmask.bitmask); 770 + break; 768 771 case PRINT_DYNAMIC_ARRAY: 769 772 free(arg->dynarray.index); 770 773 break; ··· 2271 2268 case PRINT_FIELD ... PRINT_SYMBOL: 2272 2269 case PRINT_STRING: 2273 2270 case PRINT_BSTRING: 2271 + case PRINT_BITMASK: 2274 2272 default: 2275 2273 do_warning("invalid eval type %d", arg->type); 2276 2274 ret = 0; ··· 2300 2296 case PRINT_FIELD ... PRINT_SYMBOL: 2301 2297 case PRINT_STRING: 2302 2298 case PRINT_BSTRING: 2299 + case PRINT_BITMASK: 2303 2300 default: 2304 2301 do_warning("invalid eval type %d", arg->type); 2305 2302 break; ··· 2688 2683 return EVENT_ERROR; 2689 2684 } 2690 2685 2686 + static enum event_type 2687 + process_bitmask(struct event_format *event __maybe_unused, struct print_arg *arg, 2688 + char **tok) 2689 + { 2690 + enum event_type type; 2691 + char *token; 2692 + 2693 + if (read_expect_type(EVENT_ITEM, &token) < 0) 2694 + goto out_free; 2695 + 2696 + arg->type = PRINT_BITMASK; 2697 + arg->bitmask.bitmask = token; 2698 + arg->bitmask.offset = -1; 2699 + 2700 + if (read_expected(EVENT_DELIM, ")") < 0) 2701 + goto out_err; 2702 + 2703 + type = read_token(&token); 2704 + *tok = token; 2705 + 2706 + return type; 2707 + 2708 + out_free: 2709 + free_token(token); 2710 + out_err: 2711 + *tok = NULL; 2712 + return EVENT_ERROR; 2713 + } 2714 + 2691 2715 static struct pevent_function_handler * 2692 2716 find_func_handler(struct pevent *pevent, char *func_name) 2693 2717 { ··· 2830 2796 if (strcmp(token, "__get_str") == 0) { 2831 2797 free_token(token); 2832 2798 return process_str(event, arg, tok); 2799 + } 2800 + if (strcmp(token, "__get_bitmask") == 0) { 2801 + free_token(token); 2802 + return process_bitmask(event, arg, tok); 2833 2803 } 2834 2804 if (strcmp(token, "__get_dynamic_array") == 0) { 2835 2805 free_token(token); ··· 3362 3324 return eval_type(val, arg, 0); 3363 3325 case PRINT_STRING: 3364 3326 case PRINT_BSTRING: 3327 + case PRINT_BITMASK: 3365 3328 return 0; 3366 3329 case PRINT_FUNC: { 3367 3330 struct trace_seq s; ··· 3595 3556 trace_seq_printf(s, format, str); 3596 3557 } 3597 3558 3559 + static void print_bitmask_to_seq(struct pevent *pevent, 3560 + struct trace_seq *s, const char *format, 3561 + int len_arg, const void *data, int size) 3562 + { 3563 + int nr_bits = size * 8; 3564 + int str_size = (nr_bits + 3) / 4; 3565 + int len = 0; 3566 + char buf[3]; 3567 + char *str; 3568 + int index; 3569 + int i; 3570 + 3571 + /* 3572 + * The kernel likes to put in commas every 32 bits, we 3573 + * can do the same. 3574 + */ 3575 + str_size += (nr_bits - 1) / 32; 3576 + 3577 + str = malloc(str_size + 1); 3578 + if (!str) { 3579 + do_warning("%s: not enough memory!", __func__); 3580 + return; 3581 + } 3582 + str[str_size] = 0; 3583 + 3584 + /* Start out with -2 for the two chars per byte */ 3585 + for (i = str_size - 2; i >= 0; i -= 2) { 3586 + /* 3587 + * data points to a bit mask of size bytes. 3588 + * In the kernel, this is an array of long words, thus 3589 + * endianess is very important. 3590 + */ 3591 + if (pevent->file_bigendian) 3592 + index = size - (len + 1); 3593 + else 3594 + index = len; 3595 + 3596 + snprintf(buf, 3, "%02x", *((unsigned char *)data + index)); 3597 + memcpy(str + i, buf, 2); 3598 + len++; 3599 + if (!(len & 3) && i > 0) { 3600 + i--; 3601 + str[i] = ','; 3602 + } 3603 + } 3604 + 3605 + if (len_arg >= 0) 3606 + trace_seq_printf(s, format, len_arg, str); 3607 + else 3608 + trace_seq_printf(s, format, str); 3609 + 3610 + free(str); 3611 + } 3612 + 3598 3613 static void print_str_arg(struct trace_seq *s, void *data, int size, 3599 3614 struct event_format *event, const char *format, 3600 3615 int len_arg, struct print_arg *arg) ··· 3784 3691 case PRINT_BSTRING: 3785 3692 print_str_to_seq(s, format, len_arg, arg->string.string); 3786 3693 break; 3694 + case PRINT_BITMASK: { 3695 + int bitmask_offset; 3696 + int bitmask_size; 3697 + 3698 + if (arg->bitmask.offset == -1) { 3699 + struct format_field *f; 3700 + 3701 + f = pevent_find_any_field(event, arg->bitmask.bitmask); 3702 + arg->bitmask.offset = f->offset; 3703 + } 3704 + bitmask_offset = data2host4(pevent, data + arg->bitmask.offset); 3705 + bitmask_size = bitmask_offset >> 16; 3706 + bitmask_offset &= 0xffff; 3707 + print_bitmask_to_seq(pevent, s, format, len_arg, 3708 + data + bitmask_offset, bitmask_size); 3709 + break; 3710 + } 3787 3711 case PRINT_OP: 3788 3712 /* 3789 3713 * The only op for string should be ? : ··· 4931 4821 case PRINT_STRING: 4932 4822 case PRINT_BSTRING: 4933 4823 printf("__get_str(%s)", args->string.string); 4824 + break; 4825 + case PRINT_BITMASK: 4826 + printf("__get_bitmask(%s)", args->bitmask.bitmask); 4934 4827 break; 4935 4828 case PRINT_TYPE: 4936 4829 printf("(%s)", args->typecast.type);
+22 -3
tools/lib/traceevent/event-parse.h
··· 107 107 typedef int (*pevent_plugin_load_func)(struct pevent *pevent); 108 108 typedef int (*pevent_plugin_unload_func)(struct pevent *pevent); 109 109 110 - struct plugin_option { 111 - struct plugin_option *next; 110 + struct pevent_plugin_option { 111 + struct pevent_plugin_option *next; 112 112 void *handle; 113 113 char *file; 114 114 char *name; ··· 135 135 * PEVENT_PLUGIN_OPTIONS: (optional) 136 136 * Plugin options that can be set before loading 137 137 * 138 - * struct plugin_option PEVENT_PLUGIN_OPTIONS[] = { 138 + * struct pevent_plugin_option PEVENT_PLUGIN_OPTIONS[] = { 139 139 * { 140 140 * .name = "option-name", 141 141 * .plugin_alias = "overide-file-name", (optional) ··· 208 208 int offset; 209 209 }; 210 210 211 + struct print_arg_bitmask { 212 + char *bitmask; 213 + int offset; 214 + }; 215 + 211 216 struct print_arg_field { 212 217 char *name; 213 218 struct format_field *field; ··· 279 274 PRINT_DYNAMIC_ARRAY, 280 275 PRINT_OP, 281 276 PRINT_FUNC, 277 + PRINT_BITMASK, 282 278 }; 283 279 284 280 struct print_arg { ··· 294 288 struct print_arg_hex hex; 295 289 struct print_arg_func func; 296 290 struct print_arg_string string; 291 + struct print_arg_bitmask bitmask; 297 292 struct print_arg_op op; 298 293 struct print_arg_dynarray dynarray; 299 294 }; ··· 361 354 362 355 enum pevent_flag { 363 356 PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */ 357 + PEVENT_DISABLE_SYS_PLUGINS = 1 << 1, 358 + PEVENT_DISABLE_PLUGINS = 1 << 2, 364 359 }; 365 360 366 361 #define PEVENT_ERRORS \ ··· 419 410 420 411 struct plugin_list; 421 412 413 + #define INVALID_PLUGIN_LIST_OPTION ((char **)((unsigned long)-1)) 414 + 422 415 struct plugin_list *traceevent_load_plugins(struct pevent *pevent); 423 416 void traceevent_unload_plugins(struct plugin_list *plugin_list, 424 417 struct pevent *pevent); 418 + char **traceevent_plugin_list_options(void); 419 + void traceevent_plugin_free_options_list(char **list); 420 + int traceevent_plugin_add_options(const char *name, 421 + struct pevent_plugin_option *options); 422 + void traceevent_plugin_remove_options(struct pevent_plugin_option *options); 423 + void traceevent_print_plugins(struct trace_seq *s, 424 + const char *prefix, const char *suffix, 425 + const struct plugin_list *list); 425 426 426 427 struct cmdline; 427 428 struct cmdline_list;
+202 -1
tools/lib/traceevent/event-plugin.c
··· 18 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 19 */ 20 20 21 + #include <stdio.h> 21 22 #include <string.h> 22 23 #include <dlfcn.h> 23 24 #include <stdlib.h> ··· 31 30 32 31 #define LOCAL_PLUGIN_DIR ".traceevent/plugins" 33 32 33 + static struct registered_plugin_options { 34 + struct registered_plugin_options *next; 35 + struct pevent_plugin_option *options; 36 + } *registered_options; 37 + 38 + static struct trace_plugin_options { 39 + struct trace_plugin_options *next; 40 + char *plugin; 41 + char *option; 42 + char *value; 43 + } *trace_plugin_options; 44 + 34 45 struct plugin_list { 35 46 struct plugin_list *next; 36 47 char *name; 37 48 void *handle; 38 49 }; 50 + 51 + /** 52 + * traceevent_plugin_list_options - get list of plugin options 53 + * 54 + * Returns an array of char strings that list the currently registered 55 + * plugin options in the format of <plugin>:<option>. This list can be 56 + * used by toggling the option. 57 + * 58 + * Returns NULL if there's no options registered. On error it returns 59 + * INVALID_PLUGIN_LIST_OPTION 60 + * 61 + * Must be freed with traceevent_plugin_free_options_list(). 62 + */ 63 + char **traceevent_plugin_list_options(void) 64 + { 65 + struct registered_plugin_options *reg; 66 + struct pevent_plugin_option *op; 67 + char **list = NULL; 68 + char *name; 69 + int count = 0; 70 + 71 + for (reg = registered_options; reg; reg = reg->next) { 72 + for (op = reg->options; op->name; op++) { 73 + char *alias = op->plugin_alias ? op->plugin_alias : op->file; 74 + char **temp = list; 75 + 76 + name = malloc(strlen(op->name) + strlen(alias) + 2); 77 + if (!name) 78 + goto err; 79 + 80 + sprintf(name, "%s:%s", alias, op->name); 81 + list = realloc(list, count + 2); 82 + if (!list) { 83 + list = temp; 84 + free(name); 85 + goto err; 86 + } 87 + list[count++] = name; 88 + list[count] = NULL; 89 + } 90 + } 91 + return list; 92 + 93 + err: 94 + while (--count >= 0) 95 + free(list[count]); 96 + free(list); 97 + 98 + return INVALID_PLUGIN_LIST_OPTION; 99 + } 100 + 101 + void traceevent_plugin_free_options_list(char **list) 102 + { 103 + int i; 104 + 105 + if (!list) 106 + return; 107 + 108 + if (list == INVALID_PLUGIN_LIST_OPTION) 109 + return; 110 + 111 + for (i = 0; list[i]; i++) 112 + free(list[i]); 113 + 114 + free(list); 115 + } 116 + 117 + static int 118 + update_option(const char *file, struct pevent_plugin_option *option) 119 + { 120 + struct trace_plugin_options *op; 121 + char *plugin; 122 + 123 + if (option->plugin_alias) { 124 + plugin = strdup(option->plugin_alias); 125 + if (!plugin) 126 + return -1; 127 + } else { 128 + char *p; 129 + plugin = strdup(file); 130 + if (!plugin) 131 + return -1; 132 + p = strstr(plugin, "."); 133 + if (p) 134 + *p = '\0'; 135 + } 136 + 137 + /* first look for named options */ 138 + for (op = trace_plugin_options; op; op = op->next) { 139 + if (!op->plugin) 140 + continue; 141 + if (strcmp(op->plugin, plugin) != 0) 142 + continue; 143 + if (strcmp(op->option, option->name) != 0) 144 + continue; 145 + 146 + option->value = op->value; 147 + option->set ^= 1; 148 + goto out; 149 + } 150 + 151 + /* first look for unnamed options */ 152 + for (op = trace_plugin_options; op; op = op->next) { 153 + if (op->plugin) 154 + continue; 155 + if (strcmp(op->option, option->name) != 0) 156 + continue; 157 + 158 + option->value = op->value; 159 + option->set ^= 1; 160 + break; 161 + } 162 + 163 + out: 164 + free(plugin); 165 + return 0; 166 + } 167 + 168 + /** 169 + * traceevent_plugin_add_options - Add a set of options by a plugin 170 + * @name: The name of the plugin adding the options 171 + * @options: The set of options being loaded 172 + * 173 + * Sets the options with the values that have been added by user. 174 + */ 175 + int traceevent_plugin_add_options(const char *name, 176 + struct pevent_plugin_option *options) 177 + { 178 + struct registered_plugin_options *reg; 179 + 180 + reg = malloc(sizeof(*reg)); 181 + if (!reg) 182 + return -1; 183 + reg->next = registered_options; 184 + reg->options = options; 185 + registered_options = reg; 186 + 187 + while (options->name) { 188 + update_option(name, options); 189 + options++; 190 + } 191 + return 0; 192 + } 193 + 194 + /** 195 + * traceevent_plugin_remove_options - remove plugin options that were registered 196 + * @options: Options to removed that were registered with traceevent_plugin_add_options 197 + */ 198 + void traceevent_plugin_remove_options(struct pevent_plugin_option *options) 199 + { 200 + struct registered_plugin_options **last; 201 + struct registered_plugin_options *reg; 202 + 203 + for (last = &registered_options; *last; last = &(*last)->next) { 204 + if ((*last)->options == options) { 205 + reg = *last; 206 + *last = reg->next; 207 + free(reg); 208 + return; 209 + } 210 + } 211 + } 212 + 213 + /** 214 + * traceevent_print_plugins - print out the list of plugins loaded 215 + * @s: the trace_seq descripter to write to 216 + * @prefix: The prefix string to add before listing the option name 217 + * @suffix: The suffix string ot append after the option name 218 + * @list: The list of plugins (usually returned by traceevent_load_plugins() 219 + * 220 + * Writes to the trace_seq @s the list of plugins (files) that is 221 + * returned by traceevent_load_plugins(). Use @prefix and @suffix for formating: 222 + * @prefix = " ", @suffix = "\n". 223 + */ 224 + void traceevent_print_plugins(struct trace_seq *s, 225 + const char *prefix, const char *suffix, 226 + const struct plugin_list *list) 227 + { 228 + while (list) { 229 + trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix); 230 + list = list->next; 231 + } 232 + } 39 233 40 234 static void 41 235 load_plugin(struct pevent *pevent, const char *path, ··· 344 148 char *path; 345 149 char *envdir; 346 150 151 + if (pevent->flags & PEVENT_DISABLE_PLUGINS) 152 + return; 153 + 347 154 /* 348 155 * If a system plugin directory was defined, 349 156 * check that first. 350 157 */ 351 158 #ifdef PLUGIN_DIR 352 - load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data); 159 + if (!(pevent->flags & PEVENT_DISABLE_SYS_PLUGINS)) 160 + load_plugins_dir(pevent, suffix, PLUGIN_DIR, 161 + load_plugin, data); 353 162 #endif 354 163 355 164 /*
+37 -6
tools/lib/traceevent/plugin_function.c
··· 33 33 34 34 #define STK_BLK 10 35 35 36 + struct pevent_plugin_option plugin_options[] = 37 + { 38 + { 39 + .name = "parent", 40 + .plugin_alias = "ftrace", 41 + .description = 42 + "Print parent of functions for function events", 43 + }, 44 + { 45 + .name = "indent", 46 + .plugin_alias = "ftrace", 47 + .description = 48 + "Try to show function call indents, based on parents", 49 + .set = 1, 50 + }, 51 + { 52 + .name = NULL, 53 + } 54 + }; 55 + 56 + static struct pevent_plugin_option *ftrace_parent = &plugin_options[0]; 57 + static struct pevent_plugin_option *ftrace_indent = &plugin_options[1]; 58 + 36 59 static void add_child(struct func_stack *stack, const char *child, int pos) 37 60 { 38 61 int i; ··· 142 119 143 120 parent = pevent_find_function(pevent, pfunction); 144 121 145 - index = add_and_get_index(parent, func, record->cpu); 122 + if (parent && ftrace_indent->set) 123 + index = add_and_get_index(parent, func, record->cpu); 146 124 147 125 trace_seq_printf(s, "%*s", index*3, ""); 148 126 ··· 152 128 else 153 129 trace_seq_printf(s, "0x%llx", function); 154 130 155 - trace_seq_printf(s, " <-- "); 156 - if (parent) 157 - trace_seq_printf(s, "%s", parent); 158 - else 159 - trace_seq_printf(s, "0x%llx", pfunction); 131 + if (ftrace_parent->set) { 132 + trace_seq_printf(s, " <-- "); 133 + if (parent) 134 + trace_seq_printf(s, "%s", parent); 135 + else 136 + trace_seq_printf(s, "0x%llx", pfunction); 137 + } 160 138 161 139 return 0; 162 140 } ··· 167 141 { 168 142 pevent_register_event_handler(pevent, -1, "ftrace", "function", 169 143 function_handler, NULL); 144 + 145 + traceevent_plugin_add_options("ftrace", plugin_options); 146 + 170 147 return 0; 171 148 } 172 149 ··· 185 156 free(fstack[i].stack[x]); 186 157 free(fstack[i].stack); 187 158 } 159 + 160 + traceevent_plugin_remove_options(plugin_options); 188 161 189 162 free(fstack); 190 163 fstack = NULL;
+23
tools/perf/Documentation/perf-report.txt
··· 117 117 By default, every sort keys not specified in -F will be appended 118 118 automatically. 119 119 120 + If --mem-mode option is used, following sort keys are also available 121 + (incompatible with --branch-stack): 122 + symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline. 123 + 124 + - symbol_daddr: name of data symbol being executed on at the time of sample 125 + - dso_daddr: name of library or module containing the data being executed 126 + on at the time of sample 127 + - locked: whether the bus was locked at the time of sample 128 + - tlb: type of tlb access for the data at the time of sample 129 + - mem: type of memory access for the data at the time of sample 130 + - snoop: type of snoop (if any) for the data at the time of sample 131 + - dcacheline: the cacheline the data address is on at the time of sample 132 + 133 + And default sort keys are changed to local_weight, mem, sym, dso, 134 + symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'. 135 + 120 136 -p:: 121 137 --parent=<regex>:: 122 138 A regex filter to identify parent. The parent is a caller of this ··· 275 259 --demangle:: 276 260 Demangle symbol names to human readable form. It's enabled by default, 277 261 disable with --no-demangle. 262 + 263 + --mem-mode:: 264 + Use the data addresses of samples in addition to instruction addresses 265 + to build the histograms. To generate meaningful output, the perf.data 266 + file must have been obtained using perf record -d -W and using a 267 + special event -e cpu/mem-loads/ or -e cpu/mem-stores/. See 268 + 'perf mem' for simpler access. 278 269 279 270 --percent-limit:: 280 271 Do not show entries which have an overhead under that percent.
+20 -21
tools/perf/Documentation/perf-timechart.txt
··· 43 43 44 44 --symfs=<directory>:: 45 45 Look for files with symbols relative to this directory. 46 - 47 - EXAMPLES 48 - -------- 49 - 50 - $ perf timechart record git pull 51 - 52 - [ perf record: Woken up 13 times to write data ] 53 - [ perf record: Captured and wrote 4.253 MB perf.data (~185801 samples) ] 54 - 55 - $ perf timechart 56 - 57 - Written 10.2 seconds of trace to output.svg. 58 - 59 - Record system-wide timechart: 60 - 61 - $ perf timechart record 62 - 63 - then generate timechart and highlight 'gcc' tasks: 64 - 65 - $ perf timechart --highlight gcc 66 - 67 46 -n:: 68 47 --proc-num:: 69 48 Print task info for at least given number of tasks. ··· 66 87 -g:: 67 88 --callchain:: 68 89 Do call-graph (stack chain/backtrace) recording 90 + 91 + EXAMPLES 92 + -------- 93 + 94 + $ perf timechart record git pull 95 + 96 + [ perf record: Woken up 13 times to write data ] 97 + [ perf record: Captured and wrote 4.253 MB perf.data (~185801 samples) ] 98 + 99 + $ perf timechart 100 + 101 + Written 10.2 seconds of trace to output.svg. 102 + 103 + Record system-wide timechart: 104 + 105 + $ perf timechart record 106 + 107 + then generate timechart and highlight 'gcc' tasks: 108 + 109 + $ perf timechart --highlight gcc 69 110 70 111 SEE ALSO 71 112 --------
+3 -3
tools/perf/Makefile.perf
··· 819 819 TAG_FILES= ../../include/uapi/linux/perf_event.h 820 820 821 821 TAGS: 822 - $(RM) TAGS 822 + $(QUIET_GEN)$(RM) TAGS; \ 823 823 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs etags -a $(TAG_FILES) 824 824 825 825 tags: 826 - $(RM) tags 826 + $(QUIET_GEN)$(RM) tags; \ 827 827 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs ctags -a $(TAG_FILES) 828 828 829 829 cscope: 830 - $(RM) cscope* 830 + $(QUIET_GEN)$(RM) cscope*; \ 831 831 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs cscope -b $(TAG_FILES) 832 832 833 833 ### Detect prefix changes
+1 -1
tools/perf/builtin-inject.c
··· 72 72 if (ret) 73 73 return ret; 74 74 75 - if (&inject->output.is_pipe) 75 + if (!inject->output.is_pipe) 76 76 return 0; 77 77 78 78 return perf_event__repipe_synth(tool, event);
+14 -9
tools/perf/builtin-probe.c
··· 288 288 memset(&params, 0, sizeof(params)); 289 289 } 290 290 291 + static void pr_err_with_code(const char *msg, int err) 292 + { 293 + pr_err("%s", msg); 294 + pr_debug(" Reason: %s (Code: %d)", strerror(-err), err); 295 + pr_err("\n"); 296 + } 297 + 291 298 static int 292 299 __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) 293 300 { ··· 386 379 } 387 380 ret = parse_probe_event_argv(argc, argv); 388 381 if (ret < 0) { 389 - pr_err(" Error: Parse Error. (%d)\n", ret); 382 + pr_err_with_code(" Error: Command Parse Error.", ret); 390 383 return ret; 391 384 } 392 385 } ··· 426 419 } 427 420 ret = show_perf_probe_events(); 428 421 if (ret < 0) 429 - pr_err(" Error: Failed to show event list. (%d)\n", 430 - ret); 422 + pr_err_with_code(" Error: Failed to show event list.", ret); 431 423 return ret; 432 424 } 433 425 if (params.show_funcs) { ··· 451 445 strfilter__delete(params.filter); 452 446 params.filter = NULL; 453 447 if (ret < 0) 454 - pr_err(" Error: Failed to show functions." 455 - " (%d)\n", ret); 448 + pr_err_with_code(" Error: Failed to show functions.", ret); 456 449 return ret; 457 450 } 458 451 ··· 469 464 470 465 ret = show_line_range(&params.line_range, params.target); 471 466 if (ret < 0) 472 - pr_err(" Error: Failed to show lines. (%d)\n", ret); 467 + pr_err_with_code(" Error: Failed to show lines.", ret); 473 468 return ret; 474 469 } 475 470 if (params.show_vars) { ··· 490 485 strfilter__delete(params.filter); 491 486 params.filter = NULL; 492 487 if (ret < 0) 493 - pr_err(" Error: Failed to show vars. (%d)\n", ret); 488 + pr_err_with_code(" Error: Failed to show vars.", ret); 494 489 return ret; 495 490 } 496 491 #endif ··· 498 493 if (params.dellist) { 499 494 ret = del_perf_probe_events(params.dellist); 500 495 if (ret < 0) { 501 - pr_err(" Error: Failed to delete events. (%d)\n", ret); 496 + pr_err_with_code(" Error: Failed to delete events.", ret); 502 497 return ret; 503 498 } 504 499 } ··· 509 504 params.target, 510 505 params.force_add); 511 506 if (ret < 0) { 512 - pr_err(" Error: Failed to add events. (%d)\n", ret); 507 + pr_err_with_code(" Error: Failed to add events.", ret); 513 508 return ret; 514 509 } 515 510 }
+5 -1
tools/perf/config/Makefile
··· 299 299 NO_LIBUNWIND := 1 300 300 NO_LIBDW_DWARF_UNWIND := 1 301 301 else 302 - msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 302 + ifneq ($(filter s% -static%,$(LDFLAGS),),) 303 + msg := $(error No static glibc found, please install glibc-static); 304 + else 305 + msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]); 306 + endif 303 307 endif 304 308 else 305 309 ifndef NO_LIBDW_DWARF_UNWIND
+1
tools/perf/perf.c
··· 458 458 459 459 /* The page_size is placed in util object. */ 460 460 page_size = sysconf(_SC_PAGE_SIZE); 461 + cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); 461 462 462 463 cmd = perf_extract_argv0_path(argv[0]); 463 464 if (!cmd)
+40 -2
tools/perf/tests/builtin-test.c
··· 3 3 * 4 4 * Builtin regression testing command: ever growing number of sanity tests 5 5 */ 6 + #include <unistd.h> 7 + #include <string.h> 6 8 #include "builtin.h" 7 9 #include "intlist.h" 8 10 #include "tests.h" ··· 52 50 .func = test__pmu, 53 51 }, 54 52 { 55 - .desc = "Test dso data interface", 53 + .desc = "Test dso data read", 56 54 .func = test__dso_data, 55 + }, 56 + { 57 + .desc = "Test dso data cache", 58 + .func = test__dso_data_cache, 59 + }, 60 + { 61 + .desc = "Test dso data reopen", 62 + .func = test__dso_data_reopen, 57 63 }, 58 64 { 59 65 .desc = "roundtrip evsel->name check", ··· 182 172 return false; 183 173 } 184 174 175 + static int run_test(struct test *test) 176 + { 177 + int status, err = -1, child = fork(); 178 + 179 + if (child < 0) { 180 + pr_err("failed to fork test: %s\n", strerror(errno)); 181 + return -1; 182 + } 183 + 184 + if (!child) { 185 + pr_debug("test child forked, pid %d\n", getpid()); 186 + err = test->func(); 187 + exit(err); 188 + } 189 + 190 + wait(&status); 191 + 192 + if (WIFEXITED(status)) { 193 + err = WEXITSTATUS(status); 194 + pr_debug("test child finished with %d\n", err); 195 + } else if (WIFSIGNALED(status)) { 196 + err = -1; 197 + pr_debug("test child interrupted\n"); 198 + } 199 + 200 + return err; 201 + } 202 + 185 203 static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) 186 204 { 187 205 int i = 0; ··· 238 200 } 239 201 240 202 pr_debug("\n--- start ---\n"); 241 - err = tests[curr].func(); 203 + err = run_test(&tests[curr]); 242 204 pr_debug("---- end ----\n%s:", tests[curr].desc); 243 205 244 206 switch (err) {
+210 -4
tools/perf/tests/dso-data.c
··· 1 - #include "util.h" 2 - 3 1 #include <stdlib.h> 4 2 #include <linux/types.h> 5 3 #include <sys/stat.h> 6 4 #include <fcntl.h> 7 5 #include <string.h> 8 - 6 + #include <sys/time.h> 7 + #include <sys/resource.h> 8 + #include <api/fs/fs.h> 9 + #include "util.h" 9 10 #include "machine.h" 10 11 #include "symbol.h" 11 12 #include "tests.h" 12 13 13 14 static char *test_file(int size) 14 15 { 15 - static char buf_templ[] = "/tmp/test-XXXXXX"; 16 + #define TEMPL "/tmp/perf-test-XXXXXX" 17 + static char buf_templ[sizeof(TEMPL)]; 16 18 char *templ = buf_templ; 17 19 int fd, i; 18 20 unsigned char *buf; 21 + 22 + strcpy(buf_templ, TEMPL); 23 + #undef TEMPL 19 24 20 25 fd = mkstemp(templ); 21 26 if (fd < 0) { ··· 153 148 154 149 dso__delete(dso); 155 150 unlink(file); 151 + return 0; 152 + } 153 + 154 + static long open_files_cnt(void) 155 + { 156 + char path[PATH_MAX]; 157 + struct dirent *dent; 158 + DIR *dir; 159 + long nr = 0; 160 + 161 + scnprintf(path, PATH_MAX, "%s/self/fd", procfs__mountpoint()); 162 + pr_debug("fd path: %s\n", path); 163 + 164 + dir = opendir(path); 165 + TEST_ASSERT_VAL("failed to open fd directory", dir); 166 + 167 + while ((dent = readdir(dir)) != NULL) { 168 + if (!strcmp(dent->d_name, ".") || 169 + !strcmp(dent->d_name, "..")) 170 + continue; 171 + 172 + nr++; 173 + } 174 + 175 + closedir(dir); 176 + return nr - 1; 177 + } 178 + 179 + static struct dso **dsos; 180 + 181 + static int dsos__create(int cnt, int size) 182 + { 183 + int i; 184 + 185 + dsos = malloc(sizeof(dsos) * cnt); 186 + TEST_ASSERT_VAL("failed to alloc dsos array", dsos); 187 + 188 + for (i = 0; i < cnt; i++) { 189 + char *file; 190 + 191 + file = test_file(size); 192 + TEST_ASSERT_VAL("failed to get dso file", file); 193 + 194 + dsos[i] = dso__new(file); 195 + TEST_ASSERT_VAL("failed to get dso", dsos[i]); 196 + } 197 + 198 + return 0; 199 + } 200 + 201 + static void dsos__delete(int cnt) 202 + { 203 + int i; 204 + 205 + for (i = 0; i < cnt; i++) { 206 + struct dso *dso = dsos[i]; 207 + 208 + unlink(dso->name); 209 + dso__delete(dso); 210 + } 211 + 212 + free(dsos); 213 + } 214 + 215 + static int set_fd_limit(int n) 216 + { 217 + struct rlimit rlim; 218 + 219 + if (getrlimit(RLIMIT_NOFILE, &rlim)) 220 + return -1; 221 + 222 + pr_debug("file limit %ld, new %d\n", (long) rlim.rlim_cur, n); 223 + 224 + rlim.rlim_cur = n; 225 + return setrlimit(RLIMIT_NOFILE, &rlim); 226 + } 227 + 228 + int test__dso_data_cache(void) 229 + { 230 + struct machine machine; 231 + long nr_end, nr = open_files_cnt(); 232 + int dso_cnt, limit, i, fd; 233 + 234 + memset(&machine, 0, sizeof(machine)); 235 + 236 + /* set as system limit */ 237 + limit = nr * 4; 238 + TEST_ASSERT_VAL("failed to set file limit", !set_fd_limit(limit)); 239 + 240 + /* and this is now our dso open FDs limit + 1 extra */ 241 + dso_cnt = limit / 2 + 1; 242 + TEST_ASSERT_VAL("failed to create dsos\n", 243 + !dsos__create(dso_cnt, TEST_FILE_SIZE)); 244 + 245 + for (i = 0; i < (dso_cnt - 1); i++) { 246 + struct dso *dso = dsos[i]; 247 + 248 + /* 249 + * Open dsos via dso__data_fd or dso__data_read_offset. 250 + * Both opens the data file and keep it open. 251 + */ 252 + if (i % 2) { 253 + fd = dso__data_fd(dso, &machine); 254 + TEST_ASSERT_VAL("failed to get fd", fd > 0); 255 + } else { 256 + #define BUFSIZE 10 257 + u8 buf[BUFSIZE]; 258 + ssize_t n; 259 + 260 + n = dso__data_read_offset(dso, &machine, 0, buf, BUFSIZE); 261 + TEST_ASSERT_VAL("failed to read dso", n == BUFSIZE); 262 + } 263 + } 264 + 265 + /* open +1 dso over the allowed limit */ 266 + fd = dso__data_fd(dsos[i], &machine); 267 + TEST_ASSERT_VAL("failed to get fd", fd > 0); 268 + 269 + /* should force the first one to be closed */ 270 + TEST_ASSERT_VAL("failed to close dsos[0]", dsos[0]->data.fd == -1); 271 + 272 + /* cleanup everything */ 273 + dsos__delete(dso_cnt); 274 + 275 + /* Make sure we did not leak any file descriptor. */ 276 + nr_end = open_files_cnt(); 277 + pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end); 278 + TEST_ASSERT_VAL("failed leadking files", nr == nr_end); 279 + return 0; 280 + } 281 + 282 + int test__dso_data_reopen(void) 283 + { 284 + struct machine machine; 285 + long nr_end, nr = open_files_cnt(); 286 + int fd, fd_extra; 287 + 288 + #define dso_0 (dsos[0]) 289 + #define dso_1 (dsos[1]) 290 + #define dso_2 (dsos[2]) 291 + 292 + memset(&machine, 0, sizeof(machine)); 293 + 294 + /* 295 + * Test scenario: 296 + * - create 3 dso objects 297 + * - set process file descriptor limit to current 298 + * files count + 3 299 + * - test that the first dso gets closed when we 300 + * reach the files count limit 301 + */ 302 + 303 + /* Make sure we are able to open 3 fds anyway */ 304 + TEST_ASSERT_VAL("failed to set file limit", 305 + !set_fd_limit((nr + 3))); 306 + 307 + TEST_ASSERT_VAL("failed to create dsos\n", !dsos__create(3, TEST_FILE_SIZE)); 308 + 309 + /* open dso_0 */ 310 + fd = dso__data_fd(dso_0, &machine); 311 + TEST_ASSERT_VAL("failed to get fd", fd > 0); 312 + 313 + /* open dso_1 */ 314 + fd = dso__data_fd(dso_1, &machine); 315 + TEST_ASSERT_VAL("failed to get fd", fd > 0); 316 + 317 + /* 318 + * open extra file descriptor and we just 319 + * reached the files count limit 320 + */ 321 + fd_extra = open("/dev/null", O_RDONLY); 322 + TEST_ASSERT_VAL("failed to open extra fd", fd_extra > 0); 323 + 324 + /* open dso_2 */ 325 + fd = dso__data_fd(dso_2, &machine); 326 + TEST_ASSERT_VAL("failed to get fd", fd > 0); 327 + 328 + /* 329 + * dso_0 should get closed, because we reached 330 + * the file descriptor limit 331 + */ 332 + TEST_ASSERT_VAL("failed to close dso_0", dso_0->data.fd == -1); 333 + 334 + /* open dso_0 */ 335 + fd = dso__data_fd(dso_0, &machine); 336 + TEST_ASSERT_VAL("failed to get fd", fd > 0); 337 + 338 + /* 339 + * dso_1 should get closed, because we reached 340 + * the file descriptor limit 341 + */ 342 + TEST_ASSERT_VAL("failed to close dso_1", dso_1->data.fd == -1); 343 + 344 + /* cleanup everything */ 345 + close(fd_extra); 346 + dsos__delete(3); 347 + 348 + /* Make sure we did not leak any file descriptor. */ 349 + nr_end = open_files_cnt(); 350 + pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end); 351 + TEST_ASSERT_VAL("failed leadking files", nr == nr_end); 156 352 return 0; 157 353 }
+1 -1
tools/perf/tests/dwarf-unwind.c
··· 15 15 struct perf_sample *sample __maybe_unused, 16 16 struct machine *machine) 17 17 { 18 - return machine__process_mmap_event(machine, event, NULL); 18 + return machine__process_mmap2_event(machine, event, NULL); 19 19 } 20 20 21 21 static int init_live_machine(struct machine *machine)
+2 -5
tools/perf/tests/make
··· 205 205 ( eval $$cmd ) >> $@ 2>&1; \ 206 206 echo " test: $(call test,$@)" >> $@ 2>&1; \ 207 207 $(call test,$@) && \ 208 - rm -f $@ \ 209 - rm -rf $$TMP_DEST 208 + rm -rf $@ $$TMP_DEST || (cat $@ ; false) 210 209 211 210 $(run_O): 212 211 $(call clean) ··· 216 217 ( eval $$cmd ) >> $@ 2>&1 && \ 217 218 echo " test: $(call test_O,$@)" >> $@ 2>&1; \ 218 219 $(call test_O,$@) && \ 219 - rm -f $@ && \ 220 - rm -rf $$TMP_O \ 221 - rm -rf $$TMP_DEST 220 + rm -rf $@ $$TMP_O $$TMP_DEST || (cat $@ ; false) 222 221 223 222 tarpkg: 224 223 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
+2
tools/perf/tests/tests.h
··· 28 28 int test__pmu(void); 29 29 int test__attr(void); 30 30 int test__dso_data(void); 31 + int test__dso_data_cache(void); 32 + int test__dso_data_reopen(void); 31 33 int test__parse_events(void); 32 34 int test__hists_link(void); 33 35 int test__python_use(void);
+254 -25
tools/perf/util/dso.c
··· 1 + #include <asm/bug.h> 2 + #include <sys/time.h> 3 + #include <sys/resource.h> 1 4 #include "symbol.h" 2 5 #include "dso.h" 3 6 #include "machine.h" ··· 139 136 return ret; 140 137 } 141 138 142 - static int open_dso(struct dso *dso, struct machine *machine) 139 + /* 140 + * Global list of open DSOs and the counter. 141 + */ 142 + static LIST_HEAD(dso__data_open); 143 + static long dso__data_open_cnt; 144 + 145 + static void dso__list_add(struct dso *dso) 146 + { 147 + list_add_tail(&dso->data.open_entry, &dso__data_open); 148 + dso__data_open_cnt++; 149 + } 150 + 151 + static void dso__list_del(struct dso *dso) 152 + { 153 + list_del(&dso->data.open_entry); 154 + WARN_ONCE(dso__data_open_cnt <= 0, 155 + "DSO data fd counter out of bounds."); 156 + dso__data_open_cnt--; 157 + } 158 + 159 + static void close_first_dso(void); 160 + 161 + static int do_open(char *name) 162 + { 163 + int fd; 164 + 165 + do { 166 + fd = open(name, O_RDONLY); 167 + if (fd >= 0) 168 + return fd; 169 + 170 + pr_debug("dso open failed, mmap: %s\n", strerror(errno)); 171 + if (!dso__data_open_cnt || errno != EMFILE) 172 + break; 173 + 174 + close_first_dso(); 175 + } while (1); 176 + 177 + return -1; 178 + } 179 + 180 + static int __open_dso(struct dso *dso, struct machine *machine) 143 181 { 144 182 int fd; 145 183 char *root_dir = (char *)""; ··· 198 154 return -EINVAL; 199 155 } 200 156 201 - fd = open(name, O_RDONLY); 157 + fd = do_open(name); 202 158 free(name); 203 159 return fd; 204 160 } 205 161 162 + static void check_data_close(void); 163 + 164 + /** 165 + * dso_close - Open DSO data file 166 + * @dso: dso object 167 + * 168 + * Open @dso's data file descriptor and updates 169 + * list/count of open DSO objects. 170 + */ 171 + static int open_dso(struct dso *dso, struct machine *machine) 172 + { 173 + int fd = __open_dso(dso, machine); 174 + 175 + if (fd > 0) { 176 + dso__list_add(dso); 177 + /* 178 + * Check if we crossed the allowed number 179 + * of opened DSOs and close one if needed. 180 + */ 181 + check_data_close(); 182 + } 183 + 184 + return fd; 185 + } 186 + 187 + static void close_data_fd(struct dso *dso) 188 + { 189 + if (dso->data.fd >= 0) { 190 + close(dso->data.fd); 191 + dso->data.fd = -1; 192 + dso->data.file_size = 0; 193 + dso__list_del(dso); 194 + } 195 + } 196 + 197 + /** 198 + * dso_close - Close DSO data file 199 + * @dso: dso object 200 + * 201 + * Close @dso's data file descriptor and updates 202 + * list/count of open DSO objects. 203 + */ 204 + static void close_dso(struct dso *dso) 205 + { 206 + close_data_fd(dso); 207 + } 208 + 209 + static void close_first_dso(void) 210 + { 211 + struct dso *dso; 212 + 213 + dso = list_first_entry(&dso__data_open, struct dso, data.open_entry); 214 + close_dso(dso); 215 + } 216 + 217 + static rlim_t get_fd_limit(void) 218 + { 219 + struct rlimit l; 220 + rlim_t limit = 0; 221 + 222 + /* Allow half of the current open fd limit. */ 223 + if (getrlimit(RLIMIT_NOFILE, &l) == 0) { 224 + if (l.rlim_cur == RLIM_INFINITY) 225 + limit = l.rlim_cur; 226 + else 227 + limit = l.rlim_cur / 2; 228 + } else { 229 + pr_err("failed to get fd limit\n"); 230 + limit = 1; 231 + } 232 + 233 + return limit; 234 + } 235 + 236 + static bool may_cache_fd(void) 237 + { 238 + static rlim_t limit; 239 + 240 + if (!limit) 241 + limit = get_fd_limit(); 242 + 243 + if (limit == RLIM_INFINITY) 244 + return true; 245 + 246 + return limit > (rlim_t) dso__data_open_cnt; 247 + } 248 + 249 + /* 250 + * Check and close LRU dso if we crossed allowed limit 251 + * for opened dso file descriptors. The limit is half 252 + * of the RLIMIT_NOFILE files opened. 253 + */ 254 + static void check_data_close(void) 255 + { 256 + bool cache_fd = may_cache_fd(); 257 + 258 + if (!cache_fd) 259 + close_first_dso(); 260 + } 261 + 262 + /** 263 + * dso__data_close - Close DSO data file 264 + * @dso: dso object 265 + * 266 + * External interface to close @dso's data file descriptor. 267 + */ 268 + void dso__data_close(struct dso *dso) 269 + { 270 + close_dso(dso); 271 + } 272 + 273 + /** 274 + * dso__data_fd - Get dso's data file descriptor 275 + * @dso: dso object 276 + * @machine: machine object 277 + * 278 + * External interface to find dso's file, open it and 279 + * returns file descriptor. 280 + */ 206 281 int dso__data_fd(struct dso *dso, struct machine *machine) 207 282 { 208 283 enum dso_binary_type binary_type_data[] = { ··· 331 168 }; 332 169 int i = 0; 333 170 334 - if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) 335 - return open_dso(dso, machine); 171 + if (dso->data.fd >= 0) 172 + return dso->data.fd; 173 + 174 + if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) { 175 + dso->data.fd = open_dso(dso, machine); 176 + return dso->data.fd; 177 + } 336 178 337 179 do { 338 180 int fd; ··· 346 178 347 179 fd = open_dso(dso, machine); 348 180 if (fd >= 0) 349 - return fd; 181 + return dso->data.fd = fd; 350 182 351 183 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); 352 184 ··· 428 260 } 429 261 430 262 static ssize_t 431 - dso_cache__read(struct dso *dso, struct machine *machine, 432 - u64 offset, u8 *data, ssize_t size) 263 + dso_cache__read(struct dso *dso, u64 offset, u8 *data, ssize_t size) 433 264 { 434 265 struct dso_cache *cache; 435 266 ssize_t ret; 436 - int fd; 437 - 438 - fd = dso__data_fd(dso, machine); 439 - if (fd < 0) 440 - return -1; 441 267 442 268 do { 443 269 u64 cache_offset; ··· 445 283 cache_offset = offset & DSO__DATA_CACHE_MASK; 446 284 ret = -EINVAL; 447 285 448 - if (-1 == lseek(fd, cache_offset, SEEK_SET)) 286 + if (-1 == lseek(dso->data.fd, cache_offset, SEEK_SET)) 449 287 break; 450 288 451 - ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); 289 + ret = read(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE); 452 290 if (ret <= 0) 453 291 break; 454 292 455 293 cache->offset = cache_offset; 456 294 cache->size = ret; 457 - dso_cache__insert(&dso->cache, cache); 295 + dso_cache__insert(&dso->data.cache, cache); 458 296 459 297 ret = dso_cache__memcpy(cache, offset, data, size); 460 298 ··· 463 301 if (ret <= 0) 464 302 free(cache); 465 303 466 - close(fd); 467 304 return ret; 468 305 } 469 306 470 - static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, 471 - u64 offset, u8 *data, ssize_t size) 307 + static ssize_t dso_cache_read(struct dso *dso, u64 offset, 308 + u8 *data, ssize_t size) 472 309 { 473 310 struct dso_cache *cache; 474 311 475 - cache = dso_cache__find(&dso->cache, offset); 312 + cache = dso_cache__find(&dso->data.cache, offset); 476 313 if (cache) 477 314 return dso_cache__memcpy(cache, offset, data, size); 478 315 else 479 - return dso_cache__read(dso, machine, offset, data, size); 316 + return dso_cache__read(dso, offset, data, size); 480 317 } 481 318 482 - ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 483 - u64 offset, u8 *data, ssize_t size) 319 + /* 320 + * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks 321 + * in the rb_tree. Any read to already cached data is served 322 + * by cached data. 323 + */ 324 + static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size) 484 325 { 485 326 ssize_t r = 0; 486 327 u8 *p = data; ··· 491 326 do { 492 327 ssize_t ret; 493 328 494 - ret = dso_cache_read(dso, machine, offset, p, size); 329 + ret = dso_cache_read(dso, offset, p, size); 495 330 if (ret < 0) 496 331 return ret; 497 332 ··· 511 346 return r; 512 347 } 513 348 349 + static int data_file_size(struct dso *dso) 350 + { 351 + struct stat st; 352 + 353 + if (!dso->data.file_size) { 354 + if (fstat(dso->data.fd, &st)) { 355 + pr_err("dso mmap failed, fstat: %s\n", strerror(errno)); 356 + return -1; 357 + } 358 + dso->data.file_size = st.st_size; 359 + } 360 + 361 + return 0; 362 + } 363 + 364 + static ssize_t data_read_offset(struct dso *dso, u64 offset, 365 + u8 *data, ssize_t size) 366 + { 367 + if (data_file_size(dso)) 368 + return -1; 369 + 370 + /* Check the offset sanity. */ 371 + if (offset > dso->data.file_size) 372 + return -1; 373 + 374 + if (offset + size < offset) 375 + return -1; 376 + 377 + return cached_read(dso, offset, data, size); 378 + } 379 + 380 + /** 381 + * dso__data_read_offset - Read data from dso file offset 382 + * @dso: dso object 383 + * @machine: machine object 384 + * @offset: file offset 385 + * @data: buffer to store data 386 + * @size: size of the @data buffer 387 + * 388 + * External interface to read data from dso file offset. Open 389 + * dso data file and use cached_read to get the data. 390 + */ 391 + ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 392 + u64 offset, u8 *data, ssize_t size) 393 + { 394 + if (dso__data_fd(dso, machine) < 0) 395 + return -1; 396 + 397 + return data_read_offset(dso, offset, data, size); 398 + } 399 + 400 + /** 401 + * dso__data_read_addr - Read data from dso address 402 + * @dso: dso object 403 + * @machine: machine object 404 + * @add: virtual memory address 405 + * @data: buffer to store data 406 + * @size: size of the @data buffer 407 + * 408 + * External interface to read data from dso address. 409 + */ 514 410 ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 515 411 struct machine *machine, u64 addr, 516 412 u8 *data, ssize_t size) ··· 699 473 dso__set_short_name(dso, dso->name, false); 700 474 for (i = 0; i < MAP__NR_TYPES; ++i) 701 475 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 702 - dso->cache = RB_ROOT; 476 + dso->data.cache = RB_ROOT; 477 + dso->data.fd = -1; 703 478 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 704 479 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; 705 480 dso->loaded = 0; ··· 712 485 dso->kernel = DSO_TYPE_USER; 713 486 dso->needs_swap = DSO_SWAP__UNSET; 714 487 INIT_LIST_HEAD(&dso->node); 488 + INIT_LIST_HEAD(&dso->data.open_entry); 715 489 } 716 490 717 491 return dso; ··· 734 506 dso->long_name_allocated = false; 735 507 } 736 508 737 - dso_cache__free(&dso->cache); 509 + dso__data_close(dso); 510 + dso_cache__free(&dso->data.cache); 738 511 dso__free_a2l(dso); 739 512 zfree(&dso->symsrc_filename); 740 513 free(dso);
+49 -1
tools/perf/util/dso.h
··· 76 76 struct list_head node; 77 77 struct rb_root symbols[MAP__NR_TYPES]; 78 78 struct rb_root symbol_names[MAP__NR_TYPES]; 79 - struct rb_root cache; 80 79 void *a2l; 81 80 char *symsrc_filename; 82 81 unsigned int a2l_fails; ··· 98 99 const char *long_name; 99 100 u16 long_name_len; 100 101 u16 short_name_len; 102 + 103 + /* dso data file */ 104 + struct { 105 + struct rb_root cache; 106 + int fd; 107 + size_t file_size; 108 + struct list_head open_entry; 109 + } data; 110 + 101 111 char name[0]; 102 112 }; 103 113 ··· 149 141 int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, 150 142 char *root_dir, char *filename, size_t size); 151 143 144 + /* 145 + * The dso__data_* external interface provides following functions: 146 + * dso__data_fd 147 + * dso__data_close 148 + * dso__data_read_offset 149 + * dso__data_read_addr 150 + * 151 + * Please refer to the dso.c object code for each function and 152 + * arguments documentation. Following text tries to explain the 153 + * dso file descriptor caching. 154 + * 155 + * The dso__data* interface allows caching of opened file descriptors 156 + * to speed up the dso data accesses. The idea is to leave the file 157 + * descriptor opened ideally for the whole life of the dso object. 158 + * 159 + * The current usage of the dso__data_* interface is as follows: 160 + * 161 + * Get DSO's fd: 162 + * int fd = dso__data_fd(dso, machine); 163 + * USE 'fd' SOMEHOW 164 + * 165 + * Read DSO's data: 166 + * n = dso__data_read_offset(dso_0, &machine, 0, buf, BUFSIZE); 167 + * n = dso__data_read_addr(dso_0, &machine, 0, buf, BUFSIZE); 168 + * 169 + * Eventually close DSO's fd: 170 + * dso__data_close(dso); 171 + * 172 + * It is not necessary to close the DSO object data file. Each time new 173 + * DSO data file is opened, the limit (RLIMIT_NOFILE/2) is checked. Once 174 + * it is crossed, the oldest opened DSO object is closed. 175 + * 176 + * The dso__delete function calls close_dso function to ensure the 177 + * data file descriptor gets closed/unmapped before the dso object 178 + * is freed. 179 + * 180 + * TODO 181 + */ 152 182 int dso__data_fd(struct dso *dso, struct machine *machine); 183 + void dso__data_close(struct dso *dso); 184 + 153 185 ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 154 186 u64 offset, u8 *data, ssize_t size); 155 187 ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
+41 -16
tools/perf/util/event.c
··· 1 1 #include <linux/types.h> 2 + #include <sys/mman.h> 2 3 #include "event.h" 3 4 #include "debug.h" 4 5 #include "hist.h" ··· 179 178 return -1; 180 179 } 181 180 182 - event->header.type = PERF_RECORD_MMAP; 181 + event->header.type = PERF_RECORD_MMAP2; 183 182 184 183 while (1) { 185 184 char bf[BUFSIZ]; 186 185 char prot[5]; 187 186 char execname[PATH_MAX]; 188 187 char anonstr[] = "//anon"; 188 + unsigned int ino; 189 189 size_t size; 190 190 ssize_t n; 191 191 ··· 197 195 strcpy(execname, ""); 198 196 199 197 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 200 - n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", 201 - &event->mmap.start, &event->mmap.len, prot, 202 - &event->mmap.pgoff, 203 - execname); 198 + n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n", 199 + &event->mmap2.start, &event->mmap2.len, prot, 200 + &event->mmap2.pgoff, &event->mmap2.maj, 201 + &event->mmap2.min, 202 + &ino, execname); 203 + 204 204 /* 205 205 * Anon maps don't have the execname. 206 206 */ 207 - if (n < 4) 207 + if (n < 7) 208 208 continue; 209 + 210 + event->mmap2.ino = (u64)ino; 211 + 209 212 /* 210 213 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 211 214 */ ··· 218 211 event->header.misc = PERF_RECORD_MISC_USER; 219 212 else 220 213 event->header.misc = PERF_RECORD_MISC_GUEST_USER; 214 + 215 + /* map protection and flags bits */ 216 + event->mmap2.prot = 0; 217 + event->mmap2.flags = 0; 218 + if (prot[0] == 'r') 219 + event->mmap2.prot |= PROT_READ; 220 + if (prot[1] == 'w') 221 + event->mmap2.prot |= PROT_WRITE; 222 + if (prot[2] == 'x') 223 + event->mmap2.prot |= PROT_EXEC; 224 + 225 + if (prot[3] == 's') 226 + event->mmap2.flags |= MAP_SHARED; 227 + else 228 + event->mmap2.flags |= MAP_PRIVATE; 221 229 222 230 if (prot[2] != 'x') { 223 231 if (!mmap_data || prot[0] != 'r') ··· 245 223 strcpy(execname, anonstr); 246 224 247 225 size = strlen(execname) + 1; 248 - memcpy(event->mmap.filename, execname, size); 226 + memcpy(event->mmap2.filename, execname, size); 249 227 size = PERF_ALIGN(size, sizeof(u64)); 250 - event->mmap.len -= event->mmap.start; 251 - event->mmap.header.size = (sizeof(event->mmap) - 252 - (sizeof(event->mmap.filename) - size)); 253 - memset(event->mmap.filename + size, 0, machine->id_hdr_size); 254 - event->mmap.header.size += machine->id_hdr_size; 255 - event->mmap.pid = tgid; 256 - event->mmap.tid = pid; 228 + event->mmap2.len -= event->mmap.start; 229 + event->mmap2.header.size = (sizeof(event->mmap2) - 230 + (sizeof(event->mmap2.filename) - size)); 231 + memset(event->mmap2.filename + size, 0, machine->id_hdr_size); 232 + event->mmap2.header.size += machine->id_hdr_size; 233 + event->mmap2.pid = tgid; 234 + event->mmap2.tid = pid; 257 235 258 236 if (process(tool, event, &synth_sample, machine) != 0) { 259 237 rc = -1; ··· 634 612 size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) 635 613 { 636 614 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 637 - " %02x:%02x %"PRIu64" %"PRIu64"]: %c %s\n", 615 + " %02x:%02x %"PRIu64" %"PRIu64"]: %c%c%c%c %s\n", 638 616 event->mmap2.pid, event->mmap2.tid, event->mmap2.start, 639 617 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, 640 618 event->mmap2.min, event->mmap2.ino, 641 619 event->mmap2.ino_generation, 642 - (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x', 620 + (event->mmap2.prot & PROT_READ) ? 'r' : '-', 621 + (event->mmap2.prot & PROT_WRITE) ? 'w' : '-', 622 + (event->mmap2.prot & PROT_EXEC) ? 'x' : '-', 623 + (event->mmap2.flags & MAP_SHARED) ? 's' : 'p', 643 624 event->mmap2.filename); 644 625 } 645 626
+7
tools/perf/util/event.h
··· 7 7 #include "../perf.h" 8 8 #include "map.h" 9 9 #include "build-id.h" 10 + #include "perf_regs.h" 10 11 11 12 struct mmap_event { 12 13 struct perf_event_header header; ··· 28 27 u32 min; 29 28 u64 ino; 30 29 u64 ino_generation; 30 + u32 prot; 31 + u32 flags; 31 32 char filename[PATH_MAX]; 32 33 }; 33 34 ··· 90 87 u64 abi; 91 88 u64 mask; 92 89 u64 *regs; 90 + 91 + /* Cached values/mask filled by first register access. */ 92 + u64 cache_regs[PERF_REGS_MAX]; 93 + u64 cache_mask; 93 94 }; 94 95 95 96 struct stack_dump {
+3 -2
tools/perf/util/evsel.c
··· 589 589 } 590 590 591 591 /* 592 - * We default some events to a 1 default interval. But keep 592 + * We default some events to have a default interval. But keep 593 593 * it a weak assumption overridable by the user. 594 594 */ 595 - if (!attr->sample_period || (opts->user_freq != UINT_MAX && 595 + if (!attr->sample_period || (opts->user_freq != UINT_MAX || 596 596 opts->user_interval != ULLONG_MAX)) { 597 597 if (opts->freq) { 598 598 perf_evsel__set_sample_bit(evsel, PERIOD); ··· 659 659 perf_evsel__set_sample_bit(evsel, WEIGHT); 660 660 661 661 attr->mmap = track; 662 + attr->mmap2 = track && !perf_missing_features.mmap2; 662 663 attr->comm = track; 663 664 664 665 if (opts->sample_transaction)
+6 -3
tools/perf/util/hist.c
··· 128 128 + unresolved_col_width + 2; 129 129 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 130 130 symlen); 131 + hists__new_col_len(hists, HISTC_MEM_DCACHELINE, 132 + symlen + 1); 131 133 } else { 132 134 symlen = unresolved_col_width + 4 + 2; 133 135 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, ··· 441 439 .map = al->map, 442 440 .sym = al->sym, 443 441 }, 444 - .cpu = al->cpu, 445 - .ip = al->addr, 446 - .level = al->level, 442 + .cpu = al->cpu, 443 + .cpumode = al->cpumode, 444 + .ip = al->addr, 445 + .level = al->level, 447 446 .stat = { 448 447 .nr_events = 1, 449 448 .period = period,
+1
tools/perf/util/hist.h
··· 72 72 HISTC_MEM_TLB, 73 73 HISTC_MEM_LVL, 74 74 HISTC_MEM_SNOOP, 75 + HISTC_MEM_DCACHELINE, 75 76 HISTC_TRANSACTION, 76 77 HISTC_NR_COLS, /* Last entry */ 77 78 };
+3 -1
tools/perf/util/machine.c
··· 1060 1060 event->mmap2.pid, event->mmap2.maj, 1061 1061 event->mmap2.min, event->mmap2.ino, 1062 1062 event->mmap2.ino_generation, 1063 + event->mmap2.prot, 1064 + event->mmap2.flags, 1063 1065 event->mmap2.filename, type); 1064 1066 1065 1067 if (map == NULL) ··· 1107 1105 1108 1106 map = map__new(&machine->user_dsos, event->mmap.start, 1109 1107 event->mmap.len, event->mmap.pgoff, 1110 - event->mmap.pid, 0, 0, 0, 0, 1108 + event->mmap.pid, 0, 0, 0, 0, 0, 0, 1111 1109 event->mmap.filename, 1112 1110 type); 1113 1111
+3 -1
tools/perf/util/map.c
··· 138 138 139 139 struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 140 140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 141 - u64 ino_gen, char *filename, 141 + u64 ino_gen, u32 prot, u32 flags, char *filename, 142 142 enum map_type type) 143 143 { 144 144 struct map *map = malloc(sizeof(*map)); ··· 157 157 map->min = d_min; 158 158 map->ino = ino; 159 159 map->ino_generation = ino_gen; 160 + map->prot = prot; 161 + map->flags = flags; 160 162 161 163 if ((anon || no_dso) && type == MAP__FUNCTION) { 162 164 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
+3 -1
tools/perf/util/map.h
··· 35 35 bool referenced; 36 36 bool erange_warned; 37 37 u32 priv; 38 + u32 prot; 39 + u32 flags; 38 40 u64 pgoff; 39 41 u64 reloc; 40 42 u32 maj, min; /* only valid for MMAP2 record */ ··· 120 118 u64 start, u64 end, u64 pgoff, struct dso *dso); 121 119 struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 122 120 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 123 - u64 ino_gen, 121 + u64 ino_gen, u32 prot, u32 flags, 124 122 char *filename, enum map_type type); 125 123 struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 126 124 void map__delete(struct map *map);
+9 -1
tools/perf/util/perf_regs.c
··· 1 1 #include <errno.h> 2 2 #include "perf_regs.h" 3 + #include "event.h" 3 4 4 5 int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) 5 6 { 6 7 int i, idx = 0; 7 8 u64 mask = regs->mask; 9 + 10 + if (regs->cache_mask & (1 << id)) 11 + goto out; 8 12 9 13 if (!(mask & (1 << id))) 10 14 return -EINVAL; ··· 18 14 idx++; 19 15 } 20 16 21 - *valp = regs->regs[idx]; 17 + regs->cache_mask |= (1 << id); 18 + regs->cache_regs[id] = regs->regs[idx]; 19 + 20 + out: 21 + *valp = regs->cache_regs[id]; 22 22 return 0; 23 23 }
+3 -1
tools/perf/util/perf_regs.h
··· 2 2 #define __PERF_REGS_H 3 3 4 4 #include <linux/types.h> 5 - #include "event.h" 5 + 6 + struct regs_dump; 6 7 7 8 #ifdef HAVE_PERF_REGS_SUPPORT 8 9 #include <perf_regs.h> ··· 12 11 13 12 #else 14 13 #define PERF_REGS_MASK 0 14 + #define PERF_REGS_MAX 0 15 15 16 16 static inline const char *perf_reg_name(int id __maybe_unused) 17 17 {
+9 -4
tools/perf/util/probe-event.c
··· 628 628 629 629 ret = debuginfo__find_line_range(dinfo, lr); 630 630 debuginfo__delete(dinfo); 631 - if (ret == 0) { 631 + if (ret == 0 || ret == -ENOENT) { 632 632 pr_warning("Specified source line is not found.\n"); 633 633 return -ENOENT; 634 634 } else if (ret < 0) { 635 - pr_warning("Debuginfo analysis failed. (%d)\n", ret); 635 + pr_warning("Debuginfo analysis failed.\n"); 636 636 return ret; 637 637 } 638 638 ··· 641 641 ret = get_real_path(tmp, lr->comp_dir, &lr->path); 642 642 free(tmp); /* Free old path */ 643 643 if (ret < 0) { 644 - pr_warning("Failed to find source file. (%d)\n", ret); 644 + pr_warning("Failed to find source file path.\n"); 645 645 return ret; 646 646 } 647 647 ··· 721 721 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, 722 722 max_vls, externs); 723 723 if (ret <= 0) { 724 - pr_err("Failed to find variables at %s (%d)\n", buf, ret); 724 + if (ret == 0 || ret == -ENOENT) { 725 + pr_err("Failed to find the address of %s\n", buf); 726 + ret = -ENOENT; 727 + } else 728 + pr_warning("Debuginfo analysis failed.\n"); 725 729 goto end; 726 730 } 731 + 727 732 /* Some variables are found */ 728 733 fprintf(stdout, "Available variables at %s\n", buf); 729 734 for (i = 0; i < ret; i++) {
+7 -4
tools/perf/util/probe-finder.c
··· 573 573 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 574 574 /* Search again in global variables */ 575 575 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 576 + pr_warning("Failed to find '%s' in this function.\n", 577 + pf->pvar->var); 576 578 ret = -ENOENT; 577 579 } 578 580 if (ret >= 0) 579 581 ret = convert_variable(&vr_die, pf); 580 582 581 - if (ret < 0) 582 - pr_warning("Failed to find '%s' in this function.\n", 583 - pf->pvar->var); 584 583 return ret; 585 584 } 586 585 ··· 1280 1281 return ret; 1281 1282 } 1282 1283 1283 - /* Find available variables at given probe point */ 1284 + /* 1285 + * Find available variables at given probe point 1286 + * Return the number of found probe points. Return 0 if there is no 1287 + * matched probe point. Return <0 if an error occurs. 1288 + */ 1284 1289 int debuginfo__find_available_vars_at(struct debuginfo *dbg, 1285 1290 struct perf_probe_event *pev, 1286 1291 struct variable_list **vls,
+1
tools/perf/util/scripting-engines/trace-event-perl.c
··· 215 215 case PRINT_BSTRING: 216 216 case PRINT_DYNAMIC_ARRAY: 217 217 case PRINT_STRING: 218 + case PRINT_BITMASK: 218 219 break; 219 220 case PRINT_TYPE: 220 221 define_event_symbols(event, ev_name, args->typecast.item);
+2
tools/perf/util/scripting-engines/trace-event-python.c
··· 197 197 case PRINT_BSTRING: 198 198 case PRINT_DYNAMIC_ARRAY: 199 199 case PRINT_FUNC: 200 + case PRINT_BITMASK: 200 201 /* we should warn... */ 201 202 return; 202 203 } ··· 623 622 fprintf(ofp, "%s=", f->name); 624 623 if (f->flags & FIELD_IS_STRING || 625 624 f->flags & FIELD_IS_FLAG || 625 + f->flags & FIELD_IS_ARRAY || 626 626 f->flags & FIELD_IS_SYMBOLIC) 627 627 fprintf(ofp, "%%s"); 628 628 else if (f->flags & FIELD_IS_SIGNED)
+107
tools/perf/util/sort.c
··· 1 + #include <sys/mman.h> 1 2 #include "sort.h" 2 3 #include "hist.h" 3 4 #include "comm.h" ··· 785 784 return repsep_snprintf(bf, size, "%-*s", width, out); 786 785 } 787 786 787 + static inline u64 cl_address(u64 address) 788 + { 789 + /* return the cacheline of the address */ 790 + return (address & ~(cacheline_size - 1)); 791 + } 792 + 793 + static int64_t 794 + sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) 795 + { 796 + u64 l, r; 797 + struct map *l_map, *r_map; 798 + 799 + if (!left->mem_info) return -1; 800 + if (!right->mem_info) return 1; 801 + 802 + /* group event types together */ 803 + if (left->cpumode > right->cpumode) return -1; 804 + if (left->cpumode < right->cpumode) return 1; 805 + 806 + l_map = left->mem_info->daddr.map; 807 + r_map = right->mem_info->daddr.map; 808 + 809 + /* if both are NULL, jump to sort on al_addr instead */ 810 + if (!l_map && !r_map) 811 + goto addr; 812 + 813 + if (!l_map) return -1; 814 + if (!r_map) return 1; 815 + 816 + if (l_map->maj > r_map->maj) return -1; 817 + if (l_map->maj < r_map->maj) return 1; 818 + 819 + if (l_map->min > r_map->min) return -1; 820 + if (l_map->min < r_map->min) return 1; 821 + 822 + if (l_map->ino > r_map->ino) return -1; 823 + if (l_map->ino < r_map->ino) return 1; 824 + 825 + if (l_map->ino_generation > r_map->ino_generation) return -1; 826 + if (l_map->ino_generation < r_map->ino_generation) return 1; 827 + 828 + /* 829 + * Addresses with no major/minor numbers are assumed to be 830 + * anonymous in userspace. Sort those on pid then address. 831 + * 832 + * The kernel and non-zero major/minor mapped areas are 833 + * assumed to be unity mapped. Sort those on address. 834 + */ 835 + 836 + if ((left->cpumode != PERF_RECORD_MISC_KERNEL) && 837 + (!(l_map->flags & MAP_SHARED)) && 838 + !l_map->maj && !l_map->min && !l_map->ino && 839 + !l_map->ino_generation) { 840 + /* userspace anonymous */ 841 + 842 + if (left->thread->pid_ > right->thread->pid_) return -1; 843 + if (left->thread->pid_ < right->thread->pid_) return 1; 844 + } 845 + 846 + addr: 847 + /* al_addr does all the right addr - start + offset calculations */ 848 + l = cl_address(left->mem_info->daddr.al_addr); 849 + r = cl_address(right->mem_info->daddr.al_addr); 850 + 851 + if (l > r) return -1; 852 + if (l < r) return 1; 853 + 854 + return 0; 855 + } 856 + 857 + static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf, 858 + size_t size, unsigned int width) 859 + { 860 + 861 + uint64_t addr = 0; 862 + struct map *map = NULL; 863 + struct symbol *sym = NULL; 864 + char level = he->level; 865 + 866 + if (he->mem_info) { 867 + addr = cl_address(he->mem_info->daddr.al_addr); 868 + map = he->mem_info->daddr.map; 869 + sym = he->mem_info->daddr.sym; 870 + 871 + /* print [s] for shared data mmaps */ 872 + if ((he->cpumode != PERF_RECORD_MISC_KERNEL) && 873 + map && (map->type == MAP__VARIABLE) && 874 + (map->flags & MAP_SHARED) && 875 + (map->maj || map->min || map->ino || 876 + map->ino_generation)) 877 + level = 's'; 878 + else if (!map) 879 + level = 'X'; 880 + } 881 + return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size, 882 + width); 883 + } 884 + 788 885 struct sort_entry sort_mispredict = { 789 886 .se_header = "Branch Mispredicted", 790 887 .se_cmp = sort__mispredict_cmp, ··· 973 874 .se_cmp = sort__snoop_cmp, 974 875 .se_snprintf = hist_entry__snoop_snprintf, 975 876 .se_width_idx = HISTC_MEM_SNOOP, 877 + }; 878 + 879 + struct sort_entry sort_mem_dcacheline = { 880 + .se_header = "Data Cacheline", 881 + .se_cmp = sort__dcacheline_cmp, 882 + .se_snprintf = hist_entry__dcacheline_snprintf, 883 + .se_width_idx = HISTC_MEM_DCACHELINE, 976 884 }; 977 885 978 886 static int64_t ··· 1149 1043 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), 1150 1044 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), 1151 1045 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), 1046 + DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline), 1152 1047 }; 1153 1048 1154 1049 #undef DIM
+2
tools/perf/util/sort.h
··· 89 89 u64 ip; 90 90 u64 transaction; 91 91 s32 cpu; 92 + u8 cpumode; 92 93 93 94 struct hist_entry_diff diff; 94 95 ··· 186 185 SORT_MEM_TLB, 187 186 SORT_MEM_LVL, 188 187 SORT_MEM_SNOOP, 188 + SORT_MEM_DCACHELINE, 189 189 }; 190 190 191 191 /*
-2
tools/perf/util/unwind-libunwind.c
··· 250 250 251 251 /* Check the .eh_frame section for unwinding info */ 252 252 offset = elf_section_offset(fd, ".eh_frame_hdr"); 253 - close(fd); 254 253 255 254 if (offset) 256 255 ret = unwind_spec_ehframe(dso, machine, offset, ··· 270 271 271 272 /* Check the .debug_frame section for unwinding info */ 272 273 *offset = elf_section_offset(fd, ".debug_frame"); 273 - close(fd); 274 274 275 275 if (*offset) 276 276 return 0;
+1
tools/perf/util/util.c
··· 17 17 * XXX We need to find a better place for these things... 18 18 */ 19 19 unsigned int page_size; 20 + int cacheline_size; 20 21 21 22 bool test_attr__enabled; 22 23
+1
tools/perf/util/util.h
··· 304 304 void dump_stack(void); 305 305 306 306 extern unsigned int page_size; 307 + extern int cacheline_size; 307 308 308 309 void get_term_dimensions(struct winsize *ws); 309 310