~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/benchmarks/bench_dirstate.py

  • Committer: Alexander Belchenko
  • Date: 2006-07-30 16:43:12 UTC
  • mto: (1711.2.111 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1906.
  • Revision ID: bialix@ukr.net-20060730164312-b025fd3ff0cee59e
rename  gpl.txt => COPYING.txt

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007 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
 
"""Benchmarks for bzr DirState performance."""
18
 
 
19
 
import os
20
 
 
21
 
from bzrlib import (
22
 
    benchmarks,
23
 
    dirstate,
24
 
    generate_ids,
25
 
    osutils,
26
 
    tests,
27
 
    )
28
 
from bzrlib.tests.compiled.test_dirstate_helpers import (
29
 
    CompiledDirstateHelpersFeature,
30
 
    )
31
 
 
32
 
 
33
 
class BenchmarkDirState(benchmarks.Benchmark):
34
 
 
35
 
    def build_helper(self, layout):
36
 
        """This is a helper with the common build_??_dirstate funcs.
37
 
 
38
 
        :param layout: [(num_dirs, files_per_dir)]
39
 
            The number of directories per level, and the number of files to put
40
 
            in it.
41
 
        :return: A DirState object with the given layout.
42
 
        """
43
 
        self.build_tree(['dir/'])
44
 
        contents = 'x'*10000
45
 
        self.build_tree_contents([('file', contents)])
46
 
        file_stat = os.lstat('file')
47
 
        dir_stat = os.lstat('dir')
48
 
        file_sha1 = osutils.sha_string(contents)
49
 
 
50
 
        state = dirstate.DirState.initialize('state')
51
 
        try:
52
 
            def create_entries(base, layout):
53
 
                if not layout:
54
 
                    return
55
 
                num_dirs, num_files = layout[0]
56
 
                for dnum in xrange(num_dirs):
57
 
                    if base:
58
 
                        path = '%s/%02d_directory' % (base, dnum)
59
 
                    else:
60
 
                        path = '%02d_directory' % (dnum,)
61
 
                    dir_id = generate_ids.gen_file_id(path)
62
 
                    state.add(path, dir_id, 'directory', dir_stat, '')
63
 
                    for fnum in xrange(num_files):
64
 
                        fname = '%s/%02d_filename' % (path, fnum)
65
 
                        file_id = generate_ids.gen_file_id(fname)
66
 
                        state.add(fname, file_id, 'file', file_stat, file_sha1)
67
 
                    create_entries(path, layout[1:])
68
 
            create_entries(None, layout)
69
 
            state.save()
70
 
        finally:
71
 
            state.unlock()
72
 
        return state
73
 
 
74
 
    def build_10k_dirstate_dirs(self):
75
 
        """Build a DirState file with 10k directories"""
76
 
        return self.build_helper([(10, 0), (10, 0), (10, 0), (10, 1)])
77
 
 
78
 
    def build_20k_dirstate(self):
79
 
        """Build a DirState file with 20k records.
80
 
 
81
 
        This approximates a kernel tree, based on the number of directories
82
 
        (1000), and number of files per directory (20) and depth (3).
83
 
        Because DirState doesn't have to have actual disk records, we just add
84
 
        random files.
85
 
        We try to have reasonable filename lengths, as well as a reasonable
86
 
        stat value, etc.
87
 
        """
88
 
        return self.build_helper([(10, 0), (10, 0), (10, 20)])
89
 
 
90
 
    def test_build_20k_dirblocks(self):
91
 
        state = self.time(self.build_20k_dirstate)
92
 
        state.lock_read()
93
 
        try:
94
 
            entries = list(state._iter_entries())
95
 
            self.assertEqual(21111, len(entries))
96
 
        finally:
97
 
            state.unlock()
98
 
 
99
 
    def test__read_dirblocks_20k_tree_no_parents(self):
100
 
        state = self.build_20k_dirstate()
101
 
        state.lock_read()
102
 
        try:
103
 
            self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
104
 
                             state._dirblock_state)
105
 
            self.time(state._read_dirblocks_if_needed)
106
 
        finally:
107
 
            state.unlock()
108
 
 
109
 
    def do_bisect_list(self, bisect_func):
110
 
        """Call bisect_dirblock for each path."""
111
 
        # We use self._paths and self._blocks because we expect it to be a very
112
 
        # long list. And the interface for 'self.time()' causes the parameters
113
 
        # to be printed when run with --lsprof-timed. Which is *really* ugly
114
 
        # when the list is thousands of entries.
115
 
        blocks = self._blocks
116
 
        return [bisect_func(blocks, path) for path in self._paths]
117
 
 
118
 
    def do_bisect_list_cached(self, bisect_func):
119
 
        """Same as do_bisect_list, but cache the split paths"""
120
 
        cache = {}
121
 
        blocks = self._blocks
122
 
        return [bisect_func(blocks, path, cache=cache) for path in self._paths]
123
 
 
124
 
    def setup_paths_and_offsets(self, state):
125
 
        """Get a list of paths and expected offsets.
126
 
 
127
 
        This will be used to check do_bisect_list*
128
 
        """
129
 
        state._read_dirblocks_if_needed()
130
 
        paths = ['']
131
 
        expected_offsets = [0]
132
 
        for offset, info in enumerate(state._dirblocks):
133
 
            dirname = info[0]
134
 
            # We already handled the empty path
135
 
            if dirname == '':
136
 
                continue
137
 
            # all paths are of the form ##_directory
138
 
            # so search for ##_director, ##_directory
139
 
            paths.extend([dirname[:-1], dirname])
140
 
            expected_offsets.extend([offset, offset])
141
 
        self._paths = paths
142
 
        self._expected_offsets = expected_offsets
143
 
        self._blocks = state._dirblocks
144
 
 
145
 
    def checkOffsets(self, offsets):
146
 
        """Make sure offsets matches self._expected_offsets"""
147
 
        # These are really long lists, so it is easier to compare them with
148
 
        # assertEqualDiff. So turn them into strings.
149
 
        expected_str = '\n'.join(str(x) for x in self._expected_offsets)
150
 
        offset_str = '\n'.join(str(x) for x in offsets)
151
 
        self.assertEqualDiff(expected_str, offset_str)
152
 
 
153
 
    def test_py_bisect_dirblock(self):
154
 
        state = self.build_10k_dirstate_dirs()
155
 
        state.lock_read()
156
 
        try:
157
 
            self.setup_paths_and_offsets(state)
158
 
            offsets = self.time(self.do_bisect_list, dirstate.py_bisect_dirblock)
159
 
            self.checkOffsets(offsets)
160
 
        finally:
161
 
            state.unlock()
162
 
 
163
 
    def test_py_bisect_dirblock_cached(self):
164
 
        state = self.build_10k_dirstate_dirs()
165
 
        state.lock_read()
166
 
        try:
167
 
            self.setup_paths_and_offsets(state)
168
 
            offsets = self.time(self.do_bisect_list_cached,
169
 
                                dirstate.py_bisect_dirblock)
170
 
            self.checkOffsets(offsets)
171
 
        finally:
172
 
            state.unlock()
173
 
 
174
 
    def test_c_bisect_dirblock(self):
175
 
        self.requireFeature(CompiledDirstateHelpersFeature)
176
 
        from bzrlib.compiled.dirstate_helpers import c_bisect_dirblock
177
 
        state = self.build_10k_dirstate_dirs()
178
 
        state.lock_read()
179
 
        try:
180
 
            self.setup_paths_and_offsets(state)
181
 
            offsets = self.time(self.do_bisect_list, c_bisect_dirblock)
182
 
            self.checkOffsets(offsets)
183
 
        finally:
184
 
            state.unlock()