37
37
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38
38
# SOFTWARE.
39
39
40
+ from time import time
41
+
42
+ # Capture module load time as soon as possible for other engines. The unit is seconds.
43
+ _module_start_time = time ()
44
+
40
45
import _io
41
46
import os
42
47
import sys
43
48
import types
44
- from time import time , monotonic_ns
45
49
46
50
GRAALPYTHON = sys .implementation .name == "graalpython"
47
51
52
+ # Try to use the timer with best accuracy. Unfortunately, 'monotonic_ns' is not available everywhere.
53
+ if GRAALPYTHON :
54
+ from time import monotonic_ns
55
+ monotonic_best_accuracy = monotonic_ns
56
+ UNITS_PER_SECOND = 1e9
57
+ else :
58
+ monotonic_best_accuracy = time
59
+ UNITS_PER_SECOND = 1.0
60
+
48
61
_HRULE = '-' .join (['' for i in range (80 )])
49
62
50
63
#: this function is used to pre-process the arguments as expected by the __benchmark__ and __setup__ entry points
59
72
ATTR_TEARDOWN = '__teardown__'
60
73
61
74
75
+ def get_seconds_since_startup (cur_time ):
76
+ if GRAALPYTHON and __graalpython__ .startup_nano != - 1 :
77
+ return (cur_time - __graalpython__ .startup_nano ) / UNITS_PER_SECOND
78
+ # note: the unit of _module_start_time is seconds
79
+ return cur_time / UNITS_PER_SECOND - _module_start_time
80
+
81
+
62
82
# ----------------------------------------------------------------------------------------------------------------------
63
83
#
64
84
# the CUSUM method adapted for warmup detection within a given threshold (initial iterations)
@@ -273,34 +293,31 @@ def run(self):
273
293
self ._call_attr (ATTR_SETUP , * args )
274
294
print ("### start benchmark ... " )
275
295
276
- report_startup = GRAALPYTHON and self .startup and __graalpython__ . startup_nano != - 1
296
+ report_startup = self .startup
277
297
278
298
bench_func = self ._get_attr (ATTR_BENCHMARK )
279
- startup_ns = - 1
280
- early_warmup_ns = - 1
281
- late_warmup_ns = - 1
299
+ startup_s = - 1.0
300
+ early_warmup_s = - 1.0
301
+ late_warmup_s = - 1.0
282
302
durations = []
283
303
if bench_func and hasattr (bench_func , '__call__' ):
284
304
if self .warmup_runs :
285
305
print ("### (pre)warming up for %s iterations ... " % self .warmup_runs )
286
306
for _ in range (self .warmup_runs ):
287
307
bench_func (* args )
288
- cur_time_nano = monotonic_ns ()
289
- if report_startup and startup_ns == - 1 :
290
- startup_ns = cur_time_nano - __graalpython__ .startup_nano
291
308
self ._call_attr (ATTR_CLEANUP , * args )
292
309
293
310
for iteration in range (self .iterations ):
294
311
start = time ()
295
312
bench_func (* args )
296
- cur_time_nano = monotonic_ns ()
313
+ cur_time = monotonic_best_accuracy ()
297
314
duration = time () - start
298
- if report_startup and startup_ns == - 1 and iteration == self .startup [0 ] - 1 :
299
- startup_ns = cur_time_nano - __graalpython__ . startup_nano
300
- if report_startup and early_warmup_ns == - 1 and iteration == self .startup [1 ] - 1 :
301
- early_warmup_ns = cur_time_nano - __graalpython__ . startup_nano
302
- if report_startup and late_warmup_ns == - 1 and iteration == self .startup [2 ] - 1 :
303
- late_warmup_ns = cur_time_nano - __graalpython__ . startup_nano
315
+ if report_startup and startup_s < 0.0 and iteration == self .startup [0 ] - 1 :
316
+ startup_s = get_seconds_since_startup ( cur_time )
317
+ if report_startup and early_warmup_s < 0.0 and iteration == self .startup [1 ] - 1 :
318
+ early_warmup_s = get_seconds_since_startup ( cur_time )
319
+ if report_startup and late_warmup_s < 0 and iteration == self .startup [2 ] - 1 :
320
+ late_warmup_s = get_seconds_since_startup ( cur_time )
304
321
durations .append (duration )
305
322
duration_str = "%.3f" % duration
306
323
self ._call_attr (ATTR_CLEANUP , * args )
@@ -330,9 +347,9 @@ def run(self):
330
347
# summary
331
348
# We can do that only on Graalpython
332
349
if report_startup :
333
- print ("### STARTUP at iteration: %d, duration: %.3f" % (self .startup [0 ], startup_ns / 1e9 ))
334
- print ("### EARLY WARMUP at iteration: %d, duration: %.3f" % (self .startup [1 ], early_warmup_ns / 1e9 ))
335
- print ("### LATE WARMUP at iteration: %d, duration: %.3f" % (self .startup [2 ], late_warmup_ns / 1e9 ))
350
+ print ("### STARTUP at iteration: %d, duration: %.3f" % (self .startup [0 ], startup_s ))
351
+ print ("### EARLY WARMUP at iteration: %d, duration: %.3f" % (self .startup [1 ], early_warmup_s ))
352
+ print ("### LATE WARMUP at iteration: %d, duration: %.3f" % (self .startup [2 ], late_warmup_s ))
336
353
if self ._run_once :
337
354
print ("### SINGLE RUN duration: %.3f s" % durations [0 ])
338
355
else :
@@ -356,7 +373,7 @@ def run(self):
356
373
print ("### WARMUP iteration not specified or could not be detected" )
357
374
358
375
if GRAALPYTHON and self .startup and __graalpython__ .startup_nano == - 1 :
359
- print ("### Startup could not be measured. You need to enable startup time snapshotting." )
376
+ print ("### NOTE: enable startup time snapshotting to increase accuracy ." )
360
377
361
378
print (_HRULE )
362
379
print ("### RAW DURATIONS: %s" % str (durations ))
0 commit comments