aboutsummaryrefslogtreecommitdiffstats
path: root/tools/power/pm-graph/bootgraph.py
diff options
context:
space:
mode:
authorTodd E Brandt <todd.e.brandt@linux.intel.com>2018-01-30 03:17:19 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-02-21 17:56:22 -0500
commitd83a76a8ec34b3c52e9aadafadb370ebd82cf79a (patch)
treec49457a40427f73f52d7f3a1a6bcbc7ef7a42ccc /tools/power/pm-graph/bootgraph.py
parenta6fbdbb2b852c2208156f21747b270931fd0d427 (diff)
pm-graph: AnalyzeBoot v2.2
- add -cgskip option to reduce callgraph output size - add -cgfilter option to focus on a list of devices - add -result option for exporting batch test results - removed all phoronix hooks, use -result to enable batch testing - changed argument -f to match sleegraph, -f = -callgraph - use -fstat for function status instead of -f - add -verbose option to print out timeline stats and kernel options - include command string and kernel params in timeline output header Signed-off-by: Todd Brandt <todd.e.brandt@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'tools/power/pm-graph/bootgraph.py')
-rwxr-xr-xtools/power/pm-graph/bootgraph.py219
1 files changed, 146 insertions, 73 deletions
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)