def test_multiple_process(self): data = '{"traceEvents": [{"pid":7762,"tid":7761,"ts":23668655766.343,"dur":5.8,"name":"builtins.exec","caller_lineno":147,"ph":"X","cat":"FEE"}, {"pid":7761,"tid":7761,"ts":23668655766.343,"dur":5.8,"name":"builtins.exec","caller_lineno":147,"ph":"X","cat":"FEE"}], "viztracer_metadata": {"version": "0.6.2"}}' snap = ProgSnapshot(data) self.assertEqual(len(list(snap.get_trees())), 2) # Coverage test _ = snap.list_pid()
def test_change_parent(self): data = '{"traceEvents": [{"pid":7762,"tid":7761,"ts":0,"dur":100,"name":"grandpa","caller_lineno":147,"ph":"X","cat":"FEE"}, {"pid":7762,"tid":7761,"ts":50,"dur":10,"name":"grandson","caller_lineno":147,"ph":"X","cat":"FEE"}, {"pid":7762,"tid":7761,"ts":10,"dur":80,"name":"son","caller_lineno":147,"ph":"X","cat":"FEE"}], "viztracer_metadata": {"version": "0.6.2"}}' snap = ProgSnapshot(data) tree = next(snap.get_trees()) for node in tree.inorder_traverse(): if node.parent: self.assertIn(node, node.parent.children)
def test_invalid(self): data = '{"traceEvents": [{"ph": "hello"}], "viztracer_metadata": {"version": "0.6.2"}}' with self.assertRaises(ValueError): _ = ProgSnapshot(data) data = '{"traceEvents": [{"ph": "hello", "pid": 1, "tid": 1}], "viztracer_metadata": {"version": "0.6.2"}}' with self.assertRaises(ValueError): _ = ProgSnapshot(data)
def test_basic(self): snap = ProgSnapshot(test1_str) tree_len = len(list(snap.get_trees())) self.assertEqual(tree_len, 1) tree = next(snap.get_trees()) count = 0 for _ in tree.inorder_traverse(): count += 1 self.assertEqual(count, 12)
def test_version(self): no_version_str = '{"traceEvents":[]}' snap = ProgSnapshot(no_version_str) self.assertFalse(snap.valid) low_version_str = '{"traceEvents":[], "viztracer_metadata":{"version":"0.0.1"}}' snap = ProgSnapshot(low_version_str) self.assertFalse(snap.valid) # Pure coverage high_version_str = '{"traceEvents":[{"pid":7761,"tid":7761,"ts":23668655766.343,"dur":5.8,"name":"builtins.exec","caller_lineno":147,"ph":"X","cat":"FEE"}], "viztracer_metadata":{"version":"1000.0.1"}}' snap = ProgSnapshot(high_version_str)
def test_next(self): snap = ProgSnapshot(test1_str) self.assertEqual(snap.curr_frame.node.fullname, "builtins.exec") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "<module>") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "t") snap.next() self.assertEqual(snap.curr_frame.node.funcname, "t") self.assertEqual(snap.curr_frame.curr_children_idx, 1)
def test_random_entries(self): import random snap = ProgSnapshot(test1_str) test_obj = json.loads(test1_str) random.shuffle(test_obj["traceEvents"]) snap2 = ProgSnapshot(json.dumps(test_obj)) self.assertTrue(list(snap.get_trees())[0].is_same(list(snap2.get_trees())[0]))
def test_object(self): data = '{"traceEvents": [{"pid":1,"tid":1,"ts":0.05,"dur":5.8,"name":"builtins.exec","caller_lineno":147,"ph":"X","cat":"FEE"}, {"ph": "N", "pid": 1, "tid": 1, "ts": 0.1, "id": 1000, "name": "a"}, {"ph": "D", "pid": 1, "tid": 1, "ts": 0.3, "id": 1000, "name": "a"}], "viztracer_metadata": {"version": "0.6.2"}}' snap = ProgSnapshot(data) self.assertEqual(len(snap.object_events._objects), 1)
def test_step(self): snap = ProgSnapshot(test1_str) self.assertEqual(snap.curr_frame.node.fullname, "builtins.exec") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "<module>") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "t") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "f") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "g") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "h") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "g") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "f") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "h") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "f") snap.step() self.assertEqual(snap.curr_frame.node.funcname, "t")
def main(argv=sys.argv): parser = argparse.ArgumentParser( argv[0], formatter_class=argparse.RawDescriptionHelpFormatter, usage=usage) parser.add_argument( '--verbose', '-v', action='count', default=0) # by default quiet, since we write to stdout parser.add_argument('--quiet', '-q', action='count', default=0) parser.add_argument( '--keep-cpython-evals', help= "keep CPython evaluation stacktraces (instead of replacing) (default: %(default)s)", default=False, action='store_true') parser.add_argument('--no-keep-cpython-evals', dest="keep_cpython_evals", action='store_false') parser.add_argument( '--allow-mismatch', help= "Keep going even when we cannot match the C and Python stacktrace (default: %(default)s)", default=False, action='store_true') parser.add_argument('--no-allow-mismatch', dest="allow_mismatch", action='store_false') parser.add_argument( '--pedantic', help= "If false, accept known stack mismatch issues (default: %(default)s)", default=False, action='store_true') parser.add_argument('--no-pedantic', dest="pedantic", action='store_false') parser.add_argument('--input', '-i', help="VizTracer input (default %(default)s)", default="viztracer.json") parser.add_argument('--output', '-o', dest="output", default=None, help="Output filename (default %(default)s)") args = parser.parse_args(argv[1:]) verbose = args.verbose - args.quiet perf_script_args = ['--no-inline'] perf_script_args = ' '.join(perf_script_args) cmd = f"perf script {perf_script_args}" if verbose >= 2: print(f"Running: {cmd}") perf_args = shlex.split(cmd) perf = subprocess.Popen(perf_args, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) #, stdin=subprocess.PIPE) if args.output is None: output = sys.stdout else: output = open(args.output, "w") if verbose >= 1: print_stderr("Loading snapshot") with open(args.input, "r") as f: json_data = f.read() snap = ProgSnapshot(json_data) # find all pids (or tids) pids = list(snap.func_trees) for pid in pids.copy(): pids.extend(list(snap.func_trees[pid])) t0 = min(event['ts'] for event in json.loads(json_data)['traceEvents']) for header, stacktrace in read_events(perf.stdout): print(header, file=output) values, _, _ = parse_header(header) time = values['time'] - t0 triggerpid = values['triggerpid'] if triggerpid in pids: try: stacktrace = stacktrace_inject( stacktrace, snap, triggerpid, time, keep_cpython_evals=args.keep_cpython_evals, allow_mismatch=args.allow_mismatch, pedantic=args.pedantic) for call in stacktrace: print(call, file=output) except: print(f"Error for event: {header}") raise print(file=output)
def main(argv=sys.argv): parser = argparse.ArgumentParser( argv[0], formatter_class=argparse.RawDescriptionHelpFormatter, usage=usage) parser.add_argument( '--verbose', '-v', action='count', default=0) # by default quiet, since we write to stdout parser.add_argument('--quiet', '-q', action='count', default=0) parser.add_argument('--state', help='State to match (default: %(default)s)', default="S(GIL)") parser.add_argument( '--strip-take-gil', dest="strip_take_gil", help= "Remove everything from the stack above take_gil (default: %(default)s)", default=True, action='store_true') parser.add_argument('--no-strip-take-gil', dest="strip_take_gil", action='store_false') parser.add_argument( '--keep-cpython-evals', help= "keep CPython evaluation stacktraces (instead of replacing) (default: %(default)s)", default=False, action='store_true') parser.add_argument('--no-keep-cpython-evals', dest="keep_cpython_evals", action='store_false') parser.add_argument( '--allow-mismatch', help= "Keep going even when we cannot match the C and Python stacktrace (default: %(default)s)", default=False, action='store_true') parser.add_argument('--no-allow-mismatch', dest="allow_mismatch", action='store_false') parser.add_argument( '--pedantic', help= "If false, accept known stack mismatch issues (default: %(default)s)", default=False, action='store_true') parser.add_argument('--no-pedantic', dest="pedantic", action='store_false') parser.add_argument('--input-perf', help="Perf input (default %(default)s)", default="perf-sched.data") parser.add_argument('--input-viztracer', help="VizTracer input (default %(default)s)", default="viztracer.json") parser.add_argument('--output', '-o', dest="output", default=None, help="Output filename (default %(default)s)") args = parser.parse_args(argv[1:]) verbose = args.verbose - args.quiet perf_script_args = ['--no-inline'] perf_script_args = ' '.join(perf_script_args) cmd = f"perf script {perf_script_args} -i {args.input_perf}" if verbose >= 2: print(f"Running: {cmd}") perf_args = shlex.split(cmd) perf = subprocess.Popen(perf_args, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) #, stdin=subprocess.PIPE) if args.output is None: output = sys.stdout else: output = open(args.output, "w") if verbose >= 1: print_stderr("Loading snapshot") with open(args.input_viztracer, "r") as f: json_data = f.read() snap = ProgSnapshot(json_data) # find all pids (or tids) pids = list(snap.func_trees) for pid in pids.copy(): pids.extend(list(snap.func_trees[pid])) t0 = min(event['ts'] for event in json.loads(json_data)['traceEvents'] if 'ts' in event) for header, stacktrace, event in perf2trace(perf.stdout, verbose): if event['name'] == args.state: values, _, _ = parse_header(header) time = values['time'] - t0 triggerpid = event['tid'] if triggerpid in pids: try: stacktrace = stacktrace_inject( stacktrace, snap, triggerpid, time, keep_cpython_evals=args.keep_cpython_evals, allow_mismatch=args.allow_mismatch, pedantic=args.pedantic) if args.strip_take_gil: take_gil_index = None for i, call in enumerate(stacktrace): if 'take_gil' in call: take_gil_index = i if take_gil_index is not None: # shouldn't it be always there? stacktrace = stacktrace[take_gil_index:] for call in stacktrace: ptr, signature = call.split(' ', 1) print(signature, file=output) except: print_stderr(f"Error for event: {header}") raise print(int(event['dur'])) print(file=output)
def test_invalid_filename(self): data = '{"traceEvents": [{"pid":7761,"tid":7761,"ts":23668655769.443,"dur":0.4,"name":"_handle_fromlist (<frozen importlib._bootstrap>:1017)","caller_lineno":10,"ph":"X","cat":"FEE"}], "viztracer_metadata": {"version": "0.9.5"}}' # noqa: E501 prog = ProgSnapshot(data) prog.show()