diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/Makefile.build | 12 | ||||
-rw-r--r-- | scripts/bootgraph.pl | 16 | ||||
-rwxr-xr-x | scripts/recordmcount.pl | 4 | ||||
-rw-r--r-- | scripts/tracing/draw_functrace.py | 130 |
4 files changed, 146 insertions, 16 deletions
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 468fbc9016c7..7a176773af85 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build | |||
@@ -198,16 +198,10 @@ cmd_modversions = \ | |||
198 | fi; | 198 | fi; |
199 | endif | 199 | endif |
200 | 200 | ||
201 | ifdef CONFIG_64BIT | ||
202 | arch_bits = 64 | ||
203 | else | ||
204 | arch_bits = 32 | ||
205 | endif | ||
206 | |||
207 | ifdef CONFIG_FTRACE_MCOUNT_RECORD | 201 | ifdef CONFIG_FTRACE_MCOUNT_RECORD |
208 | cmd_record_mcount = perl $(srctree)/scripts/recordmcount.pl \ | 202 | cmd_record_mcount = perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ |
209 | "$(ARCH)" "$(arch_bits)" "$(OBJDUMP)" "$(OBJCOPY)" "$(CC)" "$(LD)" \ | 203 | "$(if $(CONFIG_64BIT),64,32)" \ |
210 | "$(NM)" "$(RM)" "$(MV)" "$(@)"; | 204 | "$(OBJDUMP)" "$(OBJCOPY)" "$(CC)" "$(LD)" "$(NM)" "$(RM)" "$(MV)" "$(@)"; |
211 | endif | 205 | endif |
212 | 206 | ||
213 | define rule_cc_o_c | 207 | define rule_cc_o_c |
diff --git a/scripts/bootgraph.pl b/scripts/bootgraph.pl index d2c61efc216f..f0af9aa9b243 100644 --- a/scripts/bootgraph.pl +++ b/scripts/bootgraph.pl | |||
@@ -78,11 +78,13 @@ while (<>) { | |||
78 | } | 78 | } |
79 | 79 | ||
80 | if ($count == 0) { | 80 | if ($count == 0) { |
81 | print "No data found in the dmesg. Make sure that 'printk.time=1' and\n"; | 81 | print STDERR <<END; |
82 | print "'initcall_debug' are passed on the kernel command line.\n\n"; | 82 | No data found in the dmesg. Make sure that 'printk.time=1' and |
83 | print "Usage: \n"; | 83 | 'initcall_debug' are passed on the kernel command line. |
84 | print " dmesg | perl scripts/bootgraph.pl > output.svg\n\n"; | 84 | Usage: |
85 | exit; | 85 | dmesg | perl scripts/bootgraph.pl > output.svg |
86 | END | ||
87 | exit 1; | ||
86 | } | 88 | } |
87 | 89 | ||
88 | print "<?xml version=\"1.0\" standalone=\"no\"?> \n"; | 90 | print "<?xml version=\"1.0\" standalone=\"no\"?> \n"; |
@@ -109,8 +111,8 @@ my $stylecounter = 0; | |||
109 | my %rows; | 111 | my %rows; |
110 | my $rowscount = 1; | 112 | my $rowscount = 1; |
111 | my @initcalls = sort { $start{$a} <=> $start{$b} } keys(%start); | 113 | my @initcalls = sort { $start{$a} <=> $start{$b} } keys(%start); |
112 | my $key; | 114 | |
113 | foreach $key (@initcalls) { | 115 | foreach my $key (@initcalls) { |
114 | my $duration = $end{$key} - $start{$key}; | 116 | my $duration = $end{$key} - $start{$key}; |
115 | 117 | ||
116 | if ($duration >= $threshold) { | 118 | if ($duration >= $threshold) { |
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 6b9fe3eb8360..eeac71c87c66 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl | |||
@@ -134,6 +134,7 @@ my $section_regex; # Find the start of a section | |||
134 | my $function_regex; # Find the name of a function | 134 | my $function_regex; # Find the name of a function |
135 | # (return offset and func name) | 135 | # (return offset and func name) |
136 | my $mcount_regex; # Find the call site to mcount (return offset) | 136 | my $mcount_regex; # Find the call site to mcount (return offset) |
137 | my $alignment; # The .align value to use for $mcount_section | ||
137 | 138 | ||
138 | if ($arch eq "x86") { | 139 | if ($arch eq "x86") { |
139 | if ($bits == 64) { | 140 | if ($bits == 64) { |
@@ -148,6 +149,7 @@ if ($arch eq "x86_64") { | |||
148 | $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; | 149 | $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; |
149 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount([+-]0x[0-9a-zA-Z]+)?\$"; | 150 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount([+-]0x[0-9a-zA-Z]+)?\$"; |
150 | $type = ".quad"; | 151 | $type = ".quad"; |
152 | $alignment = 8; | ||
151 | 153 | ||
152 | # force flags for this arch | 154 | # force flags for this arch |
153 | $ld .= " -m elf_x86_64"; | 155 | $ld .= " -m elf_x86_64"; |
@@ -160,6 +162,7 @@ if ($arch eq "x86_64") { | |||
160 | $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; | 162 | $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; |
161 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; | 163 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; |
162 | $type = ".long"; | 164 | $type = ".long"; |
165 | $alignment = 4; | ||
163 | 166 | ||
164 | # force flags for this arch | 167 | # force flags for this arch |
165 | $ld .= " -m elf_i386"; | 168 | $ld .= " -m elf_i386"; |
@@ -288,6 +291,7 @@ sub update_funcs | |||
288 | open(FILE, ">$mcount_s") || die "can't create $mcount_s\n"; | 291 | open(FILE, ">$mcount_s") || die "can't create $mcount_s\n"; |
289 | $opened = 1; | 292 | $opened = 1; |
290 | print FILE "\t.section $mcount_section,\"a\",\@progbits\n"; | 293 | print FILE "\t.section $mcount_section,\"a\",\@progbits\n"; |
294 | print FILE "\t.align $alignment\n"; | ||
291 | } | 295 | } |
292 | printf FILE "\t%s %s + %d\n", $type, $ref_func, $offsets[$i] - $offset; | 296 | printf FILE "\t%s %s + %d\n", $type, $ref_func, $offsets[$i] - $offset; |
293 | } | 297 | } |
diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py new file mode 100644 index 000000000000..902f9a992620 --- /dev/null +++ b/scripts/tracing/draw_functrace.py | |||
@@ -0,0 +1,130 @@ | |||
1 | #!/usr/bin/python | ||
2 | |||
3 | """ | ||
4 | Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com> | ||
5 | Licensed under the terms of the GNU GPL License version 2 | ||
6 | |||
7 | This script parses a trace provided by the function tracer in | ||
8 | kernel/trace/trace_functions.c | ||
9 | The resulted trace is processed into a tree to produce a more human | ||
10 | view of the call stack by drawing textual but hierarchical tree of | ||
11 | calls. Only the functions's names and the the call time are provided. | ||
12 | |||
13 | Usage: | ||
14 | Be sure that you have CONFIG_FUNCTION_TRACER | ||
15 | # mkdir /debugfs | ||
16 | # mount -t debug debug /debug | ||
17 | # echo function > /debug/tracing/current_tracer | ||
18 | $ cat /debug/tracing/trace_pipe > ~/raw_trace_func | ||
19 | Wait some times but not too much, the script is a bit slow. | ||
20 | Break the pipe (Ctrl + Z) | ||
21 | $ scripts/draw_functrace.py < raw_trace_func > draw_functrace | ||
22 | Then you have your drawn trace in draw_functrace | ||
23 | """ | ||
24 | |||
25 | |||
26 | import sys, re | ||
27 | |||
28 | class CallTree: | ||
29 | """ This class provides a tree representation of the functions | ||
30 | call stack. If a function has no parent in the kernel (interrupt, | ||
31 | syscall, kernel thread...) then it is attached to a virtual parent | ||
32 | called ROOT. | ||
33 | """ | ||
34 | ROOT = None | ||
35 | |||
36 | def __init__(self, func, time = None, parent = None): | ||
37 | self._func = func | ||
38 | self._time = time | ||
39 | if parent is None: | ||
40 | self._parent = CallTree.ROOT | ||
41 | else: | ||
42 | self._parent = parent | ||
43 | self._children = [] | ||
44 | |||
45 | def calls(self, func, calltime): | ||
46 | """ If a function calls another one, call this method to insert it | ||
47 | into the tree at the appropriate place. | ||
48 | @return: A reference to the newly created child node. | ||
49 | """ | ||
50 | child = CallTree(func, calltime, self) | ||
51 | self._children.append(child) | ||
52 | return child | ||
53 | |||
54 | def getParent(self, func): | ||
55 | """ Retrieve the last parent of the current node that | ||
56 | has the name given by func. If this function is not | ||
57 | on a parent, then create it as new child of root | ||
58 | @return: A reference to the parent. | ||
59 | """ | ||
60 | tree = self | ||
61 | while tree != CallTree.ROOT and tree._func != func: | ||
62 | tree = tree._parent | ||
63 | if tree == CallTree.ROOT: | ||
64 | child = CallTree.ROOT.calls(func, None) | ||
65 | return child | ||
66 | return tree | ||
67 | |||
68 | def __repr__(self): | ||
69 | return self.__toString("", True) | ||
70 | |||
71 | def __toString(self, branch, lastChild): | ||
72 | if self._time is not None: | ||
73 | s = "%s----%s (%s)\n" % (branch, self._func, self._time) | ||
74 | else: | ||
75 | s = "%s----%s\n" % (branch, self._func) | ||
76 | |||
77 | i = 0 | ||
78 | if lastChild: | ||
79 | branch = branch[:-1] + " " | ||
80 | while i < len(self._children): | ||
81 | if i != len(self._children) - 1: | ||
82 | s += "%s" % self._children[i].__toString(branch +\ | ||
83 | " |", False) | ||
84 | else: | ||
85 | s += "%s" % self._children[i].__toString(branch +\ | ||
86 | " |", True) | ||
87 | i += 1 | ||
88 | return s | ||
89 | |||
90 | class BrokenLineException(Exception): | ||
91 | """If the last line is not complete because of the pipe breakage, | ||
92 | we want to stop the processing and ignore this line. | ||
93 | """ | ||
94 | pass | ||
95 | |||
96 | class CommentLineException(Exception): | ||
97 | """ If the line is a comment (as in the beginning of the trace file), | ||
98 | just ignore it. | ||
99 | """ | ||
100 | pass | ||
101 | |||
102 | |||
103 | def parseLine(line): | ||
104 | line = line.strip() | ||
105 | if line.startswith("#"): | ||
106 | raise CommentLineException | ||
107 | m = re.match("[^]]+?\\] +([0-9.]+): (\\w+) <-(\\w+)", line) | ||
108 | if m is None: | ||
109 | raise BrokenLineException | ||
110 | return (m.group(1), m.group(2), m.group(3)) | ||
111 | |||
112 | |||
113 | def main(): | ||
114 | CallTree.ROOT = CallTree("Root (Nowhere)", None, None) | ||
115 | tree = CallTree.ROOT | ||
116 | |||
117 | for line in sys.stdin: | ||
118 | try: | ||
119 | calltime, callee, caller = parseLine(line) | ||
120 | except BrokenLineException: | ||
121 | break | ||
122 | except CommentLineException: | ||
123 | continue | ||
124 | tree = tree.getParent(caller) | ||
125 | tree = tree.calls(callee, calltime) | ||
126 | |||
127 | print CallTree.ROOT | ||
128 | |||
129 | if __name__ == "__main__": | ||
130 | main() | ||