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

tools lib traceevent: Added support for __get_bitmask() macro

Coming in v3.16, trace events will be able to save bitmasks in raw
format in the ring buffer and output it with the __get_bitmask() macro.

In order for userspace tools to parse this, it must be able to handle
the __get_bitmask() call and be able to convert the data that's in
the ring buffer into a nice bitmask format. The output is similar to
what the kernel uses to print bitmasks, with a comma separator every
4 bytes (8 characters).

This allows for cpumasks to also be saved efficiently.

The first user is the thermal:thermal_power_limit event which has the
following output:

thermal_power_limit: cpus=0000000f freq=1900000 cdev_state=0 power=5252

Link: http://lkml.kernel.org/r/20140506132238.22e136d1@gandalf.local.home

Suggested-by: Javi Merino <javi.merino@arm.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Javi Merino <javi.merino@arm.com>
Link: http://lkml.kernel.org/r/20140603032224.229186537@goodmis.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>

authored by

Steven Rostedt (Red Hat) and committed by
Jiri Olsa
473a778a 49440828

+122
+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);
+7
tools/lib/traceevent/event-parse.h
··· 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 };
+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);
+1
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 }