34
26
class Benchmark(ExternalBase):
38
def get_cache_dir(self, extra):
39
"""Get the directory to use for caching the given object."""
41
if Benchmark.CACHE_ROOT is None:
42
Benchmark.CACHE_ROOT = osutils.pathjoin(self.TEST_ROOT, 'CACHE')
43
if not os.path.isdir(Benchmark.CACHE_ROOT):
44
os.mkdir(Benchmark.CACHE_ROOT)
45
cache_dir = osutils.pathjoin(self.CACHE_ROOT, extra)
46
return cache_dir, os.path.exists(cache_dir)
48
28
def make_kernel_like_tree(self, url=None, root='.',
49
hardlink_working=False):
50
30
"""Setup a temporary tree roughly like a kernel tree.
52
32
:param url: Creat the kernel like tree as a lightweight checkout
53
33
of a new branch created at url.
54
:param hardlink_working: instead of creating a new copy of all files
34
:param link_working: instead of creating a new copy of all files
55
35
just hardlink the working tree. Tests must request this, because
56
36
they must break links if they want to change the files
59
b = bzrdir.BzrDir.create_branch_convenience(url)
60
d = bzrdir.BzrDir.create(root)
61
bzrlib.branch.BranchReferenceFormat().initialize(d, b)
62
tree = d.create_workingtree()
64
tree = bzrdir.BzrDir.create_standalone_workingtree(root)
66
self._link_or_copy_kernel_files(root=root, do_link=hardlink_working)
69
def _make_kernel_files(self, root='.'):
70
# a kernel tree has ~10000 and 500 directory, with most files around
72
# we simulate this by three levels of dirs named 0-7, givin 512 dirs,
75
for outer in range(8):
76
files.append("%s/" % outer)
77
for middle in range(8):
78
files.append("%s/%s/" % (outer, middle))
79
for inner in range(8):
80
prefix = "%s/%s/%s/" % (outer, middle, inner)
82
files.extend([prefix + str(foo) for foo in range(20)])
83
cwd = osutils.getcwd()
85
self.build_tree(files)
88
def _cache_kernel_like_tree(self):
89
"""Create the kernel_like_tree cache dir if it doesn't exist"""
90
cache_dir, is_cached = self.get_cache_dir('kernel_like_tree')
94
self._make_kernel_files(root=cache_dir)
95
self._protect_files(cache_dir)
98
def _link_or_copy_kernel_files(self, root, do_link=True):
99
"""Hardlink the kernel files from the cached location.
101
If the platform doesn't correctly support hardlinking files, it
102
reverts to just creating new ones.
105
if not osutils.hardlinks_good() or not do_link:
106
# Turns out that 'shutil.copytree()' is no faster than
107
# just creating them. Probably the python overhead.
108
# Plain _make_kernel_files takes 5s
110
# using hardlinks takes < 1s.
111
self._make_kernel_files(root=root)
114
cache_dir = self._cache_kernel_like_tree()
116
# Hardlinking the target directory is *much* faster (7s => <1s).
117
osutils.copy_tree(cache_dir, root,
118
handlers={'file':os.link})
120
def _clone_tree(self, source, dest, link_bzr=False, link_working=True,
122
"""Copy the contents from a given location to another location.
123
Optionally hardlink certain pieces of the tree.
125
:param source: The directory to copy
126
:param dest: The destination
127
:param link_bzr: Should the .bzr/ files be hardlinked?
128
:param link_working: Should the working tree be hardlinked?
129
:param hot_cache: Update the hash-cache when you are done
131
# We use shutil.copyfile so that we don't copy permissions
132
# because most of our source trees are marked readonly to
133
# prevent modifying in the case of hardlinks
134
handlers = {'file':shutil.copyfile}
135
if osutils.hardlinks_good():
138
handlers = {'file':os.link}
140
# Don't hardlink files inside bzr
141
def file_handler(source, dest):
142
if '.bzr/' in source:
143
shutil.copyfile(source, dest)
145
os.link(source, dest)
146
handlers = {'file':file_handler}
148
# Only link files inside .bzr/
149
def file_handler(source, dest):
150
if '.bzr/' in source:
151
os.link(source, dest)
153
shutil.copyfile(source, dest)
154
handlers = {'file':file_handler}
155
osutils.copy_tree(source, dest, handlers=handlers)
156
tree = workingtree.WorkingTree.open(dest)
160
# tree._hashcache.scan() just checks and removes
161
# entries that are out of date
162
# we need to actually store new ones
163
for path, ie in tree.inventory.iter_entries_by_dir():
164
tree.get_file_sha1(ie.file_id, path)
167
# If we didn't iterate the tree, the hash cache is technically
168
# invalid, and it would be better to remove it, but there is
169
# no public api for that.
172
def _protect_files(self, root):
173
"""Chmod all files underneath 'root' to prevent writing
175
:param root: The base directory to modify
177
for dirinfo, entries in osutils.walkdirs(root):
178
for relpath, name, kind, st, abspath in entries:
180
os.chmod(abspath, 0440)
182
def _cache_kernel_like_added_tree(self):
183
cache_dir, is_cached = self.get_cache_dir('kernel_like_added_tree')
187
# Get a basic tree with working files
188
tree = self.make_kernel_like_tree(root=cache_dir,
189
hardlink_working=True)
190
# Add everything to it
193
add.smart_add_tree(tree, [cache_dir], recurse=True, save=True)
194
self._protect_files(cache_dir+'/.bzr')
38
from bzrlib.benchmarks.tree_creator.kernel_like import (
39
KernelLikeTreeCreator,
41
creator = KernelLikeTreeCreator(self, link_working=link_working,
43
return creator.create(root=root)
200
45
def make_kernel_like_added_tree(self, root='.',
201
hardlink_working=True,
203
48
"""Make a kernel like tree, with all files added
205
50
:param root: Where to create the files
206
:param hardlink_working: Instead of copying all of the working tree
51
:param link_working: Instead of copying all of the working tree
207
52
files, just hardlink them to the cached files. Tests can unlink
208
53
files that they will change.
209
54
:param hot_cache: Run through the newly created tree and make sure
210
55
the stat-cache is correct. The old way of creating a freshly
211
56
added tree always had a hot cache.
213
# There isn't much underneath .bzr, so we don't support hardlinking
214
# it. Testing showed there wasn't much gain, and there is potentially
215
# a problem if someone modifies something underneath us.
216
cache_dir = self._cache_kernel_like_added_tree()
218
return self._clone_tree(cache_dir, root,
219
link_working=hardlink_working,
222
def _cache_kernel_like_committed_tree(self):
223
cache_dir, is_cached = self.get_cache_dir('kernel_like_committed_tree')
227
# Get a basic tree with working files
228
tree = self.make_kernel_like_added_tree(root=cache_dir,
229
hardlink_working=True,
231
tree.commit('first post', rev_id='r1')
233
self._protect_files(cache_dir+'/.bzr')
58
from bzrlib.benchmarks.tree_creator.kernel_like import (
59
KernelLikeAddedTreeCreator,
61
creator = KernelLikeAddedTreeCreator(self, link_working=link_working,
63
return creator.create(root=root)
236
65
def make_kernel_like_committed_tree(self, root='.',
237
hardlink_working=True,
240
69
"""Make a kernel like tree, with all files added and committed
242
71
:param root: Where to create the files
243
:param hardlink_working: Instead of copying all of the working tree
72
:param link_working: Instead of copying all of the working tree
244
73
files, just hardlink them to the cached files. Tests can unlink
245
74
files that they will change.
246
:param hardlink_bzr: Hardlink the .bzr directory. For readonly
75
:param link_bzr: Hardlink the .bzr directory. For readonly
247
76
operations this is safe, and shaves off a lot of setup time
249
cache_dir = self._cache_kernel_like_committed_tree()
251
# Now we have a cached tree, just copy it
252
return self._clone_tree(cache_dir, root,
253
link_bzr=hardlink_bzr,
254
link_working=hardlink_working,
257
def _cache_many_commit_tree(self):
258
cache_dir, is_cached = self.get_cache_dir('many_commit_tree')
262
tree = bzrdir.BzrDir.create_standalone_workingtree(cache_dir)
264
tree.branch.lock_write()
265
tree.branch.repository.lock_write()
267
for i in xrange(1000):
268
tree.commit('no-changes commit %d' % i)
272
tree.branch.repository.unlock()
78
from bzrlib.benchmarks.tree_creator.kernel_like import (
79
KernelLikeCommittedTreeCreator,
81
creator = KernelLikeCommittedTreeCreator(self,
82
link_working=link_working,
85
return creator.create(root=root)
280
87
def make_many_commit_tree(self, directory_name='.',