magic-wormhole/src/wormhole/timing.py
2018-04-21 13:00:08 +05:30

67 lines
2.1 KiB
Python

from __future__ import absolute_import, print_function, unicode_literals
import json
import time
from zope.interface import implementer
from ._interfaces import ITiming
class Event:
def __init__(self, name, when, **details):
# data fields that will be dumped to JSON later
self._name = name
self._start = time.time() if when is None else float(when)
self._stop = None
self._details = details
def detail(self, **details):
self._details.update(details)
def finish(self, when=None, **details):
self._stop = time.time() if when is None else float(when)
self.detail(**details)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, exc_tb):
if exc_type:
# inlineCallbacks uses a special exception (defer._DefGen_Return)
# to deliver returnValue(), so if returnValue is used inside our
# with: block, we'll mistakenly think it means something broke.
# I've moved all returnValue() calls outside the 'with
# timing.add()' blocks to avoid this, but if a new one
# accidentally pops up, it'll get marked as an error. I used to
# catch-and-release _DefGen_Return to avoid this, but removed it
# because it requires referencing defer.py's private class
self.finish(exception=str(exc_type))
else:
self.finish()
@implementer(ITiming)
class DebugTiming:
def __init__(self):
self._events = []
def add(self, name, when=None, **details):
ev = Event(name, when, **details)
self._events.append(ev)
return ev
def write(self, fn, stderr):
with open(fn, "wt") as f:
data = [
dict(
name=e._name,
start=e._start,
stop=e._stop,
details=e._details,
) for e in self._events
]
json.dump(data, f, indent=1)
f.write("\n")
print("Timing data written to %s" % fn, file=stderr)