Skip to content
This repository was archived by the owner on Jan 10, 2023. It is now read-only.

Commit 848d255

Browse files
committed
Draw/Queue/CPU ratio and GPU/CPU Bound detection
Python 3 Support for buildall.py Exporters API: setting multi-value for counter frame lanes support process labels metadata Tasks from stacks algorithm is refactored Handling of Adreno format deviations Better ETW process names handling More correct ETW VSync handling Fixes
1 parent 488651b commit 848d255

File tree

9 files changed

+385
-193
lines changed

9 files changed

+385
-193
lines changed

buildall.py

+30-47
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#
1717
#**********************************************************************************************************************************************************************************************************************************************************************************************
1818

19+
from __future__ import print_function
1920
import os
2021
import sys
2122
import shutil
@@ -56,54 +57,12 @@ def get_yocto():
5657
return {'bits': '32'}
5758
return {'bits': '64'}
5859

59-
60-
def GetJDKPath():
61-
if sys.platform == 'win32':
62-
import _winreg
63-
path = "SOFTWARE\\JavaSoft\\Java Development Kit"
64-
try:
65-
aKey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, path, 0, _winreg.KEY_READ | _winreg.KEY_WOW64_64KEY)
66-
except WindowsError:
67-
print("No key:", path)
68-
return None
69-
subkeys = []
70-
try:
71-
i = 0
72-
while True:
73-
subkeys.append(_winreg.EnumKey(aKey, i))
74-
i += 1
75-
except WindowsError:
76-
pass
77-
if not subkeys:
78-
print("No subkeys for:", path)
79-
return None
80-
subkeys.sort()
81-
path += "\\" + subkeys[-1]
82-
try:
83-
aKey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, path, 0, _winreg.KEY_READ | _winreg.KEY_WOW64_64KEY)
84-
return _winreg.QueryValueEx(aKey, "JavaHome")[0]
85-
except WindowsError:
86-
print("No value for:", path)
87-
return None
88-
else:
89-
path, err = subprocess.Popen("which javah", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
90-
if err or not path:
91-
return None
92-
if sys.platform == 'darwin':
93-
path = subprocess.check_output("/usr/libexec/java_home").decode("utf-8").split('\n')[0]
94-
return path if os.path.exists(path) else None
95-
else:
96-
matches = []
97-
for root, dirnames, filenames in os.walk('/usr/lib/jvm'):
98-
for filename in fnmatch.filter(filenames, 'jni.h'):
99-
matches.append(os.path.join(root, filename))
100-
if not matches:
101-
return None
102-
return os.path.split(matches[0])[0]
103-
10460
if sys.platform == 'win32':
10561
def read_registry(path, depth=0xFFFFFFFF, statics={}):
106-
import _winreg
62+
try:
63+
import _winreg
64+
except ImportError:
65+
import winreg as _winreg
10766
parts = path.split('\\')
10867
hub = parts[0]
10968
path = '\\'.join(parts[1:])
@@ -148,13 +107,37 @@ def enum_nodes(curpath, level):
148107
return enum_nodes(path, depth)
149108

150109

110+
def GetJDKPath():
111+
if sys.platform == 'win32':
112+
bush = read_registry(r'HKLM\SOFTWARE\JavaSoft\Java Development Kit')
113+
subkeys = sorted([key for key in bush if 'JavaHome' in bush[key]])
114+
if subkeys:
115+
return bush[subkeys[-1]]['JavaHome']
116+
return None
117+
else:
118+
path, err = subprocess.Popen("which javah", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
119+
if err or not path:
120+
return None
121+
if sys.platform == 'darwin':
122+
path = subprocess.check_output("/usr/libexec/java_home").decode("utf-8").split('\n')[0]
123+
return path if os.path.exists(path) else None
124+
else:
125+
matches = []
126+
for root, dirnames, filenames in os.walk('/usr/lib/jvm'):
127+
for filename in fnmatch.filter(filenames, 'jni.h'):
128+
matches.append(os.path.join(root, filename))
129+
if not matches:
130+
return None
131+
return os.path.split(matches[0])[0]
132+
133+
151134
def get_vs_versions():
152135
if sys.platform != 'win32':
153136
return []
154137
bush = read_registry(r'HKLM\SOFTWARE\Microsoft\VisualStudio', 2)
155138

156139
versions = []
157-
for key, val in bush.iteritems():
140+
for key in bush:
158141
if '.' not in key:
159142
continue
160143
version = key.split('.')[0]

runtool/collectors/ftrace.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def start(self):
164164
self.perf_file = os.path.join(self.args.output, 'perf-%s.data' % (self.args.cuts[0] if self.args.cuts else '0'))
165165
if os.path.exists(self.perf_file):
166166
os.remove(self.perf_file)
167-
cmd = 'perf record -a -g -o "%s" -a --pid=%s' % (self.perf_file, self.args.target)
167+
cmd = 'perf record -a -g -o "%s" --pid=%s' % (self.perf_file, self.args.target)
168168
self.perf_proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setpgrp)
169169

170170
def copy_from_target(self, what, where):

runtool/collectors/osx.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,10 @@ def stop(self, wait=True):
183183
self.log("pid: %s" % str(self.pid))
184184
if not self.pid:
185185
return []
186-
children = list(self.get_pid_children(self.pid))
187-
for pid in children:
186+
dtrace_pids = [self.pid] + list(self.get_pid_children(self.pid))
187+
for pid in dtrace_pids: # FIXME: check if it has parent pid as well. Looks as we kill only children.
188188
self.execute("sudo -A kill -2 %d" % pid, env=os.environ)
189-
print pid, str(children)
190-
os.waitpid(self.pid, 0)
191-
for pid in children:
189+
for pid in dtrace_pids:
192190
try:
193191
os.waitpid(pid, 0)
194192
except:

runtool/collectors/win.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def __init__(self, args):
228228
Collector.__init__(self, args)
229229
wpr = WPRCollector.detect()
230230
self.xperf = os.path.normpath(os.path.join(os.path.dirname(wpr), 'xperf')) if wpr else None
231-
if not os.path.exists(self.xperf):
231+
if not self.xperf or not os.path.exists(self.xperf):
232232
variants = self.detect_instances('xperf')
233233
if variants:
234234
self.xperf = variants[0] # TODO: select by higher version

runtool/decoders/Adreno.py

+25-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@ def __init__(self, args, callbacks):
1515

1616
@staticmethod
1717
def parse_args(args):
18-
return dict(pair.split('=') for pair in args.split())
18+
res = {None:[]}
19+
no_pair = []
20+
for chunk in args.split():
21+
if '=' in chunk:
22+
key, val = chunk.split('=')
23+
res[key] = val
24+
else:
25+
res[None].append(chunk)
26+
return res
1927

2028
def gpu_queue(self, ctx, inflight, timestamp):
2129
state = self.ctx.setdefault(ctx, {'inflight': inflight, 'queued': None})
@@ -123,20 +131,34 @@ def handle_record(self, proc, pid, tid, cpu, flags, timestamp, name, args):
123131
elif name in ['kgsl_pwr_set_state', 'kgsl_pwr_request_state']:
124132
args = self.parse_args(args)
125133
thread = self.gpu.thread(-1)
126-
thread.counter('POWER_STATE').set_value(timestamp, 0 if args['state'] == 'NAP' else 1)
134+
if 'state' in args:
135+
state = 0 if args['state'] == 'NAP' else 1
136+
else:
137+
state = 0 if 'NAP' in args[None] else 1
138+
thread.counter('POWER_STATE').set_value(timestamp, state)
127139
elif name == 'kgsl_gpubusy':
128140
args = self.parse_args(args)
129141
thread = self.gpu.thread(-1)
130142
thread.counter('busy').set_value(timestamp, int(args['busy']))
131143
thread.counter('elapsed').set_value(timestamp, int(args['elapsed']))
144+
elif name == 'kgsl_tz_params':
145+
args = self.parse_args(args)
146+
thread = self.gpu.thread(-1)
147+
thread.counter('total_time').set_value(timestamp, int(args['total_time']))
148+
thread.counter('busy_time').set_value(timestamp, int(args['busy_time']))
149+
thread.counter('idle_time').set_value(timestamp, int(args['idle_time']))
132150
elif name == 'kgsl_a3xx_irq_status':
133151
args = self.parse_args(args)
134152
thread = self.gpu.thread(-1)
135153
thread.object(0, args['d_name'], 'Adreno').snapshot(timestamp, args)
136154
elif name in ['kgsl_bus', 'kgsl_rail', 'kgsl_irq', 'kgsl_clk']:
137155
args = self.parse_args(args)
138156
thread = self.gpu.thread(-1)
139-
thread.counter(name.split('_')[1].upper()).set_value(timestamp, 1 if args['flag'] == 'on' else 0)
157+
if 'flag' in args:
158+
state = 1 if args['flag'] == 'on' else 0
159+
else:
160+
state = 1 if 'on' in args[None] else 0
161+
thread.counter(name.split('_')[1].upper()).set_value(timestamp, state)
140162
elif name in ['kgsl_register_event', 'kgsl_fire_event', 'kgsl_regwrite', 'kgsl_issueibcmds', 'kgsl_active_count']:
141163
args = self.parse_args(args)
142164
self.callbacks.process(pid).thread(tid).marker('thread', name, 'Adreno').set(timestamp, args=args)

runtool/exporters/ChromeTracing.py

+48-30
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def __init__(self, args, tree):
5050
self.frames = {}
5151
self.samples = []
5252
self.last_task = None
53+
self.metadata = {}
5354
if self.args.trace:
5455
for trace in self.args.trace:
5556
if trace.endswith(".etl"):
@@ -209,13 +210,17 @@ def calc_time_sync(time_sync, series=True):
209210

210211
def global_metadata(self, data):
211212
if data['str'] == "__process__": # this is the very first record in the trace
212-
if data.has_key('data'):
213+
if 'data' in data:
213214
self.file.write(
214215
'{"name": "process_name", "ph":"M", "pid":%d, "tid":%d, "args": {"name":"%s"}},\n' % (int(data['pid']), int(data['tid']), data['data'].replace("\\", "\\\\").encode('utf-8'))
215216
)
216-
if data.has_key('delta'):
217+
if 'delta' in data:
217218
self.file.write(
218-
'{"name": "process_sort_index", "ph":"M", "pid":%d, "tid":%s, "args": {"sort_index":%d}},\n' % (data['pid'], data['tid'], data['delta'])
219+
'{"name": "process_sort_index", "ph":"M", "pid":%d, "tid":%s, "args": {"sort_index":%d}},\n' % (data['pid'], data['tid'], abs(data['delta']) if abs(data['delta']) > 100 else data['delta'])
220+
)
221+
if 'labels' in data and data['labels']:
222+
self.file.write(
223+
'{"name": "process_labels", "ph":"M", "pid":%d, "tid":%s, "args": {"labels":"%s"}},\n' % (data['pid'], data['tid'], ','.join(data['labels']))
219224
)
220225
if data['tid'] >= 0 and not self.tree['threads'].has_key('%d,%d' % (data['pid'], data['tid'])): # marking the main thread
221226
self.file.write(
@@ -225,10 +230,12 @@ def global_metadata(self, data):
225230
self.file.write(
226231
'{"name": "thread_name", "ph":"M", "pid":%d, "tid":%d, "args": {"name":"%s"}},\n' % (int(data['pid']), int(data['tid']), data['data'].replace("\\", "\\\\").encode('utf-8'))
227232
)
228-
if data.has_key('delta'):
233+
if 'delta' in data:
229234
self.file.write(
230-
'{"name": "thread_sort_index", "ph":"M", "pid":%d, "tid":%s, "args": {"sort_index":%d}},\n' % (data['pid'], data['tid'], data['delta'])
235+
'{"name": "thread_sort_index", "ph":"M", "pid":%d, "tid":%s, "args": {"sort_index":%d}},\n' % (data['pid'], data['tid'], abs(data['delta']) if abs(data['delta']) > 100 else data['delta'])
231236
)
237+
else:
238+
self.metadata.setdefault(data['str'], []).append(data['data'])
232239

233240
def relation(self, data, head, tail):
234241
if not head or not tail:
@@ -266,12 +273,14 @@ def complete_task(self, type, begin, end):
266273
self.last_task = (type, begin, end)
267274
assert (GoogleTrace.Phase.has_key(type))
268275
if begin['type'] == 7: # frame_begin
269-
begin['id'] = begin['tid'] if begin.has_key('tid') else 0 # Async events are groupped by cat & id
276+
if 'id' not in begin:
277+
begin['id'] = id(begin) # Async events are groupped by cat & id
270278
res = self.format_task('b', 'frame', begin, {})
271-
res += [',\n']
272-
end_begin = begin.copy()
273-
end_begin['time'] = end['time']
274-
res += self.format_task('e', 'frame', end_begin, {})
279+
if end:
280+
res += [',\n']
281+
end_begin = begin.copy()
282+
end_begin['time'] = end['time'] - 1000
283+
res += self.format_task('e', 'frame', end_begin, {})
275284
else:
276285
res = self.format_task(GoogleTrace.Phase[type], type, begin, end)
277286

@@ -331,7 +340,7 @@ def handle_stack(self, task, stack, name='stack'):
331340

332341
def format_task(self, phase, type, begin, end):
333342
res = []
334-
res.append('{"ph":"%s"' % (phase))
343+
res.append('{"ph":"%s"' % phase)
335344
res.append(', "pid":%(pid)d' % begin)
336345
if begin.has_key('tid'):
337346
res.append(', "tid":%(tid)d' % begin)
@@ -374,7 +383,7 @@ def format_task(self, phase, type, begin, end):
374383
res.append(', "cat":"%s"' % (begin['domain']))
375384

376385
if 'id' in begin:
377-
res.append(', "id":%s' % (begin['id']))
386+
res.append(', "id":"%s"' % str(begin['id']))
378387
if type in ['task']:
379388
dur = self.convert_time(end['time']) - self.convert_time(begin['time'])
380389
if dur < self.args.min_dur:
@@ -392,7 +401,8 @@ def format_task(self, phase, type, begin, end):
392401
args["__file__"] = begin["__file__"]
393402
args["__line__"] = begin["__line__"]
394403
if 'counter' == type:
395-
args[name] = begin['delta']
404+
if 'delta' in begin: # multi-counter is passed as named sub-counters dict
405+
args[name] = begin['delta']
396406
if 'memory' in begin:
397407
total = 0
398408
breakdown = {}
@@ -426,23 +436,31 @@ def remove_last(self, count):
426436
self.file.truncate()
427437

428438
def finish(self, intermediate=False):
429-
if self.samples and not intermediate:
430-
self.remove_last(2)
431-
self.file.write('], "stackFrames": {\n')
432-
for id, frame in self.frames.iteritems():
433-
self.file.write('"%s": %s,\n' % (id, json.dumps(frame)))
434-
if self.frames: # deleting last two symbols from the file as we can't leave comma at the end due to json restrictions
435-
self.remove_last(2)
436-
self.file.write('\n}, "samples": [\n')
437-
for sample in self.samples:
438-
self.file.write(json.dumps(sample) + ',\n')
439-
if self.samples: # deleting last two symbols from the file as we can't leave comma at the end due to json restrictions
440-
self.remove_last(2)
441-
self.file.write('\n]}')
442-
self.samples = []
443-
self.frames = {}
444-
else:
445-
self.file.write('{}]}')
439+
self.remove_last(2) # remove trailing ,\n
440+
if not intermediate:
441+
if self.samples:
442+
self.file.write('], "stackFrames": {\n')
443+
for id, frame in self.frames.iteritems():
444+
self.file.write('"%s": %s,\n' % (id, json.dumps(frame)))
445+
if self.frames: # deleting last two symbols from the file as we can't leave comma at the end due to json restrictions
446+
self.remove_last(2)
447+
self.file.write('\n}, "samples": [\n')
448+
for sample in self.samples:
449+
self.file.write(json.dumps(sample) + ',\n')
450+
if self.samples: # deleting last two symbols from the file as we can't leave comma at the end due to json restrictions
451+
self.remove_last(2)
452+
self.samples = []
453+
self.frames = {}
454+
if self.metadata:
455+
self.file.write('\n],\n')
456+
for key, value in self.metadata.iteritems():
457+
self.file.write('"%s": %s,\n' % (key, json.dumps(value[0] if len(value) == 1 else value)))
458+
self.remove_last(2) # remove trailing ,\n
459+
self.file.write('\n}')
460+
self.file.close()
461+
return
462+
463+
self.file.write('\n]}')
446464
self.file.close()
447465

448466
@staticmethod

0 commit comments

Comments
 (0)