##// END OF EJS Templates
wireprotov2peer: stream decoded responses...
wireprotov2peer: stream decoded responses Previously, wire protocol version 2 would buffer all response data. Only once all data was received did we CBOR decode it and resolve the future associated with the command. This was obviously not desirable. In future commits that introduce large response payloads, this caused significant memory bloat and slowed down client operations due to waiting on the server. This commit refactors the response handling code so that response data can be streamed. Command response objects now contain a buffered CBOR decoder. As new data arrives, it is fed into the decoder. Decoded objects are made available to the generator as they are decoded. Because there is a separate thread processing incoming frames and feeding data into the response object, there is the potential for race conditions when mutating response objects. So a lock has been added to guard access to critical state variables. Because the generator emitting decoded objects needs to wait on those objects to become available, we've added an Event for the generator to wait on so it doesn't busy loop. This does mean there is the potential for deadlocks. And I'm pretty sure they can occur in some scenarios. We already have a handful of TODOs around this. But I've added some more. Fixing this will likely require moving the background thread receiving frames into clienthandler. We likely would have done this anyway when implementing the client bits for the SSH transport. Test output changes because the initial CBOR map holding the overall response state is now always handled internally by the response object. Differential Revision: https://phab.mercurial-scm.org/D4474

File last commit:

r35854:d4e5b265 default
r39597:d06834e0 default
Show More
lsprof.py
121 lines | 4.0 KiB | text/x-python | PythonLexer
Gregory Szorc
lsprof: use print function
r27617 from __future__ import absolute_import, print_function
Gregory Szorc
lsprof: support PyPy (issue4573)...
r27061
import _lsprof
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 import sys
Gregory Szorc
lsprof: support PyPy (issue4573)...
r27061
Profiler = _lsprof.Profiler
# PyPy doesn't expose profiler_entry from the module.
profiler_entry = getattr(_lsprof, 'profiler_entry', None)
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422
__all__ = ['profile', 'Stats']
def profile(f, *args, **kwds):
"""XXX docstring"""
p = Profiler()
Dirkjan Ochtman
updating lsprof.py from remote repository
r5992 p.enable(subcalls=True, builtins=True)
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 try:
Dirkjan Ochtman
updating lsprof.py from remote repository
r5992 f(*args, **kwds)
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 finally:
p.disable()
Dirkjan Ochtman
updating lsprof.py from remote repository
r5992 return Stats(p.getstats())
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422
class Stats(object):
"""XXX docstring"""
def __init__(self, data):
self.data = data
Augie Fackler
lsprof: use native string when peeking in __dict__...
r35854 def sort(self, crit=r"inlinetime"):
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 """XXX docstring"""
Gregory Szorc
lsprof: support PyPy (issue4573)...
r27061 # profiler_entries isn't defined when running under PyPy.
if profiler_entry:
if crit not in profiler_entry.__dict__:
raise ValueError("Can't sort by %s" % crit)
elif self.data and not getattr(self.data[0], crit, None):
Peter Ruibal
use Exception(args)-style raising consistently (py3k compatibility)
r7008 raise ValueError("Can't sort by %s" % crit)
Gregory Szorc
lsprof: support PyPy (issue4573)...
r27061
Alejandro Santos
compat: use 'key' argument instead of 'cmp' when sorting a list
r9032 self.data.sort(key=lambda x: getattr(x, crit), reverse=True)
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 for e in self.data:
if e.calls:
Alejandro Santos
compat: use 'key' argument instead of 'cmp' when sorting a list
r9032 e.calls.sort(key=lambda x: getattr(x, crit), reverse=True)
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422
def pprint(self, top=None, file=None, limit=None, climit=None):
"""XXX docstring"""
if file is None:
file = sys.stdout
d = self.data
if top is not None:
d = d[:top]
Dirkjan Ochtman
updating lsprof.py from remote repository
r5992 cols = "% 12s %12s %11.4f %11.4f %s\n"
hcols = "% 12s %12s %12s %12s %s\n"
Bryan O'Sullivan
lsprof: report units correctly
r16804 file.write(hcols % ("CallCount", "Recursive", "Total(s)",
"Inline(s)", "module:lineno(function)"))
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 count = 0
for e in d:
Dirkjan Ochtman
updating lsprof.py from remote repository
r5992 file.write(cols % (e.callcount, e.reccallcount, e.totaltime,
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 e.inlinetime, label(e.code)))
count += 1
if limit is not None and count == limit:
return
ccount = 0
Matt Mackall
profile: add undocumented config options for profiler output
r16263 if climit and e.calls:
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 for se in e.calls:
Mads Kiilerich
profiling: replace '+' markup of nested lines with indentation...
r18642 file.write(cols % (se.callcount, se.reccallcount,
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 se.totaltime, se.inlinetime,
Mads Kiilerich
profiling: replace '+' markup of nested lines with indentation...
r18642 " %s" % label(se.code)))
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 count += 1
ccount += 1
if limit is not None and count == limit:
return
if climit is not None and ccount == climit:
break
def freeze(self):
"""Replace all references to code objects with string
descriptions; this makes it possible to pickle the instance."""
# this code is probably rather ickier than it needs to be!
for i in range(len(self.data)):
e = self.data[i]
if not isinstance(e.code, str):
self.data[i] = type(e)((label(e.code),) + e[1:])
Dirkjan Ochtman
updating lsprof.py from remote repository
r5992 if e.calls:
for j in range(len(e.calls)):
se = e.calls[j]
if not isinstance(se.code, str):
e.calls[j] = type(se)((label(se.code),) + se[1:])
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422
_fn2mod = {}
def label(code):
if isinstance(code, str):
return code
try:
mname = _fn2mod[code.co_filename]
except KeyError:
Dirkjan Ochtman
lsprof: make profile not die when imported modules changes (issue1774)
r9314 for k, v in list(sys.modules.iteritems()):
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 if v is None:
continue
Augie Fackler
lsprof: use getattr instead of hasattr
r14959 if not isinstance(getattr(v, '__file__', None), str):
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 continue
if v.__file__.startswith(code.co_filename):
mname = _fn2mod[code.co_filename] = k
break
else:
Benoit Boissinot
fix spaces/identation issues
r10339 mname = _fn2mod[code.co_filename] = '<%s>' % code.co_filename
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422
return '%s:%d(%s)' % (mname, code.co_firstlineno, code.co_name)
if __name__ == '__main__':
import os
sys.argv = sys.argv[1:]
if not sys.argv:
Gregory Szorc
lsprof: use print function
r27617 print("usage: lsprof.py <script> <arguments...>", file=sys.stderr)
Vadim Gelfer
add --lsprof option. 3x faster than --profile, more useful output....
r2422 sys.exit(2)
sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0])))
stats = profile(execfile, sys.argv[0], globals(), locals())
stats.sort()
stats.pprint()