2
Some quick notes about get_ancestry results when tested with bzr's ancestry
4
4401 Canonical.com Patch Queue Manager 2009-06-03 [merge]
5
revision-id:pqm@pqm.ubuntu.com-20090603080435-2gbqwzvbx31zr7ok
6
(andrew) Fix tracebacks when receiving error responses to
7
BzrDirFormat.initialize* RPCs.
9
This is in a fully packed repository, so there is only a single btree index,
10
and thus there should be only a small handful of genuinely missing keys.
12
First call to get_ancestry reads the root node, +1 internal node, +1 leaf node
13
It is able to expand from 1 key into 74 already know parent keys, and 75
16
Second call expands to 2 internal nodes (all of them), 14 leaf nodes, and 398
17
known parents, and 82 search tips. Of those 82 tips, 51 of them are present on
18
nodes that we had already read, we just didn't find them because we don't
19
search outside the current page for parent keys.
24
36 actually present on an unread LeafNode
25
794 parent_map (found parents)
48
103 really missing # went down?
50
103 leaf nodes (out of 221 total)
53
455 search keys (down?)
88
# I wonder if at this point a major limitation is the parents that are read but
89
# are not on the same page. You could have flip-flop cases, where you have:
90
# pqm@ => john@ => pqm@ => john@ => pqm@ => john@
91
# And each one of those is going to require another re-entrance into
94
gen search_keys parent_map parents_found
95
not loaded num_leaf_nodes_cached
101
5 246 108 2034 52 791
102
6 431 119 3272 79 1238
103
7 529 103 5472 103 2200
104
8 455 75 7759 119 2287
105
9 430 157 10004 130 2245
106
10 407 157 11788 148 1784
107
11 400 127 13502 165 1714
108
12 389 145 15500 179 1998
109
13 289 72 17586 194 2086
110
14 210 46 19185 203 1599
111
15 140 2 20474 210 1289
112
16 63 5 21331 211 857
113
17 53 9 21761 212 430
114
18 30 3 22159 214 398
115
19 23 4 22700 216 541
116
20 15 1 23055 217 355
117
21 11 1 23266 218 211
149
# Note the *really* long tail where after we have 20k keys we've pretty much
150
# read all the pages, and at this point, we only have a small handful
151
# (sometimes only 1) parent to search for.
152
# Then again, if you look at the number of parents found count, it is going
153
# up by easily 20-100 at each step, so it is still fairly efficient.
155
# Also, we can compare this to the performance of just looping over
156
# 'get_parent_map()' calls
157
gen search_keys next_keys
1270
Note that it takes 1100 trips to the index layer to generate the 25k revision
1271
history, versus only 50 when we fast-loop on a given index node.
1273
Note also that from 300=>1100 we are iterating over a single revision. This is
1274
because bzr has a *very* long single-parent ancestry because of Martin's
1275
initial work. However a project like OOo is going to have *much* more of this.
1277
We do get to 20k revisions in 107 round trips, but it only takes 15 round trips
1278
to do the same with the get_ancestry version.
1280
get_parent_map peaks at a width of 360 revisions per lookup
1281
get_ancestry peaks at 529 search_keys, but peaks at finding 2287 keys in a
1282
single pass, and only has 1 pass where it failed to find more than 1 parent,
1283
and only 4 passes where it found fewer than 10.
1286
Notes from CombinedGraphIndex.get_ancestry
1288
you can see that in a real-world repository it takes 1 pass across all indexes
1289
to really 'get primed' and start yielding results. However once that has
1290
happened, we end up getting a lot of results quickly from the 'deep history'
1291
index, and then we spin around a few times to finally fill in the rest of the
1293
One possibility would be to reprioritise the various indexes, so that if an
1294
index has recently had good success returning information, we move it earlier
1295
in the list. Or conversely, if we don't get any information, we move the index
1296
to the end. I don't have anything concrete, but the idea is to avoid polling
1297
*all* of the indexes on every pass, but instead to have a tighter loop around
1298
ones that we think are going to give us good info.
1300
gen idx sub n_keys n_pmap n_miss
1342
gen idx sub n_keys n_pmap n_miss
1433
gen idx sub n_keys n_pmap n_miss
1485
gen idx sub n_keys n_pmap n_miss
1527
Performance notes so far:
1528
time ancestry_from_get_parent_map()
1529
1530ms (down from 567ms when there was a single real index)
1530
time ancestry_from_get_ancestry()
1531
309ms (down from 245ms when there was a single real index)
1533
So even without optimizing that inner loop much, we are at about 20%
1534
time.(5:1 faster). (also note that being done on different repos, the
1535
real-world test has another ~1500 revisions in the ancestry.)
1537
This also shows how much better things scale when we have lots of indexes. It
1538
allows us to not try to search across all the indexes all the time, because we
1539
follow whatever parent threads a given index can give us.
1541
The overhead of 20 indexes was only 245 => 309 or 1.26:1, rather than 3:1 for
1542
the get_parent_map implementation.
1544
Also of interest is that in the single-index case the improvement was only
1545
about 2x, so this seems quite significant overall.
1548
For OOo with a single index:
1549
time ancestry_from_get_parent_map
1552
time ancestry_from_get_ancestry
1555
This is 3.15:1 faster, even without the benefits of pyrex or a real-world case
1556
when we have more than one pack file.