aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/probe-event.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2010-01-06 09:45:34 -0500
committerIngo Molnar <mingo@elte.hu>2010-01-13 04:09:14 -0500
commit631c9def804b2c92b5cca04fb9ff7b5df9e35094 (patch)
tree3ce09a1894f765bbea6538335ef11950287d66ee /tools/perf/util/probe-event.c
parent6964cd2c8efe6e048401f1fe3952a06c563c34c1 (diff)
perf probe: Support --line option to show probable source-code lines
Add --line option to support showing probable source-code lines. perf probe --line SRC:LN[-LN|+NUM] or perf probe --line FUNC[:LN[-LN|+NUM]] This option shows source-code with line number if the line can be probed. Lines without line number (and blue color) means that the line can not be probed, because debuginfo doesn't have the information of those lines. The argument specifies the range of lines, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function. e.g. # ./perf probe --line kernel/sched.c:1080 <kernel/sched.c:1080> * * called with rq->lock held and irqs disabled */ static void hrtick_start(struct rq *rq, u64 delay) { struct hrtimer *timer = &rq->hrtick_timer; 1086 ktime_t time = ktime_add_ns(timer->base->get_time(), delay); hrtimer_set_expires(timer, time); 1090 if (rq == this_rq()) { 1091 hrtimer_restart(timer); 1092 } else if (!rq->hrtick_csd_pending) { 1093 __smp_call_function_single(cpu_of(rq), &rq->hrtick_csd, 1094 rq->hrtick_csd_pending = 1; If you specifying function name, this shows function-relative line number. # ./perf probe --line schedule <schedule:0> asmlinkage void __sched schedule(void) 1 { struct task_struct *prev, *next; unsigned long *switch_count; struct rq *rq; int cpu; need_resched: preempt_disable(); 9 cpu = smp_processor_id(); 10 rq = cpu_rq(cpu); 11 rcu_sched_qs(cpu); 12 prev = rq->curr; 13 switch_count = &prev->nivcsw; Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: systemtap <systemtap@sources.redhat.com> Cc: DLE <dle-develop@lists.sourceforge.net> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Mike Galbraith <efault@gmx.de> LKML-Reference: <20100106144534.27218.77939.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r--tools/perf/util/probe-event.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index a22141a773bc..71b0dd590a37 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -38,6 +38,7 @@
38#include "strlist.h" 38#include "strlist.h"
39#include "debug.h" 39#include "debug.h"
40#include "cache.h" 40#include "cache.h"
41#include "color.h"
41#include "parse-events.h" /* For debugfs_path */ 42#include "parse-events.h" /* For debugfs_path */
42#include "probe-event.h" 43#include "probe-event.h"
43 44
@@ -63,6 +64,42 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
63 return ret; 64 return ret;
64} 65}
65 66
67void parse_line_range_desc(const char *arg, struct line_range *lr)
68{
69 const char *ptr;
70 char *tmp;
71 /*
72 * <Syntax>
73 * SRC:SLN[+NUM|-ELN]
74 * FUNC[:SLN[+NUM|-ELN]]
75 */
76 ptr = strchr(arg, ':');
77 if (ptr) {
78 lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0);
79 if (*tmp == '+')
80 lr->end = lr->start + (unsigned int)strtoul(tmp + 1,
81 &tmp, 0);
82 else if (*tmp == '-')
83 lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0);
84 else
85 lr->end = 0;
86 pr_debug("Line range is %u to %u\n", lr->start, lr->end);
87 if (lr->end && lr->start > lr->end)
88 semantic_error("Start line must be smaller"
89 " than end line.");
90 if (*tmp != '\0')
91 semantic_error("Tailing with invalid character '%d'.",
92 *tmp);
93 tmp = strndup(arg, (ptr - arg));
94 } else
95 tmp = strdup(arg);
96
97 if (strchr(tmp, '.'))
98 lr->file = tmp;
99 else
100 lr->function = tmp;
101}
102
66/* Check the name is good for event/group */ 103/* Check the name is good for event/group */
67static bool check_event_name(const char *name) 104static bool check_event_name(const char *name)
68{ 105{
@@ -678,3 +715,66 @@ void del_trace_kprobe_events(struct strlist *dellist)
678 close(fd); 715 close(fd);
679} 716}
680 717
718#define LINEBUF_SIZE 256
719
720static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
721{
722 char buf[LINEBUF_SIZE];
723 const char *color = PERF_COLOR_BLUE;
724
725 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
726 goto error;
727 if (!skip) {
728 if (show_num)
729 fprintf(stdout, "%7u %s", l, buf);
730 else
731 color_fprintf(stdout, color, " %s", buf);
732 }
733
734 while (strlen(buf) == LINEBUF_SIZE - 1 &&
735 buf[LINEBUF_SIZE - 2] != '\n') {
736 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
737 goto error;
738 if (!skip) {
739 if (show_num)
740 fprintf(stdout, "%s", buf);
741 else
742 color_fprintf(stdout, color, "%s", buf);
743 }
744 }
745 return;
746error:
747 if (feof(fp))
748 die("Source file is shorter than expected.");
749 else
750 die("File read error: %s", strerror(errno));
751}
752
753void show_line_range(struct line_range *lr)
754{
755 unsigned int l = 1;
756 struct line_node *ln;
757 FILE *fp;
758
759 setup_pager();
760
761 if (lr->function)
762 fprintf(stdout, "<%s:%d>\n", lr->function,
763 lr->start - lr->offset);
764 else
765 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
766
767 fp = fopen(lr->path, "r");
768 if (fp == NULL)
769 die("Failed to open %s: %s", lr->path, strerror(errno));
770 /* Skip to starting line number */
771 while (l < lr->start)
772 show_one_line(fp, l++, true, false);
773
774 list_for_each_entry(ln, &lr->line_list, list) {
775 while (ln->line > l)
776 show_one_line(fp, (l++) - lr->offset, false, false);
777 show_one_line(fp, (l++) - lr->offset, false, true);
778 }
779 fclose(fp);
780}