1""" NNAPI systrace parser - getting data in from a systrace html output """ 2 3import re 4import sys 5 6def get_trace_part(filename): 7 """ Finds the text trace in the given html file, returns as a string. """ 8 with open(filename) as f: 9 lines = f.readlines() 10 seen_begin = False 11 trace = [] 12 lineno = 0 13 for line in lines: 14 lineno = lineno + 1 15 if ("# TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION" in line or 16 "# TASK-PID CPU# |||| TIMESTAMP FUNCTION" in line): 17 seen_begin = True 18 if seen_begin: 19 if "</script>" in line: 20 break 21 trace.append([line, lineno]) 22 return trace 23 24MATCHER = re.compile(r"^\s*([^ ].{1,15})-(\d+)\s+\(\s*([-0-9]+)\) .* (\d+\.\d+): tracing_mark_write: ([BE].*)$") 25MATCHER_FOR_OLD = re.compile(r"^\s*([^ ].{1,15})-(\d+) .* (\d+\.\d+): tracing_mark_write: ([BE].*)$") 26 27def parse_trace_part(trace): 28 """ Takes a string containing the text trace form systrace, parses the rows 29 and selects which threads we are interested in. 30 31 Returns (tracked_pids, driver_tgids, parsed), where: 32 - tracked_pids: map from pids we are interested in to their tgids 33 - driver_tgids: map that contains tgids of NNAPI driver processes 34 - parsed: list of parsed rows, each containing 35 TASK, PID, TGID, TIMESTAMP and FUNCTION 36 as shown below 37 """ 38 # Row format 39 # # TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION" in line: 40 # # | | | | |||| | | 41 # NeuralNetworks-5143 ( 5143) [005] ...1 142.924145: tracing_mark_write: B|5143|[NN_L 42 # <...>-5149 ( 774) [000] ...1 143.103773: tracing_mark_write: B|774|[NN_LDV_PC][validat 43 # <...>-756 ( 756) [000] ...1 143.140553: tracing_mark_write: B|756|HIDL::IDevice::prepa 44 # <...>-5149 (-----) [001] ...1 143.149856: tracing_mark_write: B|756|[NN_LCC_PE][optim 45 # HwBinder:784_1-5236 ( 784) [001] ...1 397.528915: tracing_mark_write: B|784|HIDL:: 46 # GLThread 35-1739 ( 1500) [001] ...1 277.001798: tracing_mark_write: B|1500|HIDL::IMapper::importBuffer::passthrough 47 # Notes: 48 # - systrace enter/exit marks are per PID, which is really a thread id on Linux 49 # - TGIDs identify processes 50 # 51 mark_matcher = re.compile(r"([BE])\|(\d+).*") 52 tracked_pids = {} 53 driver_tgids = {} 54 pid_to_tgid = {} 55 parsed = [] 56 seen_nnapi_runtime = False 57 for [line, lineno] in trace: 58 m = MATCHER.match(line) 59 m_old = MATCHER_FOR_OLD.match(line) 60 if not m and not m_old: 61 # Check parsing doesn't discard interesting lines 62 assert not "HIDL::IDevice" in line, line 63 assert not "[NN_" in line, line 64 assert not "tracing_mark_write: B" in line, line 65 assert not "tracing_mark_write: E" in line, line 66 continue 67 if m: 68 [task, pid, tgid, time, mark] = m.groups() 69 else: 70 [task, pid, time, mark] = m_old.groups() 71 if "|" in mark: 72 tgid = mark.split("|")[1] 73 else: 74 tgid = pid_to_tgid[pid] 75 assert pid 76 pid_to_tgid[pid] = tgid 77 if tgid == "-----": 78 mm = mark_matcher.match(mark) 79 tgid = mm.group(2) 80 assert tgid 81 parsed.append( [task, pid, tgid, time, mark, line, lineno] ) 82 if "[NN" in mark: 83 tracked_pids[pid] = tgid 84 if "NN_LR" in mark: 85 seen_nnapi_runtime = True 86 if "HIDL::IDevice" in mark and "::server" in mark: 87 tracked_pids[pid] = tgid 88 driver_tgids[tgid] = True 89 90 if not seen_nnapi_runtime: 91 sys.stderr.write("\n*** No NNAPI Runtime trace present - check your systrace setup ***\n\n") 92 return tracked_pids, driver_tgids, parsed 93 94