2016-03-02 01:18:10 +00:00
|
|
|
# To use the web() option, you should do:
|
|
|
|
# * cd misc
|
2016-04-29 21:28:04 +00:00
|
|
|
# * npm install d3 zepto
|
2016-03-02 01:18:10 +00:00
|
|
|
|
|
|
|
from __future__ import print_function
|
2016-04-29 21:28:04 +00:00
|
|
|
import os, sys, time, json, random
|
2016-03-02 01:18:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
streams = sys.argv[1:]
|
2016-04-29 21:28:04 +00:00
|
|
|
if not streams:
|
|
|
|
print("run like: python dump-timing.py tx.json rx.json")
|
|
|
|
sys.exit(1)
|
2016-03-02 01:18:10 +00:00
|
|
|
num_streams = len(streams)
|
|
|
|
labels = dict([(num, " "*num + "[%d]" % (num+1) + " "*(num_streams-1-num))
|
|
|
|
for num in range(num_streams)])
|
2016-04-29 21:28:04 +00:00
|
|
|
abs_timeline = []
|
|
|
|
sides = []
|
|
|
|
|
|
|
|
for side,fn in enumerate(streams):
|
2016-03-02 01:18:10 +00:00
|
|
|
with open(fn, "rb") as f:
|
2016-04-29 21:28:04 +00:00
|
|
|
for (start, sent, finish, what, details) in json.load(f):
|
|
|
|
abs_timeline.append( (start, sent, finish, side, what, details) )
|
|
|
|
print("%s is %s" % (labels[side], fn))
|
|
|
|
sides.append(os.path.basename(fn))
|
|
|
|
|
|
|
|
# relativize all timestamps
|
|
|
|
all_times = [e[0] for e in abs_timeline] + [e[2] for e in abs_timeline if e[2]]
|
|
|
|
all_times.sort()
|
|
|
|
earliest = all_times[0]
|
|
|
|
def rel(t):
|
|
|
|
if t is None: return None
|
|
|
|
return t - earliest
|
|
|
|
timeline = [ (rel(start), rel(sent), rel(finish), side, what, details)
|
|
|
|
for (start, sent, finish, side, what, details)
|
|
|
|
in abs_timeline ]
|
|
|
|
data = {}
|
|
|
|
|
|
|
|
# we pre-calculate the "lane" that each item uses, here in python, rather
|
|
|
|
# than leaving that up to the javascript.
|
|
|
|
data["lanes"] = ["proc", # 0 gets high-level events and spans: process start,
|
|
|
|
# imports, command dispatch, code established, key
|
|
|
|
# established, transit connected, process exit
|
|
|
|
"API", # 1 gets API call spans (apps usually only wait for
|
|
|
|
# one at a time, so they won't overlap): get_code,
|
|
|
|
# input_code, get_verifier, get_data, send_data,
|
|
|
|
# close
|
|
|
|
"wait", # 2 shows waiting-for-human: input code, get
|
|
|
|
# permission
|
|
|
|
"app", # 3: file-xfer events
|
|
|
|
"skt", # 4: websocket message send/receives
|
|
|
|
"misc", # 5: anything else
|
|
|
|
]
|
|
|
|
data["bounds"] = {"min": rel(all_times[0]), "max": rel(all_times[-1]),
|
|
|
|
}
|
|
|
|
data["sides"] = sides
|
|
|
|
print("started at %s" % time.ctime(earliest))
|
|
|
|
print("duration %s seconds" % data["bounds"]["max"])
|
|
|
|
items = data["items"] = []
|
|
|
|
|
|
|
|
for num, (start, sent, finish, side, what, details) in enumerate(timeline):
|
|
|
|
background = False
|
|
|
|
if what in ["wormhole",]:
|
|
|
|
# background region for wormhole lifetime
|
|
|
|
lane = 0
|
|
|
|
background = True
|
|
|
|
elif what in ["process start", "import", "command dispatch",
|
|
|
|
"code established", "key established", "transit connected",
|
|
|
|
"exit"]:
|
|
|
|
lane = 0
|
|
|
|
elif what in ["API get_code", "API input_code", "API set_code",
|
|
|
|
"API get_verifier", "API get_data", "API send_data",
|
|
|
|
#"API get data", "API send data",
|
|
|
|
"API close"]:
|
|
|
|
lane = 1
|
|
|
|
elif details.get("waiting") in ["user", "crypto"]: # permission or math
|
|
|
|
lane = 2
|
|
|
|
elif what in ["tx file", "get ack", "rx file", "unpack zip", "send ack"]:
|
|
|
|
lane = 3
|
|
|
|
elif what in ["websocket"]:
|
|
|
|
# connection establishment
|
|
|
|
lane = 4
|
|
|
|
background = True
|
|
|
|
elif (what in ["welcome", "error"] # rendezvous message receives
|
|
|
|
or what in ["allocate", "list", "get", "add", "deallocate"]
|
|
|
|
# rendezvous message sends
|
|
|
|
):
|
|
|
|
lane = 4
|
|
|
|
else:
|
|
|
|
lane = 5 # unknown
|
|
|
|
|
|
|
|
if background:
|
|
|
|
continue # disable until I figure out how to draw these better
|
|
|
|
|
|
|
|
details_str = ", ".join(["%s=%s" % (name, details[name])
|
|
|
|
for name in sorted(details)])
|
2016-03-02 01:18:10 +00:00
|
|
|
|
2016-04-29 21:28:04 +00:00
|
|
|
items.append({"side": side,
|
|
|
|
"lane": lane,
|
|
|
|
"start_time": start,
|
|
|
|
"server_sent": sent,
|
|
|
|
"finish_time": finish, # maybe None
|
|
|
|
"what": what,
|
|
|
|
"details": details,
|
|
|
|
"details_str": details_str,
|
|
|
|
"wiggle": random.randint(0,4),
|
|
|
|
})
|
2016-03-02 01:18:10 +00:00
|
|
|
|
2016-04-29 21:28:04 +00:00
|
|
|
#if "waiting" in details:
|
|
|
|
# viz_className += " wait-%s" % details["waiting"]
|
2016-03-04 02:06:26 +00:00
|
|
|
|
2016-04-29 21:28:04 +00:00
|
|
|
from pprint import pprint
|
|
|
|
pprint(data)
|
2016-03-02 01:18:10 +00:00
|
|
|
|
|
|
|
here = os.path.dirname(__file__)
|
|
|
|
web_root = os.path.join(here, "web")
|
2016-04-29 21:28:04 +00:00
|
|
|
lib_root = os.path.join(here, "node_modules")
|
|
|
|
if not os.path.isdir(lib_root):
|
|
|
|
print("Cannot find 'd3' and 'd3-tip' in misc/node_modules/")
|
|
|
|
print("Please run 'npm install d3 d3-tip zepto' from the misc/ directory.")
|
2016-03-02 01:18:10 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
def web():
|
|
|
|
# set up a server that serves web/ at the root, plus a /data.json built
|
|
|
|
# from {timeline}. Quit when it fetches /done .
|
|
|
|
from twisted.web import resource, static, server
|
|
|
|
from twisted.internet import reactor, endpoints
|
|
|
|
ep = endpoints.serverFromString(reactor, "tcp:8066:interface=127.0.0.1")
|
|
|
|
root = static.File(web_root)
|
2016-04-29 21:28:04 +00:00
|
|
|
root.putChild("data.json", static.Data(json.dumps(data).encode("utf-8"),
|
|
|
|
"application/json"))
|
|
|
|
root.putChild("lib", static.File(lib_root))
|
2016-03-02 01:18:10 +00:00
|
|
|
class Shutdown(resource.Resource):
|
|
|
|
def render_GET(self, request):
|
2016-04-29 21:28:04 +00:00
|
|
|
if 0:
|
|
|
|
print("timeline ready, server shutting down")
|
|
|
|
reactor.stop()
|
2016-03-02 01:18:10 +00:00
|
|
|
return "shutting down"
|
|
|
|
root.putChild("done", Shutdown())
|
|
|
|
site = server.Site(root)
|
|
|
|
ep.listen(site)
|
|
|
|
import webbrowser
|
|
|
|
def launch_browser():
|
|
|
|
webbrowser.open("http://localhost:%d/timeline.html" % 8066)
|
|
|
|
print("browser opened, waiting for shutdown")
|
|
|
|
reactor.callLater(0, launch_browser)
|
|
|
|
reactor.run()
|
|
|
|
web()
|
|
|
|
|