1
# Copyright (C) 2007, 2009, 2010, 2011 Canonical Ltd
1
# Copyright (C) 2005, 2006 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""Tests for profiling data collection."""
24
from bzrlib import errors, tests
25
from bzrlib.tests import (
24
from bzrlib import tests
27
class _LSProfFeature(tests.Feature):
31
from bzrlib import lsprof
38
LSProfFeature = _LSProfFeature()
30
41
_TXT_HEADER = " CallCount Recursive Total(ms) " + \
46
57
class TestStatsSave(tests.TestCaseInTempDir):
48
_test_needs_features = [features.lsprof_feature]
59
_test_needs_features = [LSProfFeature]
51
62
super(tests.TestCaseInTempDir, self).setUp()
54
65
def _tempfile(self, ext):
55
66
dir = self.test_dir
56
return bzrlib.osutils.pathjoin(dir, "tmp_profile_data." + ext)
67
return os.path.join(dir, "tmp_profile_data." + ext)
58
69
def test_stats_save_to_txt(self):
59
70
f = self._tempfile("txt")
67
78
lines = open(f).readlines()
68
79
self.assertEqual(lines[0], "events: Ticks\n")
69
f = bzrlib.osutils.pathjoin(self.test_dir, "callgrind.out.foo")
71
lines = open(f).readlines()
72
self.assertEqual(lines[0], "events: Ticks\n")
73
80
# Test explicit format nommination
74
81
f2 = self._tempfile("txt")
75
82
self.stats.save(f2, format="callgrind")
82
89
data1 = cPickle.load(open(f))
83
90
self.assertEqual(type(data1), bzrlib.lsprof.Stats)
86
class TestBzrProfiler(tests.TestCase):
88
_test_needs_features = [features.lsprof_feature]
90
def test_start_call_stuff_stop(self):
91
profiler = bzrlib.lsprof.BzrProfiler()
98
stats = profiler.stop()
100
lines = [str(data) for data in stats.data]
101
lines = [line for line in lines if 'a_function' in line]
102
self.assertLength(1, lines)
104
def test_block_0(self):
105
# When profiler_block is 0, reentrant profile requests fail.
106
self.overrideAttr(bzrlib.lsprof.BzrProfiler, 'profiler_block', 0)
109
profiler = bzrlib.lsprof.BzrProfiler()
110
self.assertRaises(errors.BzrError, profiler.start)
111
inner_calls.append(True)
112
bzrlib.lsprof.profile(inner)
113
self.assertLength(1, inner_calls)
115
def test_block_1(self):
116
# When profiler_block is 1, concurrent profiles serialise.
117
# This is tested by manually acquiring the profiler lock, then
118
# starting a thread that tries to profile, and releasing the lock.
119
# We know due to test_block_0 that two profiles at once hit the lock,
120
# so while this isn't perfect (we'd want a callback on the lock being
121
# entered to allow lockstep evaluation of the actions), its good enough
122
# to be confident regressions would be caught. Alternatively, if this
123
# is flakey, a fake Lock object can be used to trace the calls made.
126
calls.append('profiled')
128
bzrlib.lsprof.profile(profiled)
129
calls.append('after_profiled')
130
thread = threading.Thread(target=do_profile)
131
bzrlib.lsprof.BzrProfiler.profiler_lock.acquire()
136
bzrlib.lsprof.BzrProfiler.profiler_lock.release()
139
self.assertLength(2, calls)