@@ -91,6 +91,69 @@ def test_consts(self):
91
91
fco = ns [f"f{ num } " ]
92
92
assert (num , f"hello { num } " ) in fco .__code__ .co_consts
93
93
94
+ _LOAD_EXEC = 'load+exec'
95
+ _STEADY_STATE = 'steady-state'
96
+
97
+ def speed_comparison (source , test_name ):
98
+ print ()
99
+ print (f"Starting speed test: { test_name } " )
100
+ def helper (data , label ):
101
+ timings = {}
102
+ t0 = time .perf_counter ()
103
+ codes = []
104
+ for _ in range (1000 ):
105
+ code = marshal .loads (data )
106
+ codes .append (code )
107
+ t1 = time .perf_counter ()
108
+ print (f"{ label } load: { t1 - t0 :.3f} " )
109
+ timings ['load' ] = t1 - t0
110
+ timings ['execs' ] = []
111
+ for i in range (4 ):
112
+ t3 = time .perf_counter ()
113
+ for code in codes :
114
+ exec (code , {})
115
+ t4 = time .perf_counter ()
116
+ print (f"{ label } exec #{ i + 1 } : { t4 - t3 :.3f} " )
117
+ timings ['execs' ].append (t4 - t3 )
118
+ print (f" { label } total: { t4 - t0 :.3f} " )
119
+ return timings
120
+
121
+ code = compile (source , "<old>" , "exec" )
122
+ data = marshal .dumps (code )
123
+ classic_timings = helper (data , "Classic" )
124
+
125
+ t0 = time .perf_counter ()
126
+ data = pyco .serialize_source (source , "<new>" )
127
+ t1 = time .perf_counter ()
128
+ print (f"PYCO: { t1 - t0 :.3f} " )
129
+ assert data .startswith (b"PYC." )
130
+ new_timings = helper (data , "New PYC" )
131
+
132
+ if classic_timings and new_timings :
133
+ def comparison (title , f ):
134
+ tc = f (classic_timings )
135
+ tn = f (new_timings )
136
+ print (f">> { title } ratio: { tn / tc :.2f} "
137
+ f"(new is { 100 * (tn / tc - 1 ):.0f} % faster)" )
138
+ return tn / tc
139
+
140
+ print ("Classic-to-new comparison:" )
141
+ result = {
142
+ _LOAD_EXEC : comparison (_LOAD_EXEC , lambda t : t ['load' ] + t ['execs' ][0 ]),
143
+ _STEADY_STATE : comparison (_STEADY_STATE , lambda t : t ['execs' ][- 1 ])
144
+ }
145
+ print ()
146
+ return result
147
+
148
+
149
+ class TestSpeedComparisonApi (unittest .TestCase ):
150
+ def test_speed_comparison_api (self ):
151
+ # Note: if this test needs to change then
152
+ # Tools/pyco/perf_micro.py probably does too.
153
+ r = speed_comparison ("x=1" , "test" )
154
+ self .assertIsInstance (r , dict )
155
+ self .assertCountEqual (r .keys (), [_LOAD_EXEC , _STEADY_STATE ])
156
+
94
157
95
158
class TestNewPycSpeed (unittest .TestCase ):
96
159
@@ -100,9 +163,9 @@ def setUpClass(cls):
100
163
101
164
@classmethod
102
165
def tearDownClass (cls ):
103
- print (f"{ ' ' :25} { 'load+exec' :>15} { 'steady state' :>15} " )
104
- for t , r in sorted (cls .results .items (), key = lambda kv : - kv [1 ][0 ]):
105
- print (f"{ t :25} { r [0 ]:15.3f} { r [1 ]:15.3f} " )
166
+ print (f"{ ' ' :25} { _LOAD_EXEC :>15} { 'steady state' :>15} " )
167
+ for t , r in sorted (cls .results .items (), key = lambda kv : - kv [1 ][_LOAD_EXEC ]):
168
+ print (f"{ t :25} { r [_LOAD_EXEC ]:15.3f} { r [_STEADY_STATE ]:15.3f} " )
106
169
print ()
107
170
cls .results = {}
108
171
@@ -124,55 +187,9 @@ def do_test_speed(self, body, call=False):
124
187
source = "\n \n " .join (functions )
125
188
self .do_test_speed_for_source (source )
126
189
127
- def do_test_speed_for_source (self , source ):
128
- print ()
129
- print (f"Starting speed test: { self ._testMethodName } " )
130
- def helper (data , label ):
131
- timings = {}
132
- t0 = time .perf_counter ()
133
- codes = []
134
- for _ in range (1000 ):
135
- code = marshal .loads (data )
136
- codes .append (code )
137
- t1 = time .perf_counter ()
138
- print (f"{ label } load: { t1 - t0 :.3f} " )
139
- timings ['load' ] = t1 - t0
140
- timings ['execs' ] = []
141
- for i in range (4 ):
142
- t3 = time .perf_counter ()
143
- for code in codes :
144
- exec (code , {})
145
- t4 = time .perf_counter ()
146
- print (f"{ label } exec #{ i + 1 } : { t4 - t3 :.3f} " )
147
- timings ['execs' ].append (t4 - t3 )
148
- print (f" { label } total: { t4 - t0 :.3f} " )
149
- return timings
150
-
151
- code = compile (source , "<old>" , "exec" )
152
- data = marshal .dumps (code )
153
- classic_timings = helper (data , "Classic" )
154
-
155
- t0 = time .perf_counter ()
156
- data = pyco .serialize_source (source , "<new>" )
157
- t1 = time .perf_counter ()
158
- print (f"PYCO: { t1 - t0 :.3f} " )
159
- assert data .startswith (b"PYC." )
160
- new_timings = helper (data , "New PYC" )
161
-
162
- if classic_timings and new_timings :
163
- def comparison (title , f ):
164
- tc = f (classic_timings )
165
- tn = f (new_timings )
166
- print (f">> { title } ratio: { tn / tc :.2f} "
167
- f"(new is { 100 * (tc / tn - 1 ):.0f} % faster)" )
168
- return tn / tc
169
-
170
- print ("Classic-to-new comparison:" )
171
- self .results [self ._testMethodName .lstrip ('test_speed_' )] = [
172
- comparison ('load+exec' , lambda t : t ['load' ] + t ['execs' ][0 ]),
173
- comparison ('steady state' , lambda t : t ['execs' ][- 1 ])
174
- ]
175
- print ()
190
+ def do_test_speed_for_source (self , source , test_name = None ):
191
+ test_name = test_name or self ._testMethodName .lstrip ('test_speed_' )
192
+ self .results [test_name ] = speed_comparison (source , test_name )
176
193
177
194
def test_speed_few_locals (self ):
178
195
body = " a, b = b, a\n " * 100
0 commit comments