[PATCH 1 of 2] rbc: use struct unpack_from and pack_into instead of unpack and pack

Mads Kiilerich mads at kiilerich.com
Sun Mar 12 19:33:55 UTC 2017


# HG changeset patch
# User Mads Kiilerich <madski at unity3d.com>
# Date 1476837995 -7200
#      Wed Oct 19 02:46:35 2016 +0200
# Node ID 023b6f7456b3622cc81332ae9d6e30b7ecc37415
# Parent  1c3352d7eaf24533ad52d4b8a024211e9189fb0b
rbc: use struct unpack_from and pack_into instead of unpack and pack

These functions were introduced in Python 2.5 and are faster and simpler than
the old ones ...  mainly because we can avoid intermediate buffers:

  $ python -m timeit -s "_rbcrecfmt='>4sI'" -s 's = "x"*10000' -s 'from struct import unpack' 'unpack(_rbcrecfmt, buffer(s, 16, 8))'
  1000000 loops, best of 3: 0.543 usec per loop
  $ python -m timeit -s "_rbcrecfmt='>4sI'" -s 's = "x"*10000' -s 'from struct import unpack_from' 'unpack_from(_rbcrecfmt, s, 16)'
  1000000 loops, best of 3: 0.323 usec per loop

  $ python -m timeit -s "from array import array" -s "_rbcrecfmt='>4sI'" -s "s = array('c')" -s 's.fromstring("x"*10000)' -s 'from struct import pack' -s "rec = array('c')" 'rec.fromstring(pack(_rbcrecfmt, "asdf", 7))'
  1000000 loops, best of 3: 0.364 usec per loop
  $ python -m timeit -s "from array import array" -s "_rbcrecfmt='>4sI'" -s "s = array('c')" -s 's.fromstring("x"*10000)' -s 'from struct import pack_into' -s "rec = array('c')" -s 'rec.fromstring("x"*100)' 'pack_into(_rbcrecfmt, rec, 0, "asdf", 7)'
  1000000 loops, best of 3: 0.229 usec per loop

diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py
--- a/mercurial/branchmap.py
+++ b/mercurial/branchmap.py
@@ -25,8 +25,8 @@ from . import (
 
 array = array.array
 calcsize = struct.calcsize
-pack = struct.pack
-unpack = struct.unpack
+pack_into = struct.pack_into
+unpack_from = struct.unpack_from
 
 def _filename(repo):
     """name of a branchcache file for a given repo or repoview"""
@@ -409,8 +409,7 @@ class revbranchcache(object):
 
         # fast path: extract data from cache, use it if node is matching
         reponode = changelog.node(rev)[:_rbcnodelen]
-        cachenode, branchidx = unpack(
-            _rbcrecfmt, buffer(self._rbcrevs, rbcrevidx, _rbcrecsize))
+        cachenode, branchidx = unpack_from(_rbcrecfmt, self._rbcrevs, rbcrevidx)
         close = bool(branchidx & _rbccloseflag)
         if close:
             branchidx &= _rbcbranchidxmask
@@ -454,13 +453,11 @@ class revbranchcache(object):
     def _setcachedata(self, rev, node, branchidx):
         """Writes the node's branch data to the in-memory cache data."""
         rbcrevidx = rev * _rbcrecsize
-        rec = array('c')
-        rec.fromstring(pack(_rbcrecfmt, node, branchidx))
         if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
             self._rbcrevs.extend('\0' *
                                  (len(self._repo.changelog) * _rbcrecsize -
                                   len(self._rbcrevs)))
-        self._rbcrevs[rbcrevidx:rbcrevidx + _rbcrecsize] = rec
+        pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx)
         self._rbcrevslen = min(self._rbcrevslen, rev)
 
         tr = self._repo.currenttransaction()


More information about the Mercurial-devel mailing list