~bzr-pqm/bzr/bzr.dev

5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2007, 2009, 2010, 2011 Canonical Ltd
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
16
17
"""Tests for profiling data collection."""
18
19
20
import cPickle
5331.1.1 by Robert Collins
``bzrlib.lsprof.profile`` will no longer silently generate bad threaded
21
import threading
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
22
23
import bzrlib
5331.1.1 by Robert Collins
``bzrlib.lsprof.profile`` will no longer silently generate bad threaded
24
from bzrlib import errors, tests
2493.2.6 by Aaron Bentley
Make LSProf into a Feature required by the appropriate tests
25
26
1551.15.28 by Aaron Bentley
Improve Feature usage style w/ lsprof
27
class _LSProfFeature(tests.Feature):
2493.2.6 by Aaron Bentley
Make LSProf into a Feature required by the appropriate tests
28
29
    def available(self):
30
        try:
31
            from bzrlib import lsprof
32
        except ImportError:
33
            return False
34
        else:
35
            return True
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
36
37
1551.15.28 by Aaron Bentley
Improve Feature usage style w/ lsprof
38
LSProfFeature = _LSProfFeature()
39
40
2493.2.5 by Ian Clatworthy
explicit format saving test
41
_TXT_HEADER = "   CallCount    Recursive    Total(ms)   " + \
42
    "Inline(ms) module:lineno(function)\n"
43
44
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
45
def _junk_callable():
46
    "A simple routine to profile."
47
    result = sorted(['abc', 'def', 'ghi'])
48
49
50
def _collect_stats():
51
    "Collect and return some dummy profile data."
2493.2.6 by Aaron Bentley
Make LSProf into a Feature required by the appropriate tests
52
    from bzrlib.lsprof import profile
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
53
    ret, stats = profile(_junk_callable)
54
    return stats
55
56
2493.2.6 by Aaron Bentley
Make LSProf into a Feature required by the appropriate tests
57
class TestStatsSave(tests.TestCaseInTempDir):
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
58
1551.15.28 by Aaron Bentley
Improve Feature usage style w/ lsprof
59
    _test_needs_features = [LSProfFeature]
60
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
61
    def setUp(self):
2493.2.6 by Aaron Bentley
Make LSProf into a Feature required by the appropriate tests
62
        super(tests.TestCaseInTempDir, self).setUp()
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
63
        self.stats = _collect_stats()
64
65
    def _tempfile(self, ext):
66
        dir = self.test_dir
2805.7.5 by Ian Clatworthy
more win32 path friendliness
67
        return bzrlib.osutils.pathjoin(dir, "tmp_profile_data." + ext)
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
68
69
    def test_stats_save_to_txt(self):
70
        f = self._tempfile("txt")
71
        self.stats.save(f)
72
        lines = open(f).readlines()
2493.2.5 by Ian Clatworthy
explicit format saving test
73
        self.assertEqual(lines[0], _TXT_HEADER)
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
74
75
    def test_stats_save_to_callgrind(self):
76
        f = self._tempfile("callgrind")
77
        self.stats.save(f)
78
        lines = open(f).readlines()
2493.2.5 by Ian Clatworthy
explicit format saving test
79
        self.assertEqual(lines[0], "events: Ticks\n")
2805.7.5 by Ian Clatworthy
more win32 path friendliness
80
        f = bzrlib.osutils.pathjoin(self.test_dir, "callgrind.out.foo")
2805.7.2 by Ian Clatworthy
use basename, not full path, when checking for callgrind.out file prefix
81
        self.stats.save(f)
82
        lines = open(f).readlines()
83
        self.assertEqual(lines[0], "events: Ticks\n")
2493.2.5 by Ian Clatworthy
explicit format saving test
84
        # Test explicit format nommination
85
        f2 = self._tempfile("txt")
86
        self.stats.save(f2, format="callgrind")
87
        lines2 = open(f2).readlines()
88
        self.assertEqual(lines2[0], "events: Ticks\n")
2493.2.3 by Ian Clatworthy
changes requested in jameinel's review incorporated
89
90
    def test_stats_save_to_pickle(self):
91
        f = self._tempfile("pkl")
92
        self.stats.save(f)
93
        data1 = cPickle.load(open(f))
94
        self.assertEqual(type(data1), bzrlib.lsprof.Stats)
4641.3.2 by Robert Collins
lsprof support.
95
96
97
class TestBzrProfiler(tests.TestCase):
98
99
    _test_needs_features = [LSProfFeature]
100
101
    def test_start_call_stuff_stop(self):
102
        profiler = bzrlib.lsprof.BzrProfiler()
103
        profiler.start()
104
        try:
105
            def a_function():
106
                pass
107
            a_function()
108
        finally:
109
            stats = profiler.stop()
110
        stats.freeze()
111
        lines = [str(data) for data in stats.data]
112
        lines = [line for line in lines if 'a_function' in line]
113
        self.assertLength(1, lines)
5331.1.1 by Robert Collins
``bzrlib.lsprof.profile`` will no longer silently generate bad threaded
114
115
    def test_block_0(self):
116
        # When profiler_block is 0, reentrant profile requests fail.
117
        self.overrideAttr(bzrlib.lsprof.BzrProfiler, 'profiler_block', 0)
118
        inner_calls = []
119
        def inner():
120
            profiler = bzrlib.lsprof.BzrProfiler()
121
            self.assertRaises(errors.BzrError, profiler.start)
122
            inner_calls.append(True)
123
        bzrlib.lsprof.profile(inner)
124
        self.assertLength(1, inner_calls)
125
126
    def test_block_1(self):
127
        # When profiler_block is 1, concurrent profiles serialise.
128
        # This is tested by manually acquiring the profiler lock, then
129
        # starting a thread that tries to profile, and releasing the lock. 
130
        # We know due to test_block_0 that two profiles at once hit the lock,
131
        # so while this isn't perfect (we'd want a callback on the lock being
132
        # entered to allow lockstep evaluation of the actions), its good enough
133
        # to be confident regressions would be caught. Alternatively, if this
134
        # is flakey, a fake Lock object can be used to trace the calls made.
135
        calls = []
136
        def profiled():
137
            calls.append('profiled')
138
        def do_profile():
139
            bzrlib.lsprof.profile(profiled)
140
            calls.append('after_profiled')
141
        thread = threading.Thread(target=do_profile)
142
        bzrlib.lsprof.BzrProfiler.profiler_lock.acquire()
143
        try:
144
            try:
145
                thread.start()
146
            finally:
147
                bzrlib.lsprof.BzrProfiler.profiler_lock.release()
148
        finally:
149
            thread.join()
150
        self.assertLength(2, calls)