""" NNAPI systrace parser - getting data in from a systrace html output """ import re import sys def get_trace_part(filename): """ Finds the text trace in the given html file, returns as a string. """ with open(filename) as f: lines = f.readlines() seen_begin = False trace = [] lineno = 0 for line in lines: lineno = lineno + 1 if ("# TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION" in line or "# TASK-PID CPU# |||| TIMESTAMP FUNCTION" in line): seen_begin = True if seen_begin: if "" in line: break trace.append([line, lineno]) return trace MATCHER = re.compile(r"^\s*([^ ].{1,15})-(\d+)\s+\(\s*([-0-9]+)\) .* (\d+\.\d+): tracing_mark_write: ([BE].*)$") MATCHER_FOR_OLD = re.compile(r"^\s*([^ ].{1,15})-(\d+) .* (\d+\.\d+): tracing_mark_write: ([BE].*)$") def parse_trace_part(trace): """ Takes a string containing the text trace form systrace, parses the rows and selects which threads we are interested in. Returns (tracked_pids, driver_tgids, parsed), where: - tracked_pids: map from pids we are interested in to their tgids - driver_tgids: map that contains tgids of NNAPI driver processes - parsed: list of parsed rows, each containing TASK, PID, TGID, TIMESTAMP and FUNCTION as shown below """ # Row format # # TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION" in line: # # | | | | |||| | | # NeuralNetworks-5143 ( 5143) [005] ...1 142.924145: tracing_mark_write: B|5143|[NN_L # <...>-5149 ( 774) [000] ...1 143.103773: tracing_mark_write: B|774|[NN_LDV_PC][validat # <...>-756 ( 756) [000] ...1 143.140553: tracing_mark_write: B|756|HIDL::IDevice::prepa # <...>-5149 (-----) [001] ...1 143.149856: tracing_mark_write: B|756|[NN_LCC_PE][optim # HwBinder:784_1-5236 ( 784) [001] ...1 397.528915: tracing_mark_write: B|784|HIDL:: # GLThread 35-1739 ( 1500) [001] ...1 277.001798: tracing_mark_write: B|1500|HIDL::IMapper::importBuffer::passthrough # Notes: # - systrace enter/exit marks are per PID, which is really a thread id on Linux # - TGIDs identify processes # mark_matcher = re.compile(r"([BE])\|(\d+).*") tracked_pids = {} driver_tgids = {} pid_to_tgid = {} parsed = [] seen_nnapi_runtime = False for [line, lineno] in trace: m = MATCHER.match(line) m_old = MATCHER_FOR_OLD.match(line) if not m and not m_old: # Check parsing doesn't discard interesting lines assert not "HIDL::IDevice" in line, line assert not "[NN_" in line, line assert not "tracing_mark_write: B" in line, line assert not "tracing_mark_write: E" in line, line continue if m: [task, pid, tgid, time, mark] = m.groups() else: [task, pid, time, mark] = m_old.groups() if "|" in mark: tgid = mark.split("|")[1] else: tgid = pid_to_tgid[pid] assert pid pid_to_tgid[pid] = tgid if tgid == "-----": mm = mark_matcher.match(mark) tgid = mm.group(2) assert tgid parsed.append( [task, pid, tgid, time, mark, line, lineno] ) if "[NN" in mark: tracked_pids[pid] = tgid if "NN_LR" in mark: seen_nnapi_runtime = True if "HIDL::IDevice" in mark and "::server" in mark: tracked_pids[pid] = tgid driver_tgids[tgid] = True if not seen_nnapi_runtime: sys.stderr.write("\n*** No NNAPI Runtime trace present - check your systrace setup ***\n\n") return tracked_pids, driver_tgids, parsed