catapipe.py
120 lines
| 3.5 KiB
| text/x-python
|
PythonLexer
/ contrib / catapipe.py
Augie Fackler
|
r39288 | #!/usr/bin/env python3 | ||
# | ||||
# Copyright 2018 Google LLC. | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
"""Tool read primitive events from a pipe to produce a catapult trace. | ||||
Kyle Lippincott
|
r40526 | Usage: | ||
Terminal 1: $ catapipe.py /tmp/mypipe /tmp/trace.json | ||||
Terminal 2: $ HGCATAPULTSERVERPIPE=/tmp/mypipe hg root | ||||
<ctrl-c catapipe.py in Terminal 1> | ||||
$ catapult/tracing/bin/trace2html /tmp/trace.json # produce /tmp/trace.html | ||||
<open trace.html in your browser of choice; the WASD keys are very useful> | ||||
(catapult is located at https://github.com/catapult-project/catapult) | ||||
Augie Fackler
|
r39288 | For now the event stream supports | ||
START $SESSIONID ... | ||||
and | ||||
END $SESSIONID ... | ||||
events. Everything after the SESSIONID (which must not contain spaces) | ||||
is used as a label for the event. Events are timestamped as of when | ||||
they arrive in this process and are then used to produce catapult | ||||
traces that can be loaded in Chrome's about:tracing utility. It's | ||||
important that the event stream *into* this process stay simple, | ||||
because we have to emit it from the shell scripts produced by | ||||
run-tests.py. | ||||
Typically you'll want to place the path to the named pipe in the | ||||
HGCATAPULTSERVERPIPE environment variable, which both run-tests and hg | ||||
Kyle Lippincott
|
r40526 | understand. To trace *only* run-tests, use HGTESTCATAPULTSERVERPIPE instead. | ||
Augie Fackler
|
r39288 | """ | ||
import argparse | ||||
import json | ||||
import os | ||||
Boris Feld
|
r39550 | import timeit | ||
Augie Fackler
|
r39288 | |||
_TYPEMAP = { | ||||
'START': 'B', | ||||
'END': 'E', | ||||
Augie Fackler
|
r42675 | 'COUNTER': 'C', | ||
Augie Fackler
|
r39288 | } | ||
_threadmap = {} | ||||
Boris Feld
|
r39550 | # Timeit already contains the whole logic about which timer to use based on | ||
# Python version and OS | ||||
timer = timeit.default_timer | ||||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r39288 | def main(): | ||
parser = argparse.ArgumentParser() | ||||
Augie Fackler
|
r43346 | parser.add_argument( | ||
'pipe', | ||||
type=str, | ||||
nargs=1, | ||||
help='Path of named pipe to create and listen on.', | ||||
) | ||||
parser.add_argument( | ||||
'output', | ||||
default='trace.json', | ||||
type=str, | ||||
nargs='?', | ||||
help='Path of json file to create where the traces ' 'will be stored.', | ||||
) | ||||
parser.add_argument( | ||||
'--debug', | ||||
default=False, | ||||
action='store_true', | ||||
help='Print useful debug messages', | ||||
) | ||||
Augie Fackler
|
r39288 | args = parser.parse_args() | ||
fn = args.pipe[0] | ||||
os.mkfifo(fn) | ||||
try: | ||||
with open(fn) as f, open(args.output, 'w') as out: | ||||
out.write('[\n') | ||||
Boris Feld
|
r39550 | start = timer() | ||
Augie Fackler
|
r39288 | while True: | ||
ev = f.readline().strip() | ||||
if not ev: | ||||
continue | ||||
Boris Feld
|
r39550 | now = timer() | ||
Augie Fackler
|
r39288 | if args.debug: | ||
print(ev) | ||||
verb, session, label = ev.split(' ', 2) | ||||
if session not in _threadmap: | ||||
_threadmap[session] = len(_threadmap) | ||||
Augie Fackler
|
r42675 | if verb == 'COUNTER': | ||
amount, label = label.split(' ', 1) | ||||
payload_args = {'value': int(amount)} | ||||
else: | ||||
payload_args = {} | ||||
Augie Fackler
|
r39288 | pid = _threadmap[session] | ||
Augie Fackler
|
r39971 | ts_micros = (now - start) * 1000000 | ||
Augie Fackler
|
r43346 | out.write( | ||
json.dumps( | ||||
{ | ||||
"name": label, | ||||
"cat": "misc", | ||||
"ph": _TYPEMAP[verb], | ||||
"ts": ts_micros, | ||||
"pid": pid, | ||||
"tid": 1, | ||||
"args": payload_args, | ||||
} | ||||
) | ||||
) | ||||
Augie Fackler
|
r39288 | out.write(',\n') | ||
finally: | ||||
os.unlink(fn) | ||||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r39288 | if __name__ == '__main__': | ||
main() | ||||