##// END OF EJS Templates
diff: do not concatenate immutable bytes while building a/b bodies (issue6445)...
diff: do not concatenate immutable bytes while building a/b bodies (issue6445) Use bytearray instead. I don't know what's changed since Python 2, but bytes concatenation is 100x slow on Python 3. % python2.7 -m timeit -s "s = b''" "for i in range(10000): s += b'line'" 1000 loops, best of 3: 321 usec per loop % python3.9 -m timeit -s "s = b''" "for i in range(10000): s += b'line'" 5 loops, best of 5: 39.2 msec per loop Benchmark using tailwind.css (measuring the fast path, a is empty): % HGRCPATH=/dev/null python2.7 ./hg log -R /tmp/issue6445 -p --time \ --color=always --config diff.word-diff=true >/dev/null (prev) time: real 1.580 secs (user 1.560+0.000 sys 0.020+0.000) (this) time: real 1.610 secs (user 1.570+0.000 sys 0.030+0.000) % HGRCPATH=/dev/null python3.9 ./hg log -R /tmp/issue6445 -p --time \ --color=always --config diff.word-diff=true >/dev/null (prev) time: real 114.500 secs (user 114.460+0.000 sys 0.030+0.000) (this) time: real 2.180 secs (user 2.140+0.000 sys 0.040+0.000) Benchmark using random tabular text data (not the fast path): % dd if=/dev/urandom bs=1k count=1000 | hexdump -v -e '16/1 "%3u," "\n"' > ttf % hg ci -ma % dd if=/dev/urandom bs=1k count=1000 | hexdump -v -e '16/1 "%3u," "\n"' > ttf % hg ci -mb % HGRCPATH=/dev/null python2.7 ./hg log -R /tmp/issue6445 -p --time \ --color=always --config diff.word-diff=true >/dev/null (prev) time: real 3.240 secs (user 3.040+0.000 sys 0.200+0.000 (this) time: real 3.230 secs (user 3.070+0.000 sys 0.160+0.000) % HGRCPATH=/dev/null python3.9 ./hg log -R /tmp/issue6445 -p --time \ --color=always --config diff.word-diff=true >/dev/null (prev) time: real 44.130 secs (user 43.850+0.000 sys 0.270+0.000) (this) time: real 4.170 secs (user 3.850+0.000 sys 0.310+0.000)

File last commit:

r43347:687b865b default
r46624:210f9b8d stable
Show More
pushkey.py
71 lines | 1.7 KiB | text/x-python | PythonLexer
# pushkey.py - dispatching for pushing and pulling keys
#
# Copyright 2010 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
from . import (
bookmarks,
encoding,
obsolete,
phases,
)
def _nslist(repo):
n = {}
for k in _namespaces:
n[k] = b""
if not obsolete.isenabled(repo, obsolete.exchangeopt):
n.pop(b'obsolete')
return n
_namespaces = {
b"namespaces": (lambda *x: False, _nslist),
b"bookmarks": (bookmarks.pushbookmark, bookmarks.listbookmarks),
b"phases": (phases.pushphase, phases.listphases),
b"obsolete": (obsolete.pushmarker, obsolete.listmarkers),
}
def register(namespace, pushkey, listkeys):
_namespaces[namespace] = (pushkey, listkeys)
def _get(namespace):
return _namespaces.get(namespace, (lambda *x: False, lambda *x: {}))
def push(repo, namespace, key, old, new):
'''should succeed iff value was old'''
pk = _get(namespace)[0]
return pk(repo, key, old, new)
def list(repo, namespace):
'''return a dict'''
lk = _get(namespace)[1]
return lk(repo)
encode = encoding.fromlocal
decode = encoding.tolocal
def encodekeys(keys):
"""encode the content of a pushkey namespace for exchange over the wire"""
return b'\n'.join([b'%s\t%s' % (encode(k), encode(v)) for k, v in keys])
def decodekeys(data):
"""decode the content of a pushkey namespace from exchange over the wire"""
result = {}
for l in data.splitlines():
k, v = l.split(b'\t')
result[decode(k)] = decode(v)
return result