Loading include/linux/interrupt.h +1 −1 Original line number Diff line number Diff line Loading @@ -410,7 +410,7 @@ extern void open_softirq(int nr, void (*action)(struct softirq_action *)); extern void softirq_init(void); static inline void __raise_softirq_irqoff(unsigned int nr) { trace_softirq_raise((struct softirq_action *)(unsigned long)nr, NULL); trace_softirq_raise(nr); or_softirq_pending(1UL << nr); } Loading include/trace/events/irq.h +20 −34 Original line number Diff line number Diff line Loading @@ -86,76 +86,62 @@ TRACE_EVENT(irq_handler_exit, DECLARE_EVENT_CLASS(softirq, TP_PROTO(struct softirq_action *h, struct softirq_action *vec), TP_PROTO(unsigned int vec_nr), TP_ARGS(h, vec), TP_ARGS(vec_nr), TP_STRUCT__entry( __field( int, vec ) __field( unsigned int, vec ) ), TP_fast_assign( if (vec) __entry->vec = (int)(h - vec); else __entry->vec = (int)(long)h; __entry->vec = vec_nr; ), TP_printk("vec=%d [action=%s]", __entry->vec, TP_printk("vec=%u [action=%s]", __entry->vec, show_softirq_name(__entry->vec)) ); /** * softirq_entry - called immediately before the softirq handler * @h: pointer to struct softirq_action * @vec: pointer to first struct softirq_action in softirq_vec array * @vec_nr: softirq vector number * * The @h parameter, contains a pointer to the struct softirq_action * which has a pointer to the action handler that is called. By subtracting * the @vec pointer from the @h pointer, we can determine the softirq * number. Also, when used in combination with the softirq_exit tracepoint * we can determine the softirq latency. * When used in combination with the softirq_exit tracepoint * we can determine the softirq handler runtine. */ DEFINE_EVENT(softirq, softirq_entry, TP_PROTO(struct softirq_action *h, struct softirq_action *vec), TP_PROTO(unsigned int vec_nr), TP_ARGS(h, vec) TP_ARGS(vec_nr) ); /** * softirq_exit - called immediately after the softirq handler returns * @h: pointer to struct softirq_action * @vec: pointer to first struct softirq_action in softirq_vec array * @vec_nr: softirq vector number * * The @h parameter contains a pointer to the struct softirq_action * that has handled the softirq. By subtracting the @vec pointer from * the @h pointer, we can determine the softirq number. Also, when used in * combination with the softirq_entry tracepoint we can determine the softirq * latency. * When used in combination with the softirq_entry tracepoint * we can determine the softirq handler runtine. */ DEFINE_EVENT(softirq, softirq_exit, TP_PROTO(struct softirq_action *h, struct softirq_action *vec), TP_PROTO(unsigned int vec_nr), TP_ARGS(h, vec) TP_ARGS(vec_nr) ); /** * softirq_raise - called immediately when a softirq is raised * @h: pointer to struct softirq_action * @vec: pointer to first struct softirq_action in softirq_vec array * @vec_nr: softirq vector number * * The @h parameter contains a pointer to the softirq vector number which is * raised. @vec is NULL and it means @h includes vector number not * softirq_action. When used in combination with the softirq_entry tracepoint * we can determine the softirq raise latency. * When used in combination with the softirq_entry tracepoint * we can determine the softirq raise to run latency. */ DEFINE_EVENT(softirq, softirq_raise, TP_PROTO(struct softirq_action *h, struct softirq_action *vec), TP_PROTO(unsigned int vec_nr), TP_ARGS(h, vec) TP_ARGS(vec_nr) ); #endif /* _TRACE_IRQ_H */ Loading kernel/softirq.c +9 −7 Original line number Diff line number Diff line Loading @@ -229,18 +229,20 @@ asmlinkage void __do_softirq(void) do { if (pending & 1) { unsigned int vec_nr = h - softirq_vec; int prev_count = preempt_count(); kstat_incr_softirqs_this_cpu(h - softirq_vec); trace_softirq_entry(h, softirq_vec); kstat_incr_softirqs_this_cpu(vec_nr); trace_softirq_entry(vec_nr); h->action(h); trace_softirq_exit(h, softirq_vec); trace_softirq_exit(vec_nr); if (unlikely(prev_count != preempt_count())) { printk(KERN_ERR "huh, entered softirq %td %s %p" printk(KERN_ERR "huh, entered softirq %u %s %p" "with preempt_count %08x," " exited with %08x?\n", h - softirq_vec, softirq_to_name[h - softirq_vec], h->action, prev_count, preempt_count()); " exited with %08x?\n", vec_nr, softirq_to_name[vec_nr], h->action, prev_count, preempt_count()); preempt_count() = prev_count; } Loading tools/perf/Documentation/perf-probe.txt +17 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ or or 'perf probe' --list or 'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' 'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' or 'perf probe' [options] --vars='PROBEPOINT' DESCRIPTION ----------- Loading @@ -31,6 +33,11 @@ OPTIONS --vmlinux=PATH:: Specify vmlinux path which has debuginfo (Dwarf binary). -m:: --module=MODNAME:: Specify module name in which perf-probe searches probe points or lines. -s:: --source=PATH:: Specify path to kernel source. Loading @@ -57,6 +64,15 @@ OPTIONS Show source code lines which can be probed. This needs an argument which specifies a range of the source code. (see LINE SYNTAX for detail) -V:: --vars=:: Show available local variables at given probe point. The argument syntax is same as PROBE SYNTAX, but NO ARGs. --externs:: (Only for --vars) Show external defined variables in addition to local variables. -f:: --force:: Forcibly add events with existing name. Loading tools/perf/builtin-probe.c +67 −11 Original line number Diff line number Diff line Loading @@ -50,14 +50,17 @@ static struct { bool list_events; bool force_add; bool show_lines; bool show_vars; bool show_ext_vars; bool mod_events; int nevents; struct perf_probe_event events[MAX_PROBES]; struct strlist *dellist; struct line_range line_range; const char *target_module; int max_probe_points; } params; /* Parse an event definition. Note that any error must die. */ static int parse_probe_event(const char *str) { Loading Loading @@ -92,6 +95,7 @@ static int parse_probe_event_argv(int argc, const char **argv) len = 0; for (i = 0; i < argc; i++) len += sprintf(&buf[len], "%s ", argv[i]); params.mod_events = true; ret = parse_probe_event(buf); free(buf); return ret; Loading @@ -100,9 +104,10 @@ static int parse_probe_event_argv(int argc, const char **argv) static int opt_add_probe_event(const struct option *opt __used, const char *str, int unset __used) { if (str) if (str) { params.mod_events = true; return parse_probe_event(str); else } else return 0; } Loading @@ -110,6 +115,7 @@ static int opt_del_probe_event(const struct option *opt __used, const char *str, int unset __used) { if (str) { params.mod_events = true; if (!params.dellist) params.dellist = strlist__new(true, NULL); strlist__add(params.dellist, str); Loading @@ -130,6 +136,25 @@ static int opt_show_lines(const struct option *opt __used, return ret; } static int opt_show_vars(const struct option *opt __used, const char *str, int unset __used) { struct perf_probe_event *pev = ¶ms.events[params.nevents]; int ret; if (!str) return 0; ret = parse_probe_event(str); if (!ret && pev->nargs != 0) { pr_err(" Error: '--vars' doesn't accept arguments.\n"); return -EINVAL; } params.show_vars = true; return ret; } #endif static const char * const probe_usage[] = { Loading @@ -138,7 +163,8 @@ static const char * const probe_usage[] = { "perf probe [<options>] --del '[GROUP:]EVENT' ...", "perf probe --list", #ifdef DWARF_SUPPORT "perf probe --line 'LINEDESC'", "perf probe [<options>] --line 'LINEDESC'", "perf probe [<options>] --vars 'PROBEPOINT'", #endif NULL }; Loading Loading @@ -180,10 +206,17 @@ static const struct option options[] = { OPT_CALLBACK('L', "line", NULL, "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", "Show source code lines.", opt_show_lines), OPT_CALLBACK('V', "vars", NULL, "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT", "Show accessible variables on PROBEDEF", opt_show_vars), OPT_BOOLEAN('\0', "externs", ¶ms.show_ext_vars, "Show external variables too (with --vars only)"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), OPT_STRING('s', "source", &symbol_conf.source_prefix, "directory", "path to kernel source"), OPT_STRING('m', "module", ¶ms.target_module, "modname", "target module name"), #endif OPT__DRY_RUN(&probe_event_dry_run), OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, Loading Loading @@ -217,7 +250,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) usage_with_options(probe_usage, options); if (params.list_events) { if (params.nevents != 0 || params.dellist) { if (params.mod_events) { pr_err(" Error: Don't use --list with --add/--del.\n"); usage_with_options(probe_usage, options); } Loading @@ -225,6 +258,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) pr_err(" Error: Don't use --list with --line.\n"); usage_with_options(probe_usage, options); } if (params.show_vars) { pr_err(" Error: Don't use --list with --vars.\n"); usage_with_options(probe_usage, options); } ret = show_perf_probe_events(); if (ret < 0) pr_err(" Error: Failed to show event list. (%d)\n", Loading @@ -234,17 +271,35 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) #ifdef DWARF_SUPPORT if (params.show_lines) { if (params.nevents != 0 || params.dellist) { pr_warning(" Error: Don't use --line with" if (params.mod_events) { pr_err(" Error: Don't use --line with" " --add/--del.\n"); usage_with_options(probe_usage, options); } if (params.show_vars) { pr_err(" Error: Don't use --line with --vars.\n"); usage_with_options(probe_usage, options); } ret = show_line_range(¶ms.line_range); ret = show_line_range(¶ms.line_range, params.target_module); if (ret < 0) pr_err(" Error: Failed to show lines. (%d)\n", ret); return ret; } if (params.show_vars) { if (params.mod_events) { pr_err(" Error: Don't use --vars with" " --add/--del.\n"); usage_with_options(probe_usage, options); } ret = show_available_vars(params.events, params.nevents, params.max_probe_points, params.target_module, params.show_ext_vars); if (ret < 0) pr_err(" Error: Failed to show vars. (%d)\n", ret); return ret; } #endif if (params.dellist) { Loading @@ -258,8 +313,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) if (params.nevents) { ret = add_perf_probe_events(params.events, params.nevents, params.force_add, params.max_probe_points); params.max_probe_points, params.target_module, params.force_add); if (ret < 0) { pr_err(" Error: Failed to add events. (%d)\n", ret); return ret; Loading Loading
include/linux/interrupt.h +1 −1 Original line number Diff line number Diff line Loading @@ -410,7 +410,7 @@ extern void open_softirq(int nr, void (*action)(struct softirq_action *)); extern void softirq_init(void); static inline void __raise_softirq_irqoff(unsigned int nr) { trace_softirq_raise((struct softirq_action *)(unsigned long)nr, NULL); trace_softirq_raise(nr); or_softirq_pending(1UL << nr); } Loading
include/trace/events/irq.h +20 −34 Original line number Diff line number Diff line Loading @@ -86,76 +86,62 @@ TRACE_EVENT(irq_handler_exit, DECLARE_EVENT_CLASS(softirq, TP_PROTO(struct softirq_action *h, struct softirq_action *vec), TP_PROTO(unsigned int vec_nr), TP_ARGS(h, vec), TP_ARGS(vec_nr), TP_STRUCT__entry( __field( int, vec ) __field( unsigned int, vec ) ), TP_fast_assign( if (vec) __entry->vec = (int)(h - vec); else __entry->vec = (int)(long)h; __entry->vec = vec_nr; ), TP_printk("vec=%d [action=%s]", __entry->vec, TP_printk("vec=%u [action=%s]", __entry->vec, show_softirq_name(__entry->vec)) ); /** * softirq_entry - called immediately before the softirq handler * @h: pointer to struct softirq_action * @vec: pointer to first struct softirq_action in softirq_vec array * @vec_nr: softirq vector number * * The @h parameter, contains a pointer to the struct softirq_action * which has a pointer to the action handler that is called. By subtracting * the @vec pointer from the @h pointer, we can determine the softirq * number. Also, when used in combination with the softirq_exit tracepoint * we can determine the softirq latency. * When used in combination with the softirq_exit tracepoint * we can determine the softirq handler runtine. */ DEFINE_EVENT(softirq, softirq_entry, TP_PROTO(struct softirq_action *h, struct softirq_action *vec), TP_PROTO(unsigned int vec_nr), TP_ARGS(h, vec) TP_ARGS(vec_nr) ); /** * softirq_exit - called immediately after the softirq handler returns * @h: pointer to struct softirq_action * @vec: pointer to first struct softirq_action in softirq_vec array * @vec_nr: softirq vector number * * The @h parameter contains a pointer to the struct softirq_action * that has handled the softirq. By subtracting the @vec pointer from * the @h pointer, we can determine the softirq number. Also, when used in * combination with the softirq_entry tracepoint we can determine the softirq * latency. * When used in combination with the softirq_entry tracepoint * we can determine the softirq handler runtine. */ DEFINE_EVENT(softirq, softirq_exit, TP_PROTO(struct softirq_action *h, struct softirq_action *vec), TP_PROTO(unsigned int vec_nr), TP_ARGS(h, vec) TP_ARGS(vec_nr) ); /** * softirq_raise - called immediately when a softirq is raised * @h: pointer to struct softirq_action * @vec: pointer to first struct softirq_action in softirq_vec array * @vec_nr: softirq vector number * * The @h parameter contains a pointer to the softirq vector number which is * raised. @vec is NULL and it means @h includes vector number not * softirq_action. When used in combination with the softirq_entry tracepoint * we can determine the softirq raise latency. * When used in combination with the softirq_entry tracepoint * we can determine the softirq raise to run latency. */ DEFINE_EVENT(softirq, softirq_raise, TP_PROTO(struct softirq_action *h, struct softirq_action *vec), TP_PROTO(unsigned int vec_nr), TP_ARGS(h, vec) TP_ARGS(vec_nr) ); #endif /* _TRACE_IRQ_H */ Loading
kernel/softirq.c +9 −7 Original line number Diff line number Diff line Loading @@ -229,18 +229,20 @@ asmlinkage void __do_softirq(void) do { if (pending & 1) { unsigned int vec_nr = h - softirq_vec; int prev_count = preempt_count(); kstat_incr_softirqs_this_cpu(h - softirq_vec); trace_softirq_entry(h, softirq_vec); kstat_incr_softirqs_this_cpu(vec_nr); trace_softirq_entry(vec_nr); h->action(h); trace_softirq_exit(h, softirq_vec); trace_softirq_exit(vec_nr); if (unlikely(prev_count != preempt_count())) { printk(KERN_ERR "huh, entered softirq %td %s %p" printk(KERN_ERR "huh, entered softirq %u %s %p" "with preempt_count %08x," " exited with %08x?\n", h - softirq_vec, softirq_to_name[h - softirq_vec], h->action, prev_count, preempt_count()); " exited with %08x?\n", vec_nr, softirq_to_name[vec_nr], h->action, prev_count, preempt_count()); preempt_count() = prev_count; } Loading
tools/perf/Documentation/perf-probe.txt +17 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ or or 'perf probe' --list or 'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' 'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' or 'perf probe' [options] --vars='PROBEPOINT' DESCRIPTION ----------- Loading @@ -31,6 +33,11 @@ OPTIONS --vmlinux=PATH:: Specify vmlinux path which has debuginfo (Dwarf binary). -m:: --module=MODNAME:: Specify module name in which perf-probe searches probe points or lines. -s:: --source=PATH:: Specify path to kernel source. Loading @@ -57,6 +64,15 @@ OPTIONS Show source code lines which can be probed. This needs an argument which specifies a range of the source code. (see LINE SYNTAX for detail) -V:: --vars=:: Show available local variables at given probe point. The argument syntax is same as PROBE SYNTAX, but NO ARGs. --externs:: (Only for --vars) Show external defined variables in addition to local variables. -f:: --force:: Forcibly add events with existing name. Loading
tools/perf/builtin-probe.c +67 −11 Original line number Diff line number Diff line Loading @@ -50,14 +50,17 @@ static struct { bool list_events; bool force_add; bool show_lines; bool show_vars; bool show_ext_vars; bool mod_events; int nevents; struct perf_probe_event events[MAX_PROBES]; struct strlist *dellist; struct line_range line_range; const char *target_module; int max_probe_points; } params; /* Parse an event definition. Note that any error must die. */ static int parse_probe_event(const char *str) { Loading Loading @@ -92,6 +95,7 @@ static int parse_probe_event_argv(int argc, const char **argv) len = 0; for (i = 0; i < argc; i++) len += sprintf(&buf[len], "%s ", argv[i]); params.mod_events = true; ret = parse_probe_event(buf); free(buf); return ret; Loading @@ -100,9 +104,10 @@ static int parse_probe_event_argv(int argc, const char **argv) static int opt_add_probe_event(const struct option *opt __used, const char *str, int unset __used) { if (str) if (str) { params.mod_events = true; return parse_probe_event(str); else } else return 0; } Loading @@ -110,6 +115,7 @@ static int opt_del_probe_event(const struct option *opt __used, const char *str, int unset __used) { if (str) { params.mod_events = true; if (!params.dellist) params.dellist = strlist__new(true, NULL); strlist__add(params.dellist, str); Loading @@ -130,6 +136,25 @@ static int opt_show_lines(const struct option *opt __used, return ret; } static int opt_show_vars(const struct option *opt __used, const char *str, int unset __used) { struct perf_probe_event *pev = ¶ms.events[params.nevents]; int ret; if (!str) return 0; ret = parse_probe_event(str); if (!ret && pev->nargs != 0) { pr_err(" Error: '--vars' doesn't accept arguments.\n"); return -EINVAL; } params.show_vars = true; return ret; } #endif static const char * const probe_usage[] = { Loading @@ -138,7 +163,8 @@ static const char * const probe_usage[] = { "perf probe [<options>] --del '[GROUP:]EVENT' ...", "perf probe --list", #ifdef DWARF_SUPPORT "perf probe --line 'LINEDESC'", "perf probe [<options>] --line 'LINEDESC'", "perf probe [<options>] --vars 'PROBEPOINT'", #endif NULL }; Loading Loading @@ -180,10 +206,17 @@ static const struct option options[] = { OPT_CALLBACK('L', "line", NULL, "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", "Show source code lines.", opt_show_lines), OPT_CALLBACK('V', "vars", NULL, "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT", "Show accessible variables on PROBEDEF", opt_show_vars), OPT_BOOLEAN('\0', "externs", ¶ms.show_ext_vars, "Show external variables too (with --vars only)"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), OPT_STRING('s', "source", &symbol_conf.source_prefix, "directory", "path to kernel source"), OPT_STRING('m', "module", ¶ms.target_module, "modname", "target module name"), #endif OPT__DRY_RUN(&probe_event_dry_run), OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, Loading Loading @@ -217,7 +250,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) usage_with_options(probe_usage, options); if (params.list_events) { if (params.nevents != 0 || params.dellist) { if (params.mod_events) { pr_err(" Error: Don't use --list with --add/--del.\n"); usage_with_options(probe_usage, options); } Loading @@ -225,6 +258,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) pr_err(" Error: Don't use --list with --line.\n"); usage_with_options(probe_usage, options); } if (params.show_vars) { pr_err(" Error: Don't use --list with --vars.\n"); usage_with_options(probe_usage, options); } ret = show_perf_probe_events(); if (ret < 0) pr_err(" Error: Failed to show event list. (%d)\n", Loading @@ -234,17 +271,35 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) #ifdef DWARF_SUPPORT if (params.show_lines) { if (params.nevents != 0 || params.dellist) { pr_warning(" Error: Don't use --line with" if (params.mod_events) { pr_err(" Error: Don't use --line with" " --add/--del.\n"); usage_with_options(probe_usage, options); } if (params.show_vars) { pr_err(" Error: Don't use --line with --vars.\n"); usage_with_options(probe_usage, options); } ret = show_line_range(¶ms.line_range); ret = show_line_range(¶ms.line_range, params.target_module); if (ret < 0) pr_err(" Error: Failed to show lines. (%d)\n", ret); return ret; } if (params.show_vars) { if (params.mod_events) { pr_err(" Error: Don't use --vars with" " --add/--del.\n"); usage_with_options(probe_usage, options); } ret = show_available_vars(params.events, params.nevents, params.max_probe_points, params.target_module, params.show_ext_vars); if (ret < 0) pr_err(" Error: Failed to show vars. (%d)\n", ret); return ret; } #endif if (params.dellist) { Loading @@ -258,8 +313,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) if (params.nevents) { ret = add_perf_probe_events(params.events, params.nevents, params.force_add, params.max_probe_points); params.max_probe_points, params.target_module, params.force_add); if (ret < 0) { pr_err(" Error: Failed to add events. (%d)\n", ret); return ret; Loading