summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_cProfile.py
blob: 07b2a9b54e39131212531cef2c988e3f7a0dcc0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""Test suite for the cProfile module."""

import cProfile, pstats, sys

# In order to have reproducible time, we simulate a timer in the global
# variable 'ticks', which represents simulated time in milliseconds.
# (We can't use a helper function increment the timer since it would be
# included in the profile and would appear to consume all the time.)
ticks = 0

# IMPORTANT: this is an output test.  *ALL* NUMBERS in the expected
# output are relevant.  If you change the formatting of pstats,
# please don't just regenerate output/test_cProfile without checking
# very carefully that not a single number has changed.

def test_main():
    global ticks
    ticks = 42000
    prof = cProfile.Profile(timer, 0.001)
    prof.runctx("testfunc()", globals(), locals())
    assert ticks == 43000, ticks
    st = pstats.Stats(prof)
    st.strip_dirs().sort_stats('stdname').print_stats()
    st.print_callees()
    st.print_callers()

def timer():
    return ticks

def testfunc():
    # 1 call
    # 1000 ticks total: 270 ticks local, 730 ticks in subfunctions
    global ticks
    ticks += 99
    helper()                            # 300
    helper()                            # 300
    ticks += 171
    factorial(14)                       # 130

def factorial(n):
    # 23 calls total
    # 170 ticks total, 150 ticks local
    # 3 primitive calls, 130, 20 and 20 ticks total
    # including 116, 17, 17 ticks local
    global ticks
    if n > 0:
        ticks += n
        return mul(n, factorial(n-1))
    else:
        ticks += 11
        return 1

def mul(a, b):
    # 20 calls
    # 1 tick, local
    global ticks
    ticks += 1
    return a * b

def helper():
    # 2 calls
    # 300 ticks total: 20 ticks local, 260 ticks in subfunctions
    global ticks
    ticks += 1
    helper1()                           # 30
    ticks += 2
    helper1()                           # 30
    ticks += 6
    helper2()                           # 50
    ticks += 3
    helper2()                           # 50
    ticks += 2
    helper2()                           # 50
    ticks += 5
    helper2_indirect()                  # 70
    ticks += 1

def helper1():
    # 4 calls
    # 30 ticks total: 29 ticks local, 1 tick in subfunctions
    global ticks
    ticks += 10
    hasattr(C(), "foo")                 # 1
    ticks += 19
    lst = []
    lst.append(42)                      # 0
    sys.exc_info()                      # 0

def helper2_indirect():
    helper2()                           # 50
    factorial(3)                        # 20

def helper2():
    # 8 calls
    # 50 ticks local: 39 ticks local, 11 ticks in subfunctions
    global ticks
    ticks += 11
    hasattr(C(), "bar")                 # 1
    ticks += 13
    subhelper()                         # 10
    ticks += 15

def subhelper():
    # 8 calls
    # 10 ticks total: 8 ticks local, 2 ticks in subfunctions
    global ticks
    ticks += 2
    for i in range(2):                  # 0
        try:
            C().foo                     # 1 x 2
        except AttributeError:
            ticks += 3                  # 3 x 2

class C:
    def __getattr__(self, name):
        # 28 calls
        # 1 tick, local
        global ticks
        ticks += 1
        raise AttributeError

if __name__ == "__main__":
    test_main()