/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1707.2.2 by Robert Collins
Start on bench_add, an add benchtest.
1
# Copyright (C) 2006 by Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
18
"""Benchmark test suite for bzr."""
19
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
20
import os
21
import shutil
22
23
from bzrlib import (
24
    add,
25
    bzrdir,
26
    osutils,
27
    plugin,
28
    workingtree,
29
    )
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
30
from bzrlib.tests.TestUtil import TestLoader
1714.1.4 by Robert Collins
Add new benchmarks for status and commit.
31
from bzrlib.tests.blackbox import ExternalBase
32
1841.1.1 by John Arbash Meinel
Allow plugins to provide benchmarks just like they do tests
33
1714.1.4 by Robert Collins
Add new benchmarks for status and commit.
34
class Benchmark(ExternalBase):
35
1908.2.4 by John Arbash Meinel
Add the ability to specify a benchmark cache directory.
36
    CACHE_ROOT = None
37
38
    def get_cache_dir(self, extra):
39
        """Get the directory to use for caching the given object."""
40
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)
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
47
48
    def make_kernel_like_tree(self, url=None, root='.',
49
                              hardlink_working=False):
1725.2.5 by Robert Collins
Bugfix create_branch_convenience at the root of a file system to not loop
50
        """Setup a temporary tree roughly like a kernel tree.
51
        
52
        :param url: Creat the kernel like tree as a lightweight checkout
53
        of a new branch created at url.
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
54
        :param hardlink_working: instead of creating a new copy of all files
55
            just hardlink the working tree. Tests must request this, because
56
            they must break links if they want to change the files
1725.2.5 by Robert Collins
Bugfix create_branch_convenience at the root of a file system to not loop
57
        """
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
58
        if url is not None:
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()
63
        else:
64
            tree = bzrdir.BzrDir.create_standalone_workingtree(root)
65
66
        self._link_or_copy_kernel_files(root=root, do_link=hardlink_working)
67
        return tree
68
69
    def _make_kernel_files(self, root='.'):
1714.1.4 by Robert Collins
Add new benchmarks for status and commit.
70
        # a kernel tree has ~10000 and 500 directory, with most files around 
71
        # 3-4 levels deep. 
72
        # we simulate this by three levels of dirs named 0-7, givin 512 dirs,
73
        # and 20 files each.
74
        files = []
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)
81
                    files.append(prefix)
82
                    files.extend([prefix + str(foo) for foo in range(20)])
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
83
        cwd = osutils.getcwd()
84
        os.chdir(root)
1714.1.4 by Robert Collins
Add new benchmarks for status and commit.
85
        self.build_tree(files)
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
86
        os.chdir(cwd)
87
1908.2.5 by John Arbash Meinel
Updated bench_bench tests to test exactly what we really want to test
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')
91
        if is_cached:
92
            return cache_dir
93
        os.mkdir(cache_dir)
94
        self._make_kernel_files(root=cache_dir)
95
        self._protect_files(cache_dir)
96
        return cache_dir
97
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
98
    def _link_or_copy_kernel_files(self, root, do_link=True):
99
        """Hardlink the kernel files from the cached location.
100
101
        If the platform doesn't correctly support hardlinking files, it
102
        reverts to just creating new ones.
103
        """
104
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
109
            # cp -a takes 3s
110
            # using hardlinks takes < 1s.
111
            self._make_kernel_files(root=root)
112
            return
113
1908.2.5 by John Arbash Meinel
Updated bench_bench tests to test exactly what we really want to test
114
        cache_dir = self._cache_kernel_like_tree()
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
115
116
        # Hardlinking the target directory is *much* faster (7s => <1s).
1908.2.4 by John Arbash Meinel
Add the ability to specify a benchmark cache directory.
117
        osutils.copy_tree(cache_dir, root,
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
118
                          handlers={'file':os.link})
119
1908.2.3 by John Arbash Meinel
Support caching a committed kernel-like tree, and mark hardlinked trees as readonly.
120
    def _clone_tree(self, source, dest, link_bzr=False, link_working=True):
121
        """Copy the contents from a given location to another location.
122
        Optionally hardlink certain pieces of the tree.
123
124
        :param source: The directory to copy
125
        :param dest: The destination
126
        :param link_bzr: Should the .bzr/ files be hardlinked?
127
        :param link_working: Should the working tree be hardlinked?
128
        """
129
        # We use shutil.copyfile so that we don't copy permissions
130
        # because most of our source trees are marked readonly to
131
        # prevent modifying in the case of hardlinks
132
        handlers = {'file':shutil.copyfile}
133
        if osutils.hardlinks_good():
134
            if link_working:
135
                if link_bzr:
136
                    handlers = {'file':os.link}
137
                else:
138
                    # Don't hardlink files inside bzr
139
                    def file_handler(source, dest):
140
                        if '.bzr/' in source:
141
                            shutil.copyfile(source, dest)
142
                        else:
143
                            os.link(source, dest)
144
                    handlers = {'file':file_handler}
145
            elif link_bzr:
146
                # Only link files inside .bzr/
147
                def file_handler(source, dest):
148
                    if '.bzr/' in source:
149
                        os.link(source, dest)
150
                    else:
151
                        shutil.copyfile(source, dest)
152
                handlers = {'file':file_handler}
153
        osutils.copy_tree(source, dest, handlers=handlers)
154
155
    def _protect_files(self, root):
156
        """Chmod all files underneath 'root' to prevent writing
157
158
        :param root: The base directory to modify
159
        """
160
        for dirinfo, entries in osutils.walkdirs(root):
161
            for relpath, name, kind, st, abspath in entries:
162
                if kind == 'file':
163
                    os.chmod(abspath, 0440)
164
1908.2.5 by John Arbash Meinel
Updated bench_bench tests to test exactly what we really want to test
165
    def _cache_kernel_like_added_tree(self):
166
        cache_dir, is_cached = self.get_cache_dir('kernel_like_added_tree')
167
        if is_cached:
168
            return cache_dir
169
170
        # Get a basic tree with working files
171
        tree = self.make_kernel_like_tree(root=cache_dir,
172
                                          hardlink_working=True)
173
        # Add everything to it
174
        add.smart_add_tree(tree, [cache_dir], recurse=True, save=True)
175
176
        self._protect_files(cache_dir+'/.bzr')
177
        return cache_dir
178
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
179
    def make_kernel_like_added_tree(self, root='.',
180
                                    hardlink_working=True):
181
        """Make a kernel like tree, with all files added
182
183
        :param root: Where to create the files
184
        :param hardlink_working: Instead of copying all of the working tree
185
            files, just hardlink them to the cached files. Tests can unlink
186
            files that they will change.
187
        """
1908.2.3 by John Arbash Meinel
Support caching a committed kernel-like tree, and mark hardlinked trees as readonly.
188
        # There isn't much underneath .bzr, so we don't support hardlinking
189
        # it. Testing showed there wasn't much gain, and there is potentially
190
        # a problem if someone modifies something underneath us.
1908.2.5 by John Arbash Meinel
Updated bench_bench tests to test exactly what we really want to test
191
        cache_dir = self._cache_kernel_like_added_tree()
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
192
1908.2.4 by John Arbash Meinel
Add the ability to specify a benchmark cache directory.
193
        self._clone_tree(cache_dir, root,
1908.2.3 by John Arbash Meinel
Support caching a committed kernel-like tree, and mark hardlinked trees as readonly.
194
                         link_working=hardlink_working)
195
        return workingtree.WorkingTree.open(root)
196
1908.2.5 by John Arbash Meinel
Updated bench_bench tests to test exactly what we really want to test
197
    def _cache_kernel_like_committed_tree(self):
198
        cache_dir, is_cached = self.get_cache_dir('kernel_like_committed_tree')
199
        if is_cached:
200
            return cache_dir
201
202
        # Get a basic tree with working files
203
        tree = self.make_kernel_like_added_tree(root=cache_dir,
204
                                                hardlink_working=True)
205
        tree.commit('first post', rev_id='r1')
206
207
        self._protect_files(cache_dir+'/.bzr')
208
        return cache_dir
209
1908.2.3 by John Arbash Meinel
Support caching a committed kernel-like tree, and mark hardlinked trees as readonly.
210
    def make_kernel_like_committed_tree(self, root='.',
211
                                    hardlink_working=True,
212
                                    hardlink_bzr=False):
213
        """Make a kernel like tree, with all files added and committed
214
215
        :param root: Where to create the files
216
        :param hardlink_working: Instead of copying all of the working tree
217
            files, just hardlink them to the cached files. Tests can unlink
218
            files that they will change.
219
        :param hardlink_bzr: Hardlink the .bzr directory. For readonly 
220
            operations this is safe, and shaves off a lot of setup time
221
        """
1908.2.5 by John Arbash Meinel
Updated bench_bench tests to test exactly what we really want to test
222
        cache_dir = self._cache_kernel_like_committed_tree()
1908.2.3 by John Arbash Meinel
Support caching a committed kernel-like tree, and mark hardlinked trees as readonly.
223
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
224
        # Now we have a cached tree, just copy it
1908.2.4 by John Arbash Meinel
Add the ability to specify a benchmark cache directory.
225
        self._clone_tree(cache_dir, root,
1908.2.3 by John Arbash Meinel
Support caching a committed kernel-like tree, and mark hardlinked trees as readonly.
226
                         link_bzr=hardlink_bzr,
227
                         link_working=hardlink_working)
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
228
        return workingtree.WorkingTree.open(root)
1707.2.2 by Robert Collins
Start on bench_add, an add benchtest.
229
1756.1.2 by Aaron Bentley
Show logs using get_revisions
230
    def make_many_commit_tree(self, directory_name='.'):
1756.2.21 by Aaron Bentley
Clean up merge log benchmark
231
        """Create a tree with many commits.
1756.1.2 by Aaron Bentley
Show logs using get_revisions
232
        
233
        No files change are included.
234
        """
1711.2.82 by John Arbash Meinel
minor fix from Jan Balster to get --benchmark to work again
235
        tree = bzrdir.BzrDir.create_standalone_workingtree(directory_name)
1756.1.2 by Aaron Bentley
Show logs using get_revisions
236
        tree.lock_write()
237
        tree.branch.lock_write()
238
        tree.branch.repository.lock_write()
239
        try:
240
            for i in xrange(1000):
241
                tree.commit('no-changes commit %d' % i)
242
        finally:
243
            try:
244
                try:
245
                    tree.branch.repository.unlock()
246
                finally:
247
                    tree.branch.unlock()
248
            finally:
249
                tree.unlock()
250
        return tree
251
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
252
    def make_heavily_merged_tree(self, directory_name='.'):
1756.2.21 by Aaron Bentley
Clean up merge log benchmark
253
        """Create a tree in which almost every commit is a merge.
254
       
255
        No files change are included.  This produces two trees, 
256
        one of which is returned.  Except for the first commit, every
257
        commit in its revision-history is a merge another commit in the other
258
        tree.
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
259
        """
1711.2.82 by John Arbash Meinel
minor fix from Jan Balster to get --benchmark to work again
260
        tree = bzrdir.BzrDir.create_standalone_workingtree(directory_name)
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
261
        tree.lock_write()
262
        try:
1756.2.21 by Aaron Bentley
Clean up merge log benchmark
263
            tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
264
            tree2.lock_write()
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
265
            try:
1756.2.21 by Aaron Bentley
Clean up merge log benchmark
266
                for i in xrange(250):
267
                    revision_id = tree.commit('no-changes commit %d-a' % i)
268
                    tree2.branch.fetch(tree.branch, revision_id)
269
                    tree2.set_pending_merges([revision_id])
270
                    revision_id = tree2.commit('no-changes commit %d-b' % i)
271
                    tree.branch.fetch(tree2.branch, revision_id)
272
                    tree.set_pending_merges([revision_id])
273
                tree.set_pending_merges([])
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
274
            finally:
275
                tree.unlock()
1756.2.21 by Aaron Bentley
Clean up merge log benchmark
276
        finally:
277
            tree2.unlock()
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
278
        return tree
279
1707.2.2 by Robert Collins
Start on bench_add, an add benchtest.
280
281
def test_suite():
282
    """Build and return a TestSuite which contains benchmark tests only."""
283
    testmod_names = [ \
284
                   'bzrlib.benchmarks.bench_add',
1755.2.1 by Robert Collins
Add a benchmark for make_kernel_like_tree.
285
                   'bzrlib.benchmarks.bench_bench',
1714.1.4 by Robert Collins
Add new benchmarks for status and commit.
286
                   'bzrlib.benchmarks.bench_checkout',
1714.1.5 by Robert Collins
Add commit benchmark.
287
                   'bzrlib.benchmarks.bench_commit',
1757.2.10 by Robert Collins
Give all inventory entries __slots__ that are useful with the current codebase.
288
                   'bzrlib.benchmarks.bench_inventory',
1756.1.7 by Aaron Bentley
Merge bzr.dev
289
                   'bzrlib.benchmarks.bench_log',
1756.1.2 by Aaron Bentley
Show logs using get_revisions
290
                   'bzrlib.benchmarks.bench_osutils',
1752.1.2 by Aaron Bentley
Benchmark the rocks command
291
                   'bzrlib.benchmarks.bench_rocks',
1714.1.4 by Robert Collins
Add new benchmarks for status and commit.
292
                   'bzrlib.benchmarks.bench_status',
1534.10.33 by Aaron Bentley
Add canonicalize_path benchmark
293
                   'bzrlib.benchmarks.bench_transform',
1732.1.11 by John Arbash Meinel
Trying multiple things to get WorkingTree.list_files time down
294
                   'bzrlib.benchmarks.bench_workingtree',
1707.2.2 by Robert Collins
Start on bench_add, an add benchtest.
295
                   ]
1841.1.1 by John Arbash Meinel
Allow plugins to provide benchmarks just like they do tests
296
    suite = TestLoader().loadTestsFromModuleNames(testmod_names) 
297
298
    # Load any benchmarks from plugins
1711.2.78 by John Arbash Meinel
Cleanup the imports in bzrlib.benchmark
299
    for name, module in plugin.all_plugins().items():
300
        if getattr(module, 'bench_suite', None) is not None:
301
            suite.addTest(module.bench_suite())
1841.1.1 by John Arbash Meinel
Allow plugins to provide benchmarks just like they do tests
302
303
    return suite