|
34 | 34 | import os
|
35 | 35 | import time
|
36 | 36 | import subprocess
|
| 37 | +import argparse |
| 38 | + |
| 39 | +parser = argparse.ArgumentParser(description='Process xperf ETL file and generate flamegraph(s).') |
| 40 | +parser.add_argument('etlFilename', metavar='FILE', type=str, |
| 41 | + help='Path to ETL file') |
| 42 | +parser.add_argument('-p', '--processlist', help='List of process names to generate flamegraph for. Comma separated.', type=str) |
| 43 | +parser.add_argument('-b', '--begin', help='Time range. Begin from the specified value. In seconds.', type=float) |
| 44 | +parser.add_argument('-e', '--end', help='Time range. End at the specified value. In seconds.', type=float) |
| 45 | +parser.add_argument('-o', '--output', help='Path to directory where output will written into. Default is system TEMP directory', type=str) |
| 46 | +parser.set_defaults(output=os.environ["temp"]) |
| 47 | +parser.add_argument('-n', '--numshow', help='Number of top processes to generate flame graph for. Default is 1', type=int) |
| 48 | +parser.set_defaults(numshow=1) |
| 49 | +parser.add_argument('-d', '--dontopen', help='Do not open the generated SVG file automatically. Default is open', action='store_true') |
| 50 | +parser.set_defaults(dontopen=False) |
| 51 | +args = parser.parse_args() |
| 52 | + |
| 53 | +processList = [] |
| 54 | +if args.processlist: |
| 55 | + processList = [item.lower() for item in args.processlist.split(',')] |
37 | 56 |
|
38 | 57 | # How many threads to create collapsed stacks for.
|
39 |
| -numToShow = 1 |
| 58 | +numToShow = args.numshow |
40 | 59 |
|
41 | 60 | scriptPath = os.path.abspath(sys.argv[0])
|
42 | 61 | scriptDir = os.path.split(scriptPath)[0]
|
|
63 | 82 | print "Couldn't find \"%s\". Make sure WPT 10 is installed." % wpaExporterPath
|
64 | 83 | sys.exit(0)
|
65 | 84 |
|
66 |
| -if len(sys.argv) < 2: |
67 |
| - print "Usage: %s trace.etl begin end" % sys.argv[0] |
68 |
| - print "Begin and end specify the time range to be processed, in seconds." |
69 |
| - sys.exit(0) |
70 |
| - |
71 |
| -etlFilename = sys.argv[1] |
72 |
| -if len(sys.argv) >= 4: |
73 |
| - begin = float(sys.argv[2]) |
74 |
| - end = float(sys.argv[3]) |
75 |
| - wpaCommand = r'"%s" "%s" -range %ss %ss -profile "%s" -symbols' % (wpaExporterPath, etlFilename, begin, end, profilePath) |
| 85 | +if args.begin and args.end: |
| 86 | + wpaCommand = r'"%s" "%s" -range %ss %ss -profile "%s" -symbols' % (wpaExporterPath, args.etlFilename, args.begin, args.end, profilePath) |
76 | 87 | else:
|
77 |
| - wpaCommand = r'"%s" "%s" -profile "%s" -symbols' % (wpaExporterPath, etlFilename, profilePath) |
| 88 | + wpaCommand = r'"%s" "%s" -profile "%s" -symbols' % (wpaExporterPath, args.etlFilename, profilePath) |
78 | 89 |
|
79 | 90 | print "> %s" % wpaCommand
|
80 | 91 | start = time.clock()
|
|
97 | 108 | line = line.strip()
|
98 | 109 | firstCommaPos = line.find(",")
|
99 | 110 | process = line[:firstCommaPos]
|
| 111 | + if processList and process.split(' ')[0].lower() not in processList: |
| 112 | + continue |
100 | 113 | secondCommaPos = line.find(",", firstCommaPos + 1)
|
101 | 114 | threadID = line[firstCommaPos + 1 : secondCommaPos]
|
102 | 115 | stackSummary = line[secondCommaPos + 1:]
|
|
145 | 158 |
|
146 | 159 | print "Found %d samples from %d threads." % (totalSamples, len(samples))
|
147 | 160 |
|
148 |
| -tempDir = os.environ["temp"] |
| 161 | +if len(processList)>0: |
| 162 | + numToShow = len(sortedThreads) |
| 163 | + |
149 | 164 | count = 0
|
150 | 165 | for numSamples, processAndThread in sortedThreads[:numToShow]:
|
151 | 166 | threadSamples = samples[processAndThread]
|
152 |
| - outputName = os.path.join(tempDir, "collapsed_stacks_%d.txt" % count) |
| 167 | + outputName = os.path.join(args.output, "collapsed_stacks_%d.txt" % count) |
153 | 168 | count += 1
|
154 | 169 | print "Writing %d samples to temporary file %s" % (numSamples, outputName)
|
155 | 170 | sortedStacks = []
|
|
166 | 181 | # perl script is run.
|
167 | 182 | out.close()
|
168 | 183 |
|
169 |
| - destPath = os.path.join(tempDir, "%s.svg" % processAndThread) |
| 184 | + destPath = os.path.join(args.output, "%s.svg" % processAndThread) |
170 | 185 | title = "CPU Usage flame graph of %s" % processAndThread
|
171 | 186 | perlCommand = 'perl "%s" --title="%s" "%s"' % (flameGraphPath, title, outputName)
|
172 | 187 | print "> %s" % perlCommand
|
173 | 188 | svgOutput = subprocess.check_output(perlCommand)
|
174 | 189 | if len(svgOutput) > 100:
|
175 | 190 | open(destPath, "wt").write(svgOutput)
|
176 |
| - os.popen(destPath) |
| 191 | + if not args.dontopen: |
| 192 | + os.popen(destPath) |
177 | 193 | print 'Results are in "%s" - they should be auto-opened in the default SVG viewer.' % destPath
|
178 | 194 | else:
|
179 | 195 | print "Result size is %d bytes - is perl in your path?" % len(svgOutput)
|
0 commit comments