~bzr-pqm/bzr/bzr.dev

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