/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/benchmarks/__init__.py

  • Committer: John Arbash Meinel
  • Date: 2006-08-15 03:04:06 UTC
  • mto: This revision was merged to the branch mainline in revision 1923.
  • Revision ID: john@arbash-meinel.com-20060815030406-99b1c2c16363eb13
Move all the new TreeCreator classes into separate files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
 
18
17
"""Benchmark test suite for bzr."""
19
18
 
20
 
import errno
21
 
import os
22
 
import shutil
23
 
 
24
19
from bzrlib import (
25
 
    add,
26
 
    bzrdir,
27
 
    osutils,
28
20
    plugin,
29
 
    workingtree,
30
21
    )
31
22
from bzrlib.tests.TestUtil import TestLoader
32
23
from bzrlib.tests.blackbox import ExternalBase
44
35
            just hardlink the working tree. Tests must request this, because
45
36
            they must break links if they want to change the files
46
37
        """
 
38
        from bzrlib.benchmarks.tree_creator.kernel_like import (
 
39
            KernelLikeTreeCreator,
 
40
            )
47
41
        creator = KernelLikeTreeCreator(self, link_working=link_working,
48
42
                                        url=url)
49
43
        return creator.create(root=root)
61
55
            the stat-cache is correct. The old way of creating a freshly
62
56
            added tree always had a hot cache.
63
57
        """
 
58
        from bzrlib.benchmarks.tree_creator.kernel_like import (
 
59
            KernelLikeAddedTreeCreator,
 
60
            )
64
61
        creator = KernelLikeAddedTreeCreator(self, link_working=link_working,
65
62
                                             hot_cache=hot_cache)
66
63
        return creator.create(root=root)
78
75
        :param link_bzr: Hardlink the .bzr directory. For readonly 
79
76
            operations this is safe, and shaves off a lot of setup time
80
77
        """
 
78
        from bzrlib.benchmarks.tree_creator.kernel_like import (
 
79
            KernelLikeCommittedTreeCreator,
 
80
            )
81
81
        creator = KernelLikeCommittedTreeCreator(self,
82
82
                                                 link_working=link_working,
83
83
                                                 link_bzr=link_bzr,
91
91
        No file changes are included. Not hardlinking the working tree, 
92
92
        because there are no working tree files.
93
93
        """
 
94
        from bzrlib.benchmarks.tree_creator.simple_many_commit import (
 
95
            SimpleManyCommitTreeCreator,
 
96
            )
94
97
        creator = SimpleManyCommitTreeCreator(self, link_bzr=hardlink)
95
98
        return creator.create(root=directory_name)
96
99
 
104
107
        tree.  Not hardlinking the working tree, because there are no working 
105
108
        tree files.
106
109
        """
 
110
        from bzrlib.benchmarks.tree_creator.heavily_merged import (
 
111
            HeavilyMergedTreeCreator,
 
112
            )
107
113
        creator = HeavilyMergedTreeCreator(self, link_bzr=hardlink)
108
114
        return creator.create(root=directory_name)
109
115
 
110
116
 
111
 
class TreeCreator(object):
112
 
    """Just a basic class which is used to create various test trees"""
113
 
 
114
 
    CACHE_ROOT = None
115
 
 
116
 
    def __init__(self, test, tree_name,
117
 
                 link_bzr=False,
118
 
                 link_working=False,
119
 
                 hot_cache=True):
120
 
        """Instantiate a new creator object, supply the id of the tree"""
121
 
 
122
 
        self._cache_root = TreeCreator.CACHE_ROOT
123
 
        self._test = test
124
 
        self._tree_name = tree_name
125
 
        self._link_bzr = link_bzr
126
 
        self._link_working = link_working
127
 
        self._hot_cache = hot_cache
128
 
        if not osutils.hardlinks_good():
129
 
            self._link_working = self._link_bzr = False
130
 
 
131
 
    def is_caching_enabled(self):
132
 
        """Will we try to cache the tree we create?"""
133
 
        return self._cache_root is not None
134
 
 
135
 
    def is_cached(self):
136
 
        """Is this tree already cached?"""
137
 
        cache_dir = self._get_cache_dir()
138
 
        if cache_dir is None:
139
 
            return False
140
 
        return os.path.exists(cache_dir)
141
 
        
142
 
    def disable_cache(self):
143
 
        """Do not use the cache"""
144
 
        self._cache_root = None
145
 
 
146
 
    def ensure_cached(self):
147
 
        """If caching, make sure the cached copy exists"""
148
 
        cache_dir = self._get_cache_dir()
149
 
        if cache_dir is None:
150
 
            return
151
 
 
152
 
        if not self.is_cached():
153
 
            self._create_tree(root=cache_dir, in_cache=True)
154
 
 
155
 
    def create(self, root):
156
 
        """Create a new tree at 'root'.
157
 
 
158
 
        :return: A WorkingTree object.
159
 
        """
160
 
        cache_dir = self._get_cache_dir()
161
 
        if cache_dir is None:
162
 
            # Not caching
163
 
            return self._create_tree(root, in_cache=False)
164
 
 
165
 
        self.ensure_cached()
166
 
 
167
 
        return self._clone_cached_tree(root)
168
 
 
169
 
    def _get_cache_dir(self):
170
 
        """Get the directory to use for caching this tree
171
 
 
172
 
        :return: The path to use for caching. If None, caching is disabled
173
 
        """
174
 
        if self._cache_root is None:
175
 
            return None
176
 
        return osutils.pathjoin(self._cache_root, self._tree_name)
177
 
 
178
 
    def _create_tree(self, root, in_cache=False):
179
 
        """Create the desired tree in the given location.
180
 
 
181
 
        Children should override this function to provide the actual creation
182
 
        of the desired tree. This will be called by 'create()'. If it is
183
 
        building a tree in the cache, before copying it to the real target,
184
 
        it will pass in_cache=True
185
 
        """
186
 
        raise NotImplemented(self._create_tree)
187
 
 
188
 
    def _clone_cached_tree(self, dest):
189
 
        """Copy the contents of the cached dir into the destination
190
 
        Optionally hardlink certain pieces of the tree.
191
 
 
192
 
        This is just meant as a helper function for child classes
193
 
 
194
 
        :param dest: The destination to copy things to
195
 
        """
196
 
        # We use shutil.copyfile so that we don't copy permissions
197
 
        # because most of our source trees are marked readonly to
198
 
        # prevent modifying in the case of hardlinks
199
 
        handlers = {'file':shutil.copyfile}
200
 
        if osutils.hardlinks_good():
201
 
            if self._link_working:
202
 
                if self._link_bzr:
203
 
                    handlers = {'file':os.link}
204
 
                else:
205
 
                    # Don't hardlink files inside bzr
206
 
                    def file_handler(source, dest):
207
 
                        if '.bzr/' in source:
208
 
                            shutil.copyfile(source, dest)
209
 
                        else:
210
 
                            os.link(source, dest)
211
 
                    handlers = {'file':file_handler}
212
 
            elif self._link_bzr:
213
 
                # Only link files inside .bzr/
214
 
                def file_handler(source, dest):
215
 
                    if '.bzr/' in source:
216
 
                        os.link(source, dest)
217
 
                    else:
218
 
                        shutil.copyfile(source, dest)
219
 
                handlers = {'file':file_handler}
220
 
 
221
 
        source = self._get_cache_dir()
222
 
        osutils.copy_tree(source, dest, handlers=handlers)
223
 
        tree = workingtree.WorkingTree.open(dest)
224
 
        if self._hot_cache:
225
 
            tree.lock_write()
226
 
            try:
227
 
                # tree._hashcache.scan() just checks and removes
228
 
                # entries that are out of date
229
 
                # we need to actually store new ones
230
 
                for path, ie in tree.inventory.iter_entries_by_dir():
231
 
                    tree.get_file_sha1(ie.file_id, path)
232
 
            finally:
233
 
                tree.unlock()
234
 
        # If we didn't iterate the tree, the hash cache is technically
235
 
        # invalid, and it would be better to remove it, but there is
236
 
        # no public api for that.
237
 
        return tree
238
 
 
239
 
    def _protect_files(self, root):
240
 
        """Chmod all files underneath 'root' to prevent writing
241
 
 
242
 
        This is a helper function for child classes.
243
 
 
244
 
        :param root: The base directory to modify
245
 
        """
246
 
        for dirinfo, entries in osutils.walkdirs(root):
247
 
            for relpath, name, kind, st, abspath in entries:
248
 
                if kind == 'file':
249
 
                    os.chmod(abspath, 0440)
250
 
 
251
 
 
252
 
class KernelLikeTreeCreator(TreeCreator):
253
 
    """Create a basic tree with ~10k unversioned files""" 
254
 
 
255
 
    def __init__(self, test, link_working=False, url=None):
256
 
        super(KernelLikeTreeCreator, self).__init__(test,
257
 
            tree_name='kernel_like_tree',
258
 
            link_working=link_working,
259
 
            link_bzr=False)
260
 
 
261
 
        self._url = url
262
 
 
263
 
    def create(self, root):
264
 
        """Create all the kernel files in the given location.
265
 
 
266
 
        This is overloaded for compatibility reasons.
267
 
        """
268
 
        if self._url is not None:
269
 
            b = bzrdir.BzrDir.create_branch_convenience(self._url)
270
 
            d = bzrdir.BzrDir.create(root)
271
 
            bzrlib.branch.BranchReferenceFormat().initialize(d, b)
272
 
            tree = d.create_workingtree()
273
 
        else:
274
 
            tree = bzrdir.BzrDir.create_standalone_workingtree(root)
275
 
 
276
 
        if not self._link_working or not self.is_caching_enabled():
277
 
            # Turns out that 'shutil.copytree()' is no faster than
278
 
            # just creating them. Probably the python overhead.
279
 
            # Plain _make_kernel_files takes 3-5s
280
 
            # cp -a takes 3s
281
 
            # using hardlinks takes < 1s.
282
 
            self._create_tree(root=root, in_cache=False)
283
 
            return tree
284
 
 
285
 
        self.ensure_cached()
286
 
        cache_dir = self._get_cache_dir()
287
 
        osutils.copy_tree(cache_dir, root,
288
 
                          handlers={'file':os.link})
289
 
        return tree
290
 
 
291
 
    def _create_tree(self, root, in_cache=False):
292
 
        # a kernel tree has ~10000 and 500 directory, with most files around 
293
 
        # 3-4 levels deep. 
294
 
        # we simulate this by three levels of dirs named 0-7, givin 512 dirs,
295
 
        # and 20 files each.
296
 
        files = []
297
 
        for outer in range(8):
298
 
            files.append("%s/" % outer)
299
 
            for middle in range(8):
300
 
                files.append("%s/%s/" % (outer, middle))
301
 
                for inner in range(8):
302
 
                    prefix = "%s/%s/%s/" % (outer, middle, inner)
303
 
                    files.append(prefix)
304
 
                    files.extend([prefix + str(foo) for foo in range(20)])
305
 
        cwd = osutils.getcwd()
306
 
        os.chdir(root)
307
 
        self._test.build_tree(files)
308
 
        os.chdir(cwd)
309
 
        if in_cache:
310
 
            self._protect_files(root)
311
 
 
312
 
 
313
 
class KernelLikeAddedTreeCreator(TreeCreator):
314
 
 
315
 
    def __init__(self, test, link_working=False, hot_cache=True):
316
 
        super(KernelLikeAddedTreeCreator, self).__init__(test,
317
 
            tree_name='kernel_like_added_tree',
318
 
            link_working=link_working,
319
 
            link_bzr=False,
320
 
            hot_cache=hot_cache)
321
 
 
322
 
    def _create_tree(self, root, in_cache=False):
323
 
        """Create a kernel-like tree with the all files added
324
 
 
325
 
        :param root: The root directory to create the files
326
 
        :param in_cache: Is this being created in the cache dir?
327
 
        """
328
 
        kernel_creator = KernelLikeTreeCreator(self._test,
329
 
                                               link_working=in_cache)
330
 
        tree = kernel_creator.create(root=root)
331
 
 
332
 
        # Add everything to it
333
 
        tree.lock_write()
334
 
        try:
335
 
            add.smart_add_tree(tree, [root], recurse=True, save=True)
336
 
            if in_cache:
337
 
                self._protect_files(root+'/.bzr')
338
 
        finally:
339
 
            tree.unlock()
340
 
        return tree
341
 
 
342
 
 
343
 
class KernelLikeCommittedTreeCreator(TreeCreator):
344
 
    """Create a tree with ~10K files, and a single commit adding all of them"""
345
 
 
346
 
    def __init__(self, test, link_working=False, link_bzr=False,
347
 
                 hot_cache=True):
348
 
        super(KernelLikeCommittedTreeCreator, self).__init__(test,
349
 
            tree_name='kernel_like_committed_tree',
350
 
            link_working=link_working,
351
 
            link_bzr=link_bzr,
352
 
            hot_cache=hot_cache)
353
 
 
354
 
    def _create_tree(self, root, in_cache=False):
355
 
        """Create a kernel-like tree with all files committed
356
 
 
357
 
        :param root: The root directory to create the files
358
 
        :param in_cache: Is this being created in the cache dir?
359
 
        """
360
 
        kernel_creator = KernelLikeAddedTreeCreator(self._test,
361
 
                                                    link_working=in_cache,
362
 
                                                    hot_cache=(not in_cache))
363
 
        tree = kernel_creator.create(root=root)
364
 
        tree.commit('first post', rev_id='r1')
365
 
 
366
 
        if in_cache:
367
 
            self._protect_files(root+'/.bzr')
368
 
        return tree
369
 
 
370
 
 
371
 
class SimpleManyCommitTreeCreator(TreeCreator):
372
 
    """Create an empty tree with lots of commits"""
373
 
 
374
 
    def __init__(self, test, link_bzr=False):
375
 
        super(SimpleManyCommitTreeCreator, self).__init__(test,
376
 
            tree_name='many_commit_tree',
377
 
            link_bzr=link_bzr,
378
 
            link_working=False,
379
 
            hot_cache=True)
380
 
 
381
 
    def _create_tree(self, root, in_cache=False):
382
 
        tree = bzrdir.BzrDir.create_standalone_workingtree(root)
383
 
        tree.lock_write()
384
 
        try:
385
 
            for i in xrange(1000):
386
 
                tree.commit('no-changes commit %d' % i)
387
 
        finally:
388
 
            tree.unlock()
389
 
        if in_cache:
390
 
            self._protect_files(root+'/.bzr')
391
 
 
392
 
        return tree
393
 
 
394
 
 
395
 
class HeavilyMergedTreeCreator(TreeCreator):
396
 
    """Create a tree in which almost every commit is a merge.
397
 
   
398
 
    No file changes are included.  This produces two trees, 
399
 
    one of which is returned.  Except for the first commit, every
400
 
    commit in its revision-history is a merge of another commit in the other
401
 
    tree.  
402
 
    Not hardlinking the working tree, because there are no working tree files.
403
 
    """
404
 
 
405
 
    def __init__(self, test, link_bzr=True):
406
 
        super(HeavilyMergedTreeCreator, self).__init__(test,
407
 
            tree_name='heavily_merged_tree',
408
 
            link_bzr=link_bzr,
409
 
            link_working=False,
410
 
            hot_cache=True)
411
 
 
412
 
    def _create_tree(self, root, in_cache=False):
413
 
        try:
414
 
            os.mkdir(root)
415
 
        except (IOError, OSError), e:
416
 
            if e.errno not in (errno.EEXIST,):
417
 
                raise
418
 
 
419
 
        tree = bzrdir.BzrDir.create_standalone_workingtree(root)
420
 
        tree.lock_write()
421
 
        try:
422
 
            tree2 = tree.bzrdir.sprout(root + '/tree2').open_workingtree()
423
 
            tree2.lock_write()
424
 
            try:
425
 
                for i in xrange(250):
426
 
                    revision_id = tree.commit('no-changes commit %d-a' % i)
427
 
                    tree2.branch.fetch(tree.branch, revision_id)
428
 
                    tree2.set_pending_merges([revision_id])
429
 
                    revision_id = tree2.commit('no-changes commit %d-b' % i)
430
 
                    tree.branch.fetch(tree2.branch, revision_id)
431
 
                    tree.set_pending_merges([revision_id])
432
 
                tree.set_pending_merges([])
433
 
            finally:
434
 
                tree2.unlock()
435
 
        finally:
436
 
            tree.unlock()
437
 
        if in_cache:
438
 
            self._protect_files(root+'/.bzr')
439
 
        return tree
440
 
 
441
 
 
442
117
def test_suite():
443
118
    """Build and return a TestSuite which contains benchmark tests only."""
444
119
    testmod_names = [ \