Rev 5367: Parse times are dramatically improved. in http://bazaar.launchpad.net/~jameinel/bzr/2.3-btree-chk-leaf
John Arbash Meinel
john at arbash-meinel.com
Tue Aug 3 22:15:03 BST 2010
At http://bazaar.launchpad.net/~jameinel/bzr/2.3-btree-chk-leaf
------------------------------------------------------------
revno: 5367
revision-id: john at arbash-meinel.com-20100803211445-yfaqzmzvf8ybi28a
parent: john at arbash-meinel.com-20100803205639-k23colcozyd14440
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.3-btree-chk-leaf
timestamp: Tue 2010-08-03 16:14:45 -0500
message:
Parse times are dramatically improved.
using _LeafNode directly, the total parse time is actually 369us.
Putting all the items into a 'dict' ends up costing 250us by itself,
and a minor overhead to put that into the _LeafNode object itself.
Switching it around to call parsed(buffer...).all_items() to actually
construct the items again, and we see that it costs another 120us for
the _LeafNode implementation (which has to sort), while the Pyrex
implementation goes from 50us to parse, to just 120us to create all
the objects and return them.
It doesn't have to sort, because they are stored in sorted order.
all_keys() is even better at 94us vs 454us.
I'm rather impressed that PyString_FromFormat is actually pretty
reasonable. Certainly inefficient overall (since we'll eventually
parse back into ints again), but does a good job.
-------------- next part --------------
=== modified file 'bzrlib/_btree_serializer_pyx.pyx'
--- a/bzrlib/_btree_serializer_pyx.pyx 2010-08-03 20:56:39 +0000
+++ b/bzrlib/_btree_serializer_pyx.pyx 2010-08-03 21:14:45 +0000
@@ -322,6 +322,11 @@
return parser.parse()
+# TODO: We can go from 8 byte offset + 4 byte length to a simple lookup,
+# because the block_offset + length is likely to be repeated. However,
+# the big win there is to cache across pages, and not just one page
+# Though if we did cache in a page, we could certainly use a short int.
+# And this goes from 40 bytes to 30 bytes.
ctypedef struct gc_chk_sha1_record:
unsigned long long block_offset
unsigned int block_length
@@ -400,11 +405,15 @@
property min_key:
def __get__(self):
- pass
+ if self.num_entries > 0:
+ return self._sha1_to_key(self.entries[0].sha1)
+ return None
property max_key:
def __get__(self):
- pass
+ if self.num_entries > 0:
+ return self._sha1_to_key(self.entries[self.num_entries-1].sha1)
+ return None
cdef int _key_to_sha1(self, key, char *sha1):
"""Map a key into its sha1 content.
@@ -441,6 +450,7 @@
key = StaticTuple_New(1)
Py_INCREF(hexxed)
StaticTuple_SET_ITEM(key, 0, hexxed)
+ key = StaticTuple_Intern(key)
return key
cdef StaticTuple _record_to_value_and_refs(self,
@@ -510,16 +520,17 @@
def all_keys(self):
cdef int i
- cdef list result
+ cdef list result = []
for i from 0 <= i < self.num_entries:
result.append(self._sha1_to_key(self.entries[i].sha1))
return result
def all_items(self):
cdef int i
- cdef list result
+ cdef list result = []
for i from 0 <= i < self.num_entries:
- result.append(self._record_to_item(self.entries + i))
+ item = self._record_to_item(&self.entries[i])
+ result.append(item)
return result
cdef _parse_bytes(self, bytes):
@@ -529,13 +540,9 @@
cdef char *c_cur
cdef char *c_end
cdef char *c_next
- cdef char *c_sha1_prefix
- cdef void *buf
cdef Py_ssize_t n_bytes
cdef int num_entries
cdef int entry
- cdef int interesting_char
- cdef int i
cdef gc_chk_sha1_record *cur_record
if not PyString_CheckExact(bytes):
@@ -559,14 +566,12 @@
# Now allocate the memory for these items, and go to town
# We allocate both the offsets and the entries in the same malloc. we
# should probably pay a bit closer attention to alignment
- buf = PyMem_Malloc(num_entries *
+ self.entries = <gc_chk_sha1_record*>PyMem_Malloc(num_entries *
(sizeof(unsigned short) + sizeof(gc_chk_sha1_record)))
- self.entries = <gc_chk_sha1_record*>buf
self.num_entries = num_entries
c_cur = c_content
cur_record = self.entries
entry = 0
- interesting_char = -1
while c_cur != NULL and c_cur < c_end and entry < num_entries:
if strncmp(c_cur, 'sha1:', 5):
raise ValueError('At byte %d, line did not start with sha1: %r'
@@ -577,14 +582,6 @@
raise ValueError('Line did not contain 40 hex bytes')
if not _unhexlify_sha1(c_cur, cur_record.sha1):
raise ValueError('We failed to unhexlify')
- if interesting_char == -1:
- interesting_char = 20
- c_sha1_prefix = cur_record.sha1
- elif interesting_char > 0:
- for i from 0 <= i < interesting_char:
- if cur_record.sha1[i] != c_sha1_prefix[i]:
- interesting_char = i
- break
c_cur = c_next + 1
if c_cur[0] != c'\0':
raise ValueError('only 1 null, not 2 as expected')
More information about the bazaar-commits
mailing list