~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_lsprof.py

  • Committer: Jelmer Vernooij
  • Date: 2010-12-20 11:57:14 UTC
  • mto: This revision was merged to the branch mainline in revision 5577.
  • Revision ID: jelmer@samba.org-20101220115714-2ru3hfappjweeg7q
Don't use no-plugins.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007, 2009, 2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Tests for profiling data collection."""
 
18
 
 
19
 
 
20
import cPickle
 
21
import os
 
22
import threading
 
23
 
 
24
import bzrlib
 
25
from bzrlib import errors, tests
 
26
 
 
27
 
 
28
class _LSProfFeature(tests.Feature):
 
29
 
 
30
    def available(self):
 
31
        try:
 
32
            from bzrlib import lsprof
 
33
        except ImportError:
 
34
            return False
 
35
        else:
 
36
            return True
 
37
 
 
38
 
 
39
LSProfFeature = _LSProfFeature()
 
40
 
 
41
 
 
42
_TXT_HEADER = "   CallCount    Recursive    Total(ms)   " + \
 
43
    "Inline(ms) module:lineno(function)\n"
 
44
 
 
45
 
 
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."
 
53
    from bzrlib.lsprof import profile
 
54
    ret, stats = profile(_junk_callable)
 
55
    return stats
 
56
 
 
57
 
 
58
class TestStatsSave(tests.TestCaseInTempDir):
 
59
 
 
60
    _test_needs_features = [LSProfFeature]
 
61
 
 
62
    def setUp(self):
 
63
        super(tests.TestCaseInTempDir, self).setUp()
 
64
        self.stats = _collect_stats()
 
65
 
 
66
    def _tempfile(self, ext):
 
67
        dir = self.test_dir
 
68
        return bzrlib.osutils.pathjoin(dir, "tmp_profile_data." + ext)
 
69
 
 
70
    def test_stats_save_to_txt(self):
 
71
        f = self._tempfile("txt")
 
72
        self.stats.save(f)
 
73
        lines = open(f).readlines()
 
74
        self.assertEqual(lines[0], _TXT_HEADER)
 
75
 
 
76
    def test_stats_save_to_callgrind(self):
 
77
        f = self._tempfile("callgrind")
 
78
        self.stats.save(f)
 
79
        lines = open(f).readlines()
 
80
        self.assertEqual(lines[0], "events: Ticks\n")
 
81
        f = bzrlib.osutils.pathjoin(self.test_dir, "callgrind.out.foo")
 
82
        self.stats.save(f)
 
83
        lines = open(f).readlines()
 
84
        self.assertEqual(lines[0], "events: Ticks\n")
 
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")
 
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)
 
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)
 
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)