/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
88
    def _link_or_copy_kernel_files(self, root, do_link=True):
89
        """Hardlink the kernel files from the cached location.
90
91
        If the platform doesn't correctly support hardlinking files, it
92
        reverts to just creating new ones.
93
        """
94
95
        if not osutils.hardlinks_good() or not do_link:
96
            # Turns out that 'shutil.copytree()' is no faster than
97
            # just creating them. Probably the python overhead.
98
            # Plain _make_kernel_files takes 5s
99
            # cp -a takes 3s
100
            # using hardlinks takes < 1s.
101
            self._make_kernel_files(root=root)
102
            return
103
1908.2.4 by John Arbash Meinel
Add the ability to specify a benchmark cache directory.
104
        cache_dir, is_cached = self.get_cache_dir('kernel_like_tree')
105
        if not is_cached:
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
106
            os.mkdir(cache_dir)
107
            self._make_kernel_files(root=cache_dir)
1908.2.3 by John Arbash Meinel
Support caching a committed kernel-like tree, and mark hardlinked trees as readonly.
108
            self._protect_files(cache_dir)
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
109
110
        # 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.
111
        osutils.copy_tree(cache_dir, root,
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
112
                          handlers={'file':os.link})
113
1908.2.3 by John Arbash Meinel
Support caching a committed kernel-like tree, and mark hardlinked trees as readonly.
114
    def _clone_tree(self, source, dest, link_bzr=False, link_working=True):
115
        """Copy the contents from a given location to another location.
116
        Optionally hardlink certain pieces of the tree.
117
118
        :param source: The directory to copy
119
        :param dest: The destination
120
        :param link_bzr: Should the .bzr/ files be hardlinked?
121
        :param link_working: Should the working tree be hardlinked?
122
        """
123
        # We use shutil.copyfile so that we don't copy permissions
124
        # because most of our source trees are marked readonly to
125
        # prevent modifying in the case of hardlinks
126
        handlers = {'file':shutil.copyfile}
127
        if osutils.hardlinks_good():
128
            if link_working:
129
                if link_bzr:
130
                    handlers = {'file':os.link}
131
                else:
132
                    # Don't hardlink files inside bzr
133
                    def file_handler(source, dest):
134
                        if '.bzr/' in source:
135
                            shutil.copyfile(source, dest)
136
                        else:
137
                            os.link(source, dest)
138
                    handlers = {'file':file_handler}
139
            elif link_bzr:
140
                # Only link files inside .bzr/
141
                def file_handler(source, dest):
142
                    if '.bzr/' in source:
143
                        os.link(source, dest)
144
                    else:
145
                        shutil.copyfile(source, dest)
146
                handlers = {'file':file_handler}
147
        osutils.copy_tree(source, dest, handlers=handlers)
148
149
    def _protect_files(self, root):
150
        """Chmod all files underneath 'root' to prevent writing
151
152
        :param root: The base directory to modify
153
        """
154
        for dirinfo, entries in osutils.walkdirs(root):
155
            for relpath, name, kind, st, abspath in entries:
156
                if kind == 'file':
157
                    os.chmod(abspath, 0440)
158
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
159
    def make_kernel_like_added_tree(self, root='.',
160
                                    hardlink_working=True):
161
        """Make a kernel like tree, with all files added
162
163
        :param root: Where to create the files
164
        :param hardlink_working: Instead of copying all of the working tree
165
            files, just hardlink them to the cached files. Tests can unlink
166
            files that they will change.
167
        """
1908.2.3 by John Arbash Meinel
Support caching a committed kernel-like tree, and mark hardlinked trees as readonly.
168
        # There isn't much underneath .bzr, so we don't support hardlinking
169
        # it. Testing showed there wasn't much gain, and there is potentially
170
        # a problem if someone modifies something underneath us.
1908.2.4 by John Arbash Meinel
Add the ability to specify a benchmark cache directory.
171
        cache_dir, is_cached = self.get_cache_dir('kernel_like_added_tree')
172
        if not is_cached:
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
173
            # Get a basic tree with working files
174
            tree = self.make_kernel_like_tree(root=cache_dir,
175
                                              hardlink_working=True)
176
            # Add everything to it
177
            add.smart_add_tree(tree, [cache_dir], recurse=True, save=True)
1908.2.3 by John Arbash Meinel
Support caching a committed kernel-like tree, and mark hardlinked trees as readonly.
178
179
            self._protect_files(cache_dir+'/.bzr')
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
180
1908.2.4 by John Arbash Meinel
Add the ability to specify a benchmark cache directory.
181
        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.
182
                         link_working=hardlink_working)
183
        return workingtree.WorkingTree.open(root)
184
185
    def make_kernel_like_committed_tree(self, root='.',
186
                                    hardlink_working=True,
187
                                    hardlink_bzr=False):
188
        """Make a kernel like tree, with all files added and committed
189
190
        :param root: Where to create the files
191
        :param hardlink_working: Instead of copying all of the working tree
192
            files, just hardlink them to the cached files. Tests can unlink
193
            files that they will change.
194
        :param hardlink_bzr: Hardlink the .bzr directory. For readonly 
195
            operations this is safe, and shaves off a lot of setup time
196
        """
1908.2.4 by John Arbash Meinel
Add the ability to specify a benchmark cache directory.
197
        cache_dir, is_cached = self.get_cache_dir('kernel_like_committed_tree')
198
        if not is_cached:
1908.2.3 by John Arbash Meinel
Support caching a committed kernel-like tree, and mark hardlinked trees as readonly.
199
            # Get a basic tree with working files
200
            tree = self.make_kernel_like_added_tree(root=cache_dir,
201
                                                    hardlink_working=True)
202
            tree.commit('first post', rev_id='r1')
203
204
            self._protect_files(cache_dir+'/.bzr')
205
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
206
        # 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.
207
        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.
208
                         link_bzr=hardlink_bzr,
209
                         link_working=hardlink_working)
1908.2.2 by John Arbash Meinel
Allow caching basic kernel-like trees
210
        return workingtree.WorkingTree.open(root)
1707.2.2 by Robert Collins
Start on bench_add, an add benchtest.
211
1756.1.2 by Aaron Bentley
Show logs using get_revisions
212
    def make_many_commit_tree(self, directory_name='.'):
1756.2.21 by Aaron Bentley
Clean up merge log benchmark
213
        """Create a tree with many commits.
1756.1.2 by Aaron Bentley
Show logs using get_revisions
214
        
215
        No files change are included.
216
        """
1711.2.82 by John Arbash Meinel
minor fix from Jan Balster to get --benchmark to work again
217
        tree = bzrdir.BzrDir.create_standalone_workingtree(directory_name)
1756.1.2 by Aaron Bentley
Show logs using get_revisions
218
        tree.lock_write()
219
        tree.branch.lock_write()
220
        tree.branch.repository.lock_write()
221
        try:
222
            for i in xrange(1000):
223
                tree.commit('no-changes commit %d' % i)
224
        finally:
225
            try:
226
                try:
227
                    tree.branch.repository.unlock()
228
                finally:
229
                    tree.branch.unlock()
230
            finally:
231
                tree.unlock()
232
        return tree
233
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
234
    def make_heavily_merged_tree(self, directory_name='.'):
1756.2.21 by Aaron Bentley
Clean up merge log benchmark
235
        """Create a tree in which almost every commit is a merge.
236
       
237
        No files change are included.  This produces two trees, 
238
        one of which is returned.  Except for the first commit, every
239
        commit in its revision-history is a merge another commit in the other
240
        tree.
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
241
        """
1711.2.82 by John Arbash Meinel
minor fix from Jan Balster to get --benchmark to work again
242
        tree = bzrdir.BzrDir.create_standalone_workingtree(directory_name)
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
243
        tree.lock_write()
244
        try:
1756.2.21 by Aaron Bentley
Clean up merge log benchmark
245
            tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
246
            tree2.lock_write()
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
247
            try:
1756.2.21 by Aaron Bentley
Clean up merge log benchmark
248
                for i in xrange(250):
249
                    revision_id = tree.commit('no-changes commit %d-a' % i)
250
                    tree2.branch.fetch(tree.branch, revision_id)
251
                    tree2.set_pending_merges([revision_id])
252
                    revision_id = tree2.commit('no-changes commit %d-b' % i)
253
                    tree.branch.fetch(tree2.branch, revision_id)
254
                    tree.set_pending_merges([revision_id])
255
                tree.set_pending_merges([])
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
256
            finally:
257
                tree.unlock()
1756.2.21 by Aaron Bentley
Clean up merge log benchmark
258
        finally:
259
            tree2.unlock()
1756.2.19 by Aaron Bentley
Add benchmarks for merged trees
260
        return tree
261
1707.2.2 by Robert Collins
Start on bench_add, an add benchtest.
262
263
def test_suite():
264
    """Build and return a TestSuite which contains benchmark tests only."""
265
    testmod_names = [ \
266
                   'bzrlib.benchmarks.bench_add',
1755.2.1 by Robert Collins
Add a benchmark for make_kernel_like_tree.
267
                   'bzrlib.benchmarks.bench_bench',
1714.1.4 by Robert Collins
Add new benchmarks for status and commit.
268
                   'bzrlib.benchmarks.bench_checkout',
1714.1.5 by Robert Collins
Add commit benchmark.
269
                   'bzrlib.benchmarks.bench_commit',
1757.2.10 by Robert Collins
Give all inventory entries __slots__ that are useful with the current codebase.
270
                   'bzrlib.benchmarks.bench_inventory',
1756.1.7 by Aaron Bentley
Merge bzr.dev
271
                   'bzrlib.benchmarks.bench_log',
1756.1.2 by Aaron Bentley
Show logs using get_revisions
272
                   'bzrlib.benchmarks.bench_osutils',
1752.1.2 by Aaron Bentley
Benchmark the rocks command
273
                   'bzrlib.benchmarks.bench_rocks',
1714.1.4 by Robert Collins
Add new benchmarks for status and commit.
274
                   'bzrlib.benchmarks.bench_status',
1534.10.33 by Aaron Bentley
Add canonicalize_path benchmark
275
                   'bzrlib.benchmarks.bench_transform',
1732.1.11 by John Arbash Meinel
Trying multiple things to get WorkingTree.list_files time down
276
                   'bzrlib.benchmarks.bench_workingtree',
1707.2.2 by Robert Collins
Start on bench_add, an add benchtest.
277
                   ]
1841.1.1 by John Arbash Meinel
Allow plugins to provide benchmarks just like they do tests
278
    suite = TestLoader().loadTestsFromModuleNames(testmod_names) 
279
280
    # Load any benchmarks from plugins
1711.2.78 by John Arbash Meinel
Cleanup the imports in bzrlib.benchmark
281
    for name, module in plugin.all_plugins().items():
282
        if getattr(module, 'bench_suite', None) is not None:
283
            suite.addTest(module.bench_suite())
1841.1.1 by John Arbash Meinel
Allow plugins to provide benchmarks just like they do tests
284
285
    return suite