30
class _CompiledDirstateHelpersFeature(tests.Feature):
33
import bzrlib.compiled.dirstate_helpers
38
def feature_name(self):
39
return 'compiled dirstate helpers'
41
CompiledDirstateHelpersFeature =_CompiledDirstateHelpersFeature()
29
44
class BenchmarkDirState(benchmarks.Benchmark):
46
def build_helper(self, layout):
47
"""This is a helper with the common build_??_dirstate funcs.
49
:param layout: [(num_dirs, files_per_dir)]
50
The number of directories per level, and the number of files to put
52
:return: A DirState object with the given layout.
54
self.build_tree(['dir/'])
56
self.build_tree_contents([('file', contents)])
57
file_stat = os.lstat('file')
58
dir_stat = os.lstat('dir')
59
file_sha1 = osutils.sha_string(contents)
61
state = dirstate.DirState.initialize('state')
63
def create_entries(base, layout):
66
num_dirs, num_files = layout[0]
67
for dnum in xrange(num_dirs):
69
path = '%s/%02d_directory' % (base, dnum)
71
path = '%02d_directory' % (dnum,)
72
dir_id = generate_ids.gen_file_id(path)
73
state.add(path, dir_id, 'directory', dir_stat, '')
74
for fnum in xrange(num_files):
75
fname = '%s/%02d_filename' % (path, fnum)
76
file_id = generate_ids.gen_file_id(fname)
77
state.add(fname, file_id, 'file', file_stat, file_sha1)
78
create_entries(path, layout[1:])
79
create_entries(None, layout)
85
def build_1k_dirstate_dirs(self):
86
"""Build a DirState file with 1k directories"""
87
return self.build_helper([(10, 0), (10, 0), (10, 1)])
31
89
def build_20k_dirstate(self):
32
90
"""Build a DirState file with 20k records.
38
96
We try to have reasonable filename lengths, as well as a reasonable
41
self.build_tree(['dir/'])
42
self.build_tree_contents([('file', 'x'*10000)])
43
file_stat = os.lstat('file')
44
dir_stat = os.lstat('dir')
45
file_sha1 = osutils.sha_string('testing')
47
# the average filename length is 11 characters
48
# find . | sed -e 's/.*\///' | wc -l
50
# 237869 / 22545 = 10.6
51
# average depth is 30 characters
54
# 679884 / 22545 = 30.1
55
state = dirstate.DirState.initialize('state')
57
for lvl1 in xrange(10):
58
dir_1 = '%2d_directory' % (lvl1,)
59
dir_1_id = generate_ids.gen_file_id(dir_1)
60
state.add(dir_1, dir_1_id, 'directory', dir_stat, '')
61
for lvl2 in xrange(10):
62
dir_2 = '%s/%2d_directory' % (dir_1, lvl2)
63
dir_2_id = generate_ids.gen_file_id(dir_2)
64
state.add(dir_2, dir_2_id, 'directory', dir_stat, '')
65
for lvl3 in xrange(10):
66
dir_3 = '%s/%2d_directory' % (dir_2, lvl3)
67
dir_3_id = generate_ids.gen_file_id(dir_3)
68
state.add(dir_3, dir_3_id, 'directory', dir_stat, '')
69
for filenum in xrange(20):
70
fname = '%s/%2d_filename' % (dir_3, filenum)
71
file_id = generate_ids.gen_file_id(fname)
72
state.add(fname, file_id, 'directory', dir_stat, '')
99
return self.build_helper([(10, 0), (10, 0), (10, 20)])
78
101
def test_build_20k_dirblocks(self):
79
102
state = self.time(self.build_20k_dirstate)
93
116
self.time(state._read_dirblocks_if_needed)
120
def do_bisect_list(self, bisect_func):
121
"""Call bisect_dirblock for each path."""
122
# We use self._paths and self._blocks because we expect it to be a very
123
# long list. And the interface for 'self.time()' causes the parameters
124
# to be printed when run with --lsprof-timed. Which is *really* ugly
125
# when the list is thousands of entries.
126
blocks = self._blocks
127
return [bisect_func(blocks, path) for path in self._paths]
129
def do_bisect_list_cached(self, bisect_func):
130
"""Same as do_bisect_list, but cache the split paths"""
132
blocks = self._blocks
133
return [bisect_func(blocks, path, cache=cache) for path in self._paths]
135
def setup_paths_and_offsets(self, state):
136
"""Get a list of paths and expected offsets.
138
This will be used to check do_bisect_list*
140
state._read_dirblocks_if_needed()
142
expected_offsets = [0]
143
for offset, info in enumerate(state._dirblocks):
145
# We already handled the empty path
148
# all paths are of the form ##_directory
149
# so search for ##_director, ##_directory
150
paths.extend([dirname[:-1], dirname])
151
expected_offsets.extend([offset, offset])
153
self._expected_offsets = expected_offsets
154
self._blocks = state._dirblocks
156
def checkOffsets(self, offsets):
157
"""Make sure offsets matches self._expected_offsets"""
158
# These are really long lists, so it is easier to compare them with
159
# assertEqualDiff. So turn them into strings.
160
expected_str = '\n'.join(str(x) for x in self._expected_offsets)
161
offset_str = '\n'.join(str(x) for x in offsets)
162
self.assertEqualDiff(expected_str, offset_str)
164
def test_bisect_dirblock(self):
165
state = self.build_1k_dirstate_dirs()
168
self.setup_paths_and_offsets(state)
169
offsets = self.time(self.do_bisect_list, dirstate.bisect_dirblock)
170
self.checkOffsets(offsets)
174
def test_bisect_dirblock_cached(self):
175
state = self.build_1k_dirstate_dirs()
178
self.setup_paths_and_offsets(state)
179
offsets = self.time(self.do_bisect_list_cached,
180
dirstate.bisect_dirblock)
181
self.checkOffsets(offsets)
185
def test_bisect_dirblock_compiled(self):
186
self.requireFeature(CompiledDirstateHelpersFeature)
187
state = self.build_1k_dirstate_dirs()
190
self.setup_paths_and_offsets(state)
191
offsets = self.time(self.do_bisect_list, dirstate.bisect_dirblock)
192
self.checkOffsets(offsets)
196
def test_bisect_dirblock_compiled_cached(self):
197
self.requireFeature(CompiledDirstateHelpersFeature)
198
state = self.build_1k_dirstate_dirs()
201
self.setup_paths_and_offsets(state)
202
offsets = self.time(self.do_bisect_list_cached,
203
dirstate.bisect_dirblock)
204
self.checkOffsets(offsets)