aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/power/pm-graph/bootgraph.818
-rwxr-xr-xtools/power/pm-graph/bootgraph.py219
2 files changed, 160 insertions, 77 deletions
diff --git a/tools/power/pm-graph/bootgraph.8 b/tools/power/pm-graph/bootgraph.8
index dbdafcf546df..64d513f80a2a 100644
--- a/tools/power/pm-graph/bootgraph.8
+++ b/tools/power/pm-graph/bootgraph.8
@@ -37,6 +37,9 @@ Print the current tool version
37Add the dmesg log to the html output. It will be viewable by 37Add the dmesg log to the html output. It will be viewable by
38clicking a button in the timeline. 38clicking a button in the timeline.
39.TP 39.TP
40\fB-result \fIfile\fR
41Export a results table to a text file for parsing.
42.TP
40\fB-o \fIname\fR 43\fB-o \fIname\fR
41Overrides the output subdirectory name when running a new test. 44Overrides the output subdirectory name when running a new test.
42Use {date}, {time}, {hostname} for current values. 45Use {date}, {time}, {hostname} for current values.
@@ -44,14 +47,14 @@ Use {date}, {time}, {hostname} for current values.
44e.g. boot-{hostname}-{date}-{time} 47e.g. boot-{hostname}-{date}-{time}
45.SS "advanced" 48.SS "advanced"
46.TP 49.TP
47\fB-f\fR 50\fB-f or -callgraph\fR
48Use ftrace to add function detail (default: disabled)
49.TP
50\fB-callgraph\fR
51Use ftrace to create initcall callgraphs (default: disabled). If -func 51Use ftrace to create initcall callgraphs (default: disabled). If -func
52is not used there will be one callgraph per initcall. This can produce 52is not used there will be one callgraph per initcall. This can produce
53very large outputs, i.e. 10MB - 100MB. 53very large outputs, i.e. 10MB - 100MB.
54.TP 54.TP
55\fB-fstat\fR
56Use ftrace to add function detail (default: disabled)
57.TP
55\fB-maxdepth \fIlevel\fR 58\fB-maxdepth \fIlevel\fR
56limit the callgraph trace depth to \fIlevel\fR (default: 2). This is 59limit the callgraph trace depth to \fIlevel\fR (default: 2). This is
57the best way to limit the output size when using -callgraph. 60the best way to limit the output size when using -callgraph.
@@ -67,6 +70,13 @@ Reduce callgraph output in the timeline by limiting it to a list of calls. The
67argument can be a single function name or a comma delimited list. 70argument can be a single function name or a comma delimited list.
68(default: none) 71(default: none)
69.TP 72.TP
73\fB-cgskip \fIfile\fR
74Reduce callgraph output in the timeline by skipping over uninteresting
75functions in the trace, e.g. printk or console_unlock. The functions listed
76in this file will show up as empty leaves in the callgraph with only the start/end
77times displayed.
78(default: none)
79.TP
70\fB-timeprec \fIn\fR 80\fB-timeprec \fIn\fR
71Number of significant digits in timestamps (0:S, 3:ms, [6:us]) 81Number of significant digits in timestamps (0:S, 3:ms, [6:us])
72.TP 82.TP
diff --git a/tools/power/pm-graph/bootgraph.py b/tools/power/pm-graph/bootgraph.py
index e83df141a597..abb4c38f029b 100755
--- a/tools/power/pm-graph/bootgraph.py
+++ b/tools/power/pm-graph/bootgraph.py
@@ -32,7 +32,7 @@ import platform
32import shutil 32import shutil
33from datetime import datetime, timedelta 33from datetime import datetime, timedelta
34from subprocess import call, Popen, PIPE 34from subprocess import call, Popen, PIPE
35import analyze_suspend as aslib 35import sleepgraph as aslib
36 36
37# ----------------- CLASSES -------------------- 37# ----------------- CLASSES --------------------
38 38
@@ -42,23 +42,18 @@ import analyze_suspend as aslib
42# store system values and test parameters 42# store system values and test parameters
43class SystemValues(aslib.SystemValues): 43class SystemValues(aslib.SystemValues):
44 title = 'BootGraph' 44 title = 'BootGraph'
45 version = '2.1' 45 version = '2.2'
46 hostname = 'localhost' 46 hostname = 'localhost'
47 testtime = '' 47 testtime = ''
48 kernel = '' 48 kernel = ''
49 dmesgfile = '' 49 dmesgfile = ''
50 ftracefile = '' 50 ftracefile = ''
51 htmlfile = 'bootgraph.html' 51 htmlfile = 'bootgraph.html'
52 outfile = ''
53 testdir = '' 52 testdir = ''
54 testdirprefix = 'boot' 53 kparams = ''
55 embedded = False 54 result = ''
56 testlog = False
57 dmesglog = False
58 ftracelog = False
59 useftrace = False 55 useftrace = False
60 usecallgraph = False 56 usecallgraph = False
61 usedevsrc = True
62 suspendmode = 'boot' 57 suspendmode = 'boot'
63 max_graph_depth = 2 58 max_graph_depth = 2
64 graph_filter = 'do_one_initcall' 59 graph_filter = 'do_one_initcall'
@@ -69,11 +64,6 @@ class SystemValues(aslib.SystemValues):
69 bootloader = 'grub' 64 bootloader = 'grub'
70 blexec = [] 65 blexec = []
71 def __init__(self): 66 def __init__(self):
72 if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ):
73 self.embedded = True
74 self.dmesglog = True
75 self.outfile = os.environ['LOG_FILE']
76 self.htmlfile = os.environ['LOG_FILE']
77 self.hostname = platform.node() 67 self.hostname = platform.node()
78 self.testtime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S') 68 self.testtime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S')
79 if os.path.exists('/proc/version'): 69 if os.path.exists('/proc/version'):
@@ -148,11 +138,18 @@ class SystemValues(aslib.SystemValues):
148 cmdline = '%s -cronjob' % os.path.abspath(sys.argv[0]) 138 cmdline = '%s -cronjob' % os.path.abspath(sys.argv[0])
149 args = iter(sys.argv[1:]) 139 args = iter(sys.argv[1:])
150 for arg in args: 140 for arg in args:
151 if arg in ['-h', '-v', '-cronjob', '-reboot']: 141 if arg in ['-h', '-v', '-cronjob', '-reboot', '-verbose']:
152 continue 142 continue
153 elif arg in ['-o', '-dmesg', '-ftrace', '-func']: 143 elif arg in ['-o', '-dmesg', '-ftrace', '-func']:
154 args.next() 144 args.next()
155 continue 145 continue
146 elif arg == '-result':
147 cmdline += ' %s "%s"' % (arg, os.path.abspath(args.next()))
148 continue
149 elif arg == '-cgskip':
150 file = self.configFile(args.next())
151 cmdline += ' %s "%s"' % (arg, os.path.abspath(file))
152 continue
156 cmdline += ' '+arg 153 cmdline += ' '+arg
157 if self.graph_filter != 'do_one_initcall': 154 if self.graph_filter != 'do_one_initcall':
158 cmdline += ' -func "%s"' % self.graph_filter 155 cmdline += ' -func "%s"' % self.graph_filter
@@ -166,14 +163,6 @@ class SystemValues(aslib.SystemValues):
166 print '3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n' 163 print '3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n'
167 print 'CMDLINE="%s"' % cmdline 164 print 'CMDLINE="%s"' % cmdline
168 sys.exit() 165 sys.exit()
169 def getExec(self, cmd):
170 dirlist = ['/sbin', '/bin', '/usr/sbin', '/usr/bin',
171 '/usr/local/sbin', '/usr/local/bin']
172 for path in dirlist:
173 cmdfull = os.path.join(path, cmd)
174 if os.path.exists(cmdfull):
175 return cmdfull
176 return ''
177 def blGrub(self): 166 def blGrub(self):
178 blcmd = '' 167 blcmd = ''
179 for cmd in ['update-grub', 'grub-mkconfig', 'grub2-mkconfig']: 168 for cmd in ['update-grub', 'grub-mkconfig', 'grub2-mkconfig']:
@@ -199,6 +188,14 @@ class SystemValues(aslib.SystemValues):
199 self.blGrub() 188 self.blGrub()
200 else: 189 else:
201 doError('unknown boot loader: %s' % self.bootloader) 190 doError('unknown boot loader: %s' % self.bootloader)
191 def writeDatafileHeader(self, filename):
192 self.kparams = open('/proc/cmdline', 'r').read().strip()
193 fp = open(filename, 'w')
194 fp.write(self.teststamp+'\n')
195 fp.write(self.sysstamp+'\n')
196 fp.write('# command | %s\n' % self.cmdline)
197 fp.write('# kparams | %s\n' % self.kparams)
198 fp.close()
202 199
203sysvals = SystemValues() 200sysvals = SystemValues()
204 201
@@ -249,7 +246,7 @@ class Data(aslib.Data):
249 return name 246 return name
250 def deviceMatch(self, pid, cg): 247 def deviceMatch(self, pid, cg):
251 if cg.end - cg.start == 0: 248 if cg.end - cg.start == 0:
252 return True 249 return ''
253 for p in data.phases: 250 for p in data.phases:
254 list = self.dmesg[p]['list'] 251 list = self.dmesg[p]['list']
255 for devname in list: 252 for devname in list:
@@ -260,14 +257,25 @@ class Data(aslib.Data):
260 if(cg.start <= dev['start'] and cg.end >= dev['end'] and dev['length'] > 0): 257 if(cg.start <= dev['start'] and cg.end >= dev['end'] and dev['length'] > 0):
261 dev['ftrace'] = cg 258 dev['ftrace'] = cg
262 self.do_one_initcall = True 259 self.do_one_initcall = True
263 return True 260 return devname
264 else: 261 else:
265 if(cg.start > dev['start'] and cg.end < dev['end']): 262 if(cg.start > dev['start'] and cg.end < dev['end']):
266 if 'ftraces' not in dev: 263 if 'ftraces' not in dev:
267 dev['ftraces'] = [] 264 dev['ftraces'] = []
268 dev['ftraces'].append(cg) 265 dev['ftraces'].append(cg)
269 return True 266 return devname
270 return False 267 return ''
268 def printDetails(self):
269 sysvals.vprint('Timeline Details:')
270 sysvals.vprint(' Host: %s' % sysvals.hostname)
271 sysvals.vprint(' Kernel: %s' % sysvals.kernel)
272 sysvals.vprint(' Test time: %s' % sysvals.testtime)
273 sysvals.vprint(' Boot time: %s' % self.boottime)
274 for phase in self.phases:
275 dc = len(self.dmesg[phase]['list'])
276 sysvals.vprint('%9s mode: %.3f - %.3f (%d initcalls)' % (phase,
277 self.dmesg[phase]['start']*1000,
278 self.dmesg[phase]['end']*1000, dc))
271 279
272# ----------------- FUNCTIONS -------------------- 280# ----------------- FUNCTIONS --------------------
273 281
@@ -275,6 +283,8 @@ class Data(aslib.Data):
275# Description: 283# Description:
276# parse a kernel log for boot data 284# parse a kernel log for boot data
277def parseKernelLog(): 285def parseKernelLog():
286 sysvals.vprint('Analyzing the dmesg data (%s)...' % \
287 os.path.basename(sysvals.dmesgfile))
278 phase = 'kernel' 288 phase = 'kernel'
279 data = Data(0) 289 data = Data(0)
280 data.dmesg['kernel']['start'] = data.start = ktime = 0.0 290 data.dmesg['kernel']['start'] = data.start = ktime = 0.0
@@ -298,6 +308,12 @@ def parseKernelLog():
298 elif re.match(tp.sysinfofmt, line): 308 elif re.match(tp.sysinfofmt, line):
299 tp.sysinfo = line 309 tp.sysinfo = line
300 continue 310 continue
311 elif re.match(tp.cmdlinefmt, line):
312 tp.cmdline = line
313 continue
314 elif re.match(tp.kparamsfmt, line):
315 tp.kparams = line
316 continue
301 idx = line.find('[') 317 idx = line.find('[')
302 if idx > 1: 318 if idx > 1:
303 line = line[idx:] 319 line = line[idx:]
@@ -353,6 +369,17 @@ def parseKernelLog():
353# Description: 369# Description:
354# Check if trace is available and copy to a temp file 370# Check if trace is available and copy to a temp file
355def parseTraceLog(data): 371def parseTraceLog(data):
372 sysvals.vprint('Analyzing the ftrace data (%s)...' % \
373 os.path.basename(sysvals.ftracefile))
374 # if available, calculate cgfilter allowable ranges
375 cgfilter = []
376 if len(sysvals.cgfilter) > 0:
377 for p in data.phases:
378 list = data.dmesg[p]['list']
379 for i in sysvals.cgfilter:
380 if i in list:
381 cgfilter.append([list[i]['start']-0.0001,
382 list[i]['end']+0.0001])
356 # parse the trace log 383 # parse the trace log
357 ftemp = dict() 384 ftemp = dict()
358 tp = aslib.TestProps() 385 tp = aslib.TestProps()
@@ -366,7 +393,16 @@ def parseTraceLog(data):
366 continue 393 continue
367 m_time, m_proc, m_pid, m_msg, m_dur = \ 394 m_time, m_proc, m_pid, m_msg, m_dur = \
368 m.group('time', 'proc', 'pid', 'msg', 'dur') 395 m.group('time', 'proc', 'pid', 'msg', 'dur')
369 if float(m_time) > data.end: 396 t = float(m_time)
397 if len(cgfilter) > 0:
398 allow = False
399 for r in cgfilter:
400 if t >= r[0] and t < r[1]:
401 allow = True
402 break
403 if not allow:
404 continue
405 if t > data.end:
370 break 406 break
371 if(m_time and m_pid and m_msg): 407 if(m_time and m_pid and m_msg):
372 t = aslib.FTraceLine(m_time, m_msg, m_dur) 408 t = aslib.FTraceLine(m_time, m_msg, m_dur)
@@ -378,24 +414,36 @@ def parseTraceLog(data):
378 key = (m_proc, pid) 414 key = (m_proc, pid)
379 if(key not in ftemp): 415 if(key not in ftemp):
380 ftemp[key] = [] 416 ftemp[key] = []
381 ftemp[key].append(aslib.FTraceCallGraph(pid)) 417 ftemp[key].append(aslib.FTraceCallGraph(pid, sysvals))
382 cg = ftemp[key][-1] 418 cg = ftemp[key][-1]
383 if(cg.addLine(t)): 419 res = cg.addLine(t)
384 ftemp[key].append(aslib.FTraceCallGraph(pid)) 420 if(res != 0):
421 ftemp[key].append(aslib.FTraceCallGraph(pid, sysvals))
422 if(res == -1):
423 ftemp[key][-1].addLine(t)
424
385 tf.close() 425 tf.close()
386 426
387 # add the callgraph data to the device hierarchy 427 # add the callgraph data to the device hierarchy
388 for key in ftemp: 428 for key in ftemp:
389 proc, pid = key 429 proc, pid = key
390 for cg in ftemp[key]: 430 for cg in ftemp[key]:
391 if len(cg.list) < 1 or cg.invalid: 431 if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0):
392 continue 432 continue
393 if(not cg.postProcess()): 433 if(not cg.postProcess()):
394 print('Sanity check failed for %s-%d' % (proc, pid)) 434 print('Sanity check failed for %s-%d' % (proc, pid))
395 continue 435 continue
396 # match cg data to devices 436 # match cg data to devices
397 if not data.deviceMatch(pid, cg): 437 devname = data.deviceMatch(pid, cg)
398 print ' BAD: %s %s-%d [%f - %f]' % (cg.name, proc, pid, cg.start, cg.end) 438 if not devname:
439 kind = 'Orphan'
440 if cg.partial:
441 kind = 'Partial'
442 sysvals.vprint('%s callgraph found for %s %s-%d [%f - %f]' %\
443 (kind, cg.name, proc, pid, cg.start, cg.end))
444 elif len(cg.list) > 1000000:
445 print 'WARNING: the callgraph found for %s is massive! (%d lines)' %\
446 (devname, len(cg.list))
399 447
400# Function: retrieveLogs 448# Function: retrieveLogs
401# Description: 449# Description:
@@ -473,7 +521,7 @@ def createBootGraph(data):
473 devtl = aslib.Timeline(100, 20) 521 devtl = aslib.Timeline(100, 20)
474 522
475 # write the test title and general info header 523 # write the test title and general info header
476 devtl.createHeader(sysvals) 524 devtl.createHeader(sysvals, sysvals.stamp)
477 525
478 # Generate the header for this timeline 526 # Generate the header for this timeline
479 t0 = data.start 527 t0 = data.start
@@ -574,12 +622,9 @@ def createBootGraph(data):
574 data.dmesg[phase]['color'], phase+'_mode', phase[0]) 622 data.dmesg[phase]['color'], phase+'_mode', phase[0])
575 devtl.html += '</div>\n' 623 devtl.html += '</div>\n'
576 624
577 if(sysvals.outfile == sysvals.htmlfile): 625 hf = open(sysvals.htmlfile, 'w')
578 hf = open(sysvals.htmlfile, 'a')
579 else:
580 hf = open(sysvals.htmlfile, 'w')
581 626
582 # add the css if this is not an embedded run 627 # add the css
583 extra = '\ 628 extra = '\
584 .c1 {background:rgba(209,0,0,0.4);}\n\ 629 .c1 {background:rgba(209,0,0,0.4);}\n\
585 .c2 {background:rgba(255,102,34,0.4);}\n\ 630 .c2 {background:rgba(255,102,34,0.4);}\n\
@@ -597,8 +642,7 @@ def createBootGraph(data):
597 .fstat td {text-align:left;width:35px;}\n\ 642 .fstat td {text-align:left;width:35px;}\n\
598 .srccall {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\ 643 .srccall {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\
599 .srccall:hover {color:white;font-weight:bold;border:1px solid white;}\n' 644 .srccall:hover {color:white;font-weight:bold;border:1px solid white;}\n'
600 if(not sysvals.embedded): 645 aslib.addCSS(hf, sysvals, 1, False, extra)
601 aslib.addCSS(hf, sysvals, 1, False, extra)
602 646
603 # write the device timeline 647 # write the device timeline
604 hf.write(devtl.html) 648 hf.write(devtl.html)
@@ -631,6 +675,9 @@ def createBootGraph(data):
631 if(sysvals.usecallgraph): 675 if(sysvals.usecallgraph):
632 aslib.addCallgraphs(sysvals, hf, data) 676 aslib.addCallgraphs(sysvals, hf, data)
633 677
678 # add the test log as a hidden div
679 if sysvals.testlog and sysvals.logmsg:
680 hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n')
634 # add the dmesg log as a hidden div 681 # add the dmesg log as a hidden div
635 if sysvals.dmesglog: 682 if sysvals.dmesglog:
636 hf.write('<div id="dmesglog" style="display:none;">\n') 683 hf.write('<div id="dmesglog" style="display:none;">\n')
@@ -639,14 +686,9 @@ def createBootGraph(data):
639 hf.write(line) 686 hf.write(line)
640 hf.write('</div>\n') 687 hf.write('</div>\n')
641 688
642 if(not sysvals.embedded): 689 # write the footer and close
643 # write the footer and close 690 aslib.addScriptCode(hf, [data])
644 aslib.addScriptCode(hf, [data]) 691 hf.write('</body>\n</html>\n')
645 hf.write('</body>\n</html>\n')
646 else:
647 # embedded out will be loaded in a page, skip the js
648 hf.write('<div id=bounds style=display:none>%f,%f</div>' % \
649 (data.start*1000, data.end*1000))
650 hf.close() 692 hf.close()
651 return True 693 return True
652 694
@@ -780,6 +822,7 @@ def doError(msg, help=False):
780 if help == True: 822 if help == True:
781 printHelp() 823 printHelp()
782 print 'ERROR: %s\n' % msg 824 print 'ERROR: %s\n' % msg
825 sysvals.outputResult({'error':msg})
783 sys.exit() 826 sys.exit()
784 827
785# Function: printHelp 828# Function: printHelp
@@ -806,18 +849,21 @@ def printHelp():
806 print('Options:') 849 print('Options:')
807 print(' -h Print this help text') 850 print(' -h Print this help text')
808 print(' -v Print the current tool version') 851 print(' -v Print the current tool version')
852 print(' -verbose Print extra information during execution and analysis')
809 print(' -addlogs Add the dmesg log to the html output') 853 print(' -addlogs Add the dmesg log to the html output')
854 print(' -result fn Export a results table to a text file for parsing.')
810 print(' -o name Overrides the output subdirectory name when running a new test') 855 print(' -o name Overrides the output subdirectory name when running a new test')
811 print(' default: boot-{date}-{time}') 856 print(' default: boot-{date}-{time}')
812 print(' [advanced]') 857 print(' [advanced]')
813 print(' -f Use ftrace to add function detail (default: disabled)') 858 print(' -fstat Use ftrace to add function detail and statistics (default: disabled)')
814 print(' -callgraph Add callgraph detail, can be very large (default: disabled)') 859 print(' -f/-callgraph Add callgraph detail, can be very large (default: disabled)')
815 print(' -maxdepth N limit the callgraph data to N call levels (default: 2)') 860 print(' -maxdepth N limit the callgraph data to N call levels (default: 2)')
816 print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)') 861 print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
817 print(' -timeprec N Number of significant digits in timestamps (0:S, 3:ms, [6:us])') 862 print(' -timeprec N Number of significant digits in timestamps (0:S, 3:ms, [6:us])')
818 print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)') 863 print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)')
819 print(' -func list Limit ftrace to comma-delimited list of functions (default: do_one_initcall)') 864 print(' -func list Limit ftrace to comma-delimited list of functions (default: do_one_initcall)')
820 print(' -cgfilter S Filter the callgraph output in the timeline') 865 print(' -cgfilter S Filter the callgraph output in the timeline')
866 print(' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)')
821 print(' -bl name Use the following boot loader for kernel params (default: grub)') 867 print(' -bl name Use the following boot loader for kernel params (default: grub)')
822 print(' -reboot Reboot the machine automatically and generate a new timeline') 868 print(' -reboot Reboot the machine automatically and generate a new timeline')
823 print(' -manual Show the steps to generate a new timeline manually (used with -reboot)') 869 print(' -manual Show the steps to generate a new timeline manually (used with -reboot)')
@@ -837,8 +883,13 @@ if __name__ == '__main__':
837 # loop through the command line arguments 883 # loop through the command line arguments
838 cmd = '' 884 cmd = ''
839 testrun = True 885 testrun = True
886 switchoff = ['disable', 'off', 'false', '0']
840 simplecmds = ['-sysinfo', '-kpupdate', '-flistall', '-checkbl'] 887 simplecmds = ['-sysinfo', '-kpupdate', '-flistall', '-checkbl']
888 cgskip = ''
889 if '-f' in sys.argv:
890 cgskip = sysvals.configFile('cgskip.txt')
841 args = iter(sys.argv[1:]) 891 args = iter(sys.argv[1:])
892 mdset = False
842 for arg in args: 893 for arg in args:
843 if(arg == '-h'): 894 if(arg == '-h'):
844 printHelp() 895 printHelp()
@@ -846,13 +897,17 @@ if __name__ == '__main__':
846 elif(arg == '-v'): 897 elif(arg == '-v'):
847 print("Version %s" % sysvals.version) 898 print("Version %s" % sysvals.version)
848 sys.exit() 899 sys.exit()
900 elif(arg == '-verbose'):
901 sysvals.verbose = True
849 elif(arg in simplecmds): 902 elif(arg in simplecmds):
850 cmd = arg[1:] 903 cmd = arg[1:]
851 elif(arg == '-f'): 904 elif(arg == '-fstat'):
852 sysvals.useftrace = True 905 sysvals.useftrace = True
853 elif(arg == '-callgraph'): 906 elif(arg == '-callgraph' or arg == '-f'):
854 sysvals.useftrace = True 907 sysvals.useftrace = True
855 sysvals.usecallgraph = True 908 sysvals.usecallgraph = True
909 elif(arg == '-cgdump'):
910 sysvals.cgdump = True
856 elif(arg == '-mincg'): 911 elif(arg == '-mincg'):
857 sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0) 912 sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0)
858 elif(arg == '-cgfilter'): 913 elif(arg == '-cgfilter'):
@@ -860,7 +915,18 @@ if __name__ == '__main__':
860 val = args.next() 915 val = args.next()
861 except: 916 except:
862 doError('No callgraph functions supplied', True) 917 doError('No callgraph functions supplied', True)
863 sysvals.setDeviceFilter(val) 918 sysvals.setCallgraphFilter(val)
919 elif(arg == '-cgskip'):
920 try:
921 val = args.next()
922 except:
923 doError('No file supplied', True)
924 if val.lower() in switchoff:
925 cgskip = ''
926 else:
927 cgskip = sysvals.configFile(val)
928 if(not cgskip):
929 doError('%s does not exist' % cgskip)
864 elif(arg == '-bl'): 930 elif(arg == '-bl'):
865 try: 931 try:
866 val = args.next() 932 val = args.next()
@@ -872,6 +938,7 @@ if __name__ == '__main__':
872 elif(arg == '-timeprec'): 938 elif(arg == '-timeprec'):
873 sysvals.setPrecision(aslib.getArgInt('-timeprec', args, 0, 6)) 939 sysvals.setPrecision(aslib.getArgInt('-timeprec', args, 0, 6))
874 elif(arg == '-maxdepth'): 940 elif(arg == '-maxdepth'):
941 mdset = True
875 sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000) 942 sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000)
876 elif(arg == '-func'): 943 elif(arg == '-func'):
877 try: 944 try:
@@ -902,8 +969,6 @@ if __name__ == '__main__':
902 doError('No dmesg file supplied', True) 969 doError('No dmesg file supplied', True)
903 if(os.path.exists(val) == False): 970 if(os.path.exists(val) == False):
904 doError('%s does not exist' % val) 971 doError('%s does not exist' % val)
905 if(sysvals.htmlfile == val or sysvals.outfile == val):
906 doError('Output filename collision')
907 testrun = False 972 testrun = False
908 sysvals.dmesgfile = val 973 sysvals.dmesgfile = val
909 elif(arg == '-o'): 974 elif(arg == '-o'):
@@ -912,6 +977,12 @@ if __name__ == '__main__':
912 except: 977 except:
913 doError('No subdirectory name supplied', True) 978 doError('No subdirectory name supplied', True)
914 sysvals.testdir = sysvals.setOutputFolder(val) 979 sysvals.testdir = sysvals.setOutputFolder(val)
980 elif(arg == '-result'):
981 try:
982 val = args.next()
983 except:
984 doError('No result file supplied', True)
985 sysvals.result = val
915 elif(arg == '-reboot'): 986 elif(arg == '-reboot'):
916 sysvals.reboot = True 987 sysvals.reboot = True
917 elif(arg == '-manual'): 988 elif(arg == '-manual'):
@@ -947,7 +1018,7 @@ if __name__ == '__main__':
947 sysvals.getBootLoader() 1018 sysvals.getBootLoader()
948 print 'Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec) 1019 print 'Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec)
949 elif(cmd == 'sysinfo'): 1020 elif(cmd == 'sysinfo'):
950 sysvals.printSystemInfo() 1021 sysvals.printSystemInfo(True)
951 sys.exit() 1022 sys.exit()
952 1023
953 # reboot: update grub, setup a cronjob, and reboot 1024 # reboot: update grub, setup a cronjob, and reboot
@@ -963,6 +1034,10 @@ if __name__ == '__main__':
963 sysvals.manualRebootRequired() 1034 sysvals.manualRebootRequired()
964 sys.exit() 1035 sys.exit()
965 1036
1037 if sysvals.usecallgraph and cgskip:
1038 sysvals.vprint('Using cgskip file: %s' % cgskip)
1039 sysvals.setCallgraphBlacklist(cgskip)
1040
966 # cronjob: remove the cronjob, grub changes, and disable ftrace 1041 # cronjob: remove the cronjob, grub changes, and disable ftrace
967 if sysvals.iscronjob: 1042 if sysvals.iscronjob:
968 updateCron(True) 1043 updateCron(True)
@@ -980,29 +1055,23 @@ if __name__ == '__main__':
980 1055
981 # process the log data 1056 # process the log data
982 if sysvals.dmesgfile: 1057 if sysvals.dmesgfile:
1058 if not mdset:
1059 sysvals.max_graph_depth = 0
983 data = parseKernelLog() 1060 data = parseKernelLog()
984 if(not data.valid): 1061 if(not data.valid):
985 doError('No initcall data found in %s' % sysvals.dmesgfile) 1062 doError('No initcall data found in %s' % sysvals.dmesgfile)
986 if sysvals.useftrace and sysvals.ftracefile: 1063 if sysvals.useftrace and sysvals.ftracefile:
987 parseTraceLog(data) 1064 parseTraceLog(data)
1065 if sysvals.cgdump:
1066 data.debugPrint()
1067 sys.exit()
988 else: 1068 else:
989 doError('dmesg file required') 1069 doError('dmesg file required')
990 1070
991 print(' Host: %s' % sysvals.hostname) 1071 sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile)
992 print(' Test time: %s' % sysvals.testtime) 1072 sysvals.vprint('Command:\n %s' % sysvals.cmdline)
993 print(' Boot time: %s' % data.boottime) 1073 sysvals.vprint('Kernel parameters:\n %s' % sysvals.kparams)
994 print('Kernel Version: %s' % sysvals.kernel) 1074 data.printDetails()
995 print(' Kernel start: %.3f' % (data.start * 1000))
996 print('Usermode start: %.3f' % (data.tUserMode * 1000))
997 print('Last Init Call: %.3f' % (data.end * 1000))
998
999 # handle embedded output logs
1000 if(sysvals.outfile and sysvals.embedded):
1001 fp = open(sysvals.outfile, 'w')
1002 fp.write('pass %s initstart %.3f end %.3f boot %s\n' %
1003 (data.valid, data.tUserMode*1000, data.end*1000, data.boottime))
1004 fp.close()
1005
1006 createBootGraph(data) 1075 createBootGraph(data)
1007 1076
1008 # if running as root, change output dir owner to sudo_user 1077 # if running as root, change output dir owner to sudo_user
@@ -1010,3 +1079,7 @@ if __name__ == '__main__':
1010 os.getuid() == 0 and 'SUDO_USER' in os.environ: 1079 os.getuid() == 0 and 'SUDO_USER' in os.environ:
1011 cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' 1080 cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1'
1012 call(cmd.format(os.environ['SUDO_USER'], sysvals.testdir), shell=True) 1081 call(cmd.format(os.environ['SUDO_USER'], sysvals.testdir), shell=True)
1082
1083 sysvals.stamp['boot'] = (data.tUserMode - data.start) * 1000
1084 sysvals.stamp['lastinit'] = data.end * 1000
1085 sysvals.outputResult(sysvals.stamp)