4
4
import sys
5
5
import time
6
6
import traceback
7
+ import concurrent .futures
8
+ import io
9
+ import contextlib
7
10
8
11
import pyperformance
9
12
from . import _utils , _python , _pythoninfo
@@ -67,47 +70,40 @@ def get_loops_from_file(filename):
67
70
return loops
68
71
69
72
70
- def run_benchmarks (should_run , python , options ):
71
- if options .same_loops is not None :
72
- loops = get_loops_from_file (options .same_loops )
73
- else :
74
- loops = {}
75
-
76
- to_run = sorted (should_run )
73
+ def setup_single_venv (args ):
74
+ (i , num_benchmarks , python , options , bench ) = args
77
75
78
- info = _pythoninfo .get_info (python )
79
- runid = get_run_id (info )
76
+ stdout = io .StringIO ()
77
+ with contextlib .redirect_stdout (stdout ):
78
+ info = _pythoninfo .get_info (python )
79
+ runid = get_run_id (info )
80
80
81
- unique = getattr (options , 'unique_venvs' , False )
82
- if not unique :
83
- common = VenvForBenchmarks .ensure (
84
- _venv .get_venv_root (runid .name , python = info ),
85
- info ,
86
- upgrade = 'oncreate' ,
87
- inherit_environ = options .inherit_environ ,
88
- )
89
-
90
- benchmarks = {}
91
- venvs = set ()
92
- for i , bench in enumerate (to_run ):
81
+ unique = getattr (options , 'unique_venvs' , False )
82
+ if not unique :
83
+ common = VenvForBenchmarks .ensure (
84
+ _venv .get_venv_root (runid .name , python = info ),
85
+ info ,
86
+ upgrade = 'oncreate' ,
87
+ inherit_environ = options .inherit_environ ,
88
+ )
93
89
bench_runid = runid ._replace (bench = bench )
94
90
assert bench_runid .name , (bench , bench_runid )
95
91
name = bench_runid .name
96
92
venv_root = _venv .get_venv_root (name , python = info )
93
+ bench_status = f'({ i + 1 :>2} /{ num_benchmarks } )'
97
94
print ()
98
95
print ('=' * 50 )
99
- print (f'( { i + 1 :>2 } / { len ( to_run ) } ) creating venv for benchmark ({ bench .name } )' )
96
+ print (f'{ bench_status } creating venv for benchmark ({ bench .name } )' )
100
97
print ()
101
98
if not unique :
102
- print (' (trying common venv first)' )
99
+ print (f' { bench_status } (trying common venv first)' )
103
100
# Try the common venv first.
104
101
try :
105
102
common .ensure_reqs (bench )
106
103
except _venv .RequirementsInstallationFailedError :
107
- print (' (falling back to unique venv)' )
104
+ print (f' { bench_status } (falling back to unique venv)' )
108
105
else :
109
- benchmarks [bench ] = (common , bench_runid )
110
- continue
106
+ return (bench , None , common , bench_runid , stdout .getvalue ())
111
107
try :
112
108
venv = VenvForBenchmarks .ensure (
113
109
venv_root ,
@@ -118,12 +114,43 @@ def run_benchmarks(should_run, python, options):
118
114
# XXX Do not override when there is a requirements collision.
119
115
venv .ensure_reqs (bench )
120
116
except _venv .RequirementsInstallationFailedError :
121
- print (' (benchmark will be skipped)' )
117
+ print (f' { bench_status } (benchmark will be skipped)' )
122
118
print ()
123
119
venv = None
120
+ print (f'{ bench_status } done' )
121
+ return (bench , venv_root , venv , bench_runid , stdout .getvalue ())
122
+
123
+ def run_benchmarks (should_run , python , options ):
124
+ if options .same_loops is not None :
125
+ loops = get_loops_from_file (options .same_loops )
126
+ else :
127
+ loops = {}
128
+
129
+ to_run = sorted (should_run )
130
+ benchmarks = {}
131
+ venvs = set ()
132
+
133
+ # Setup a first venv on its own first to create common
134
+ # requirements without threading issues.
135
+ bench , venv_root , venv , bench_runid , cons_output = setup_single_venv ((0 , len (to_run ), python , options , to_run [0 ]))
136
+ if venv_root is not None :
124
137
venvs .add (venv_root )
125
- benchmarks [bench ] = (venv , bench_runid )
126
- print ()
138
+ benchmarks [bench ] = (venv , bench_runid )
139
+ print (cons_output )
140
+
141
+ # Parallelise the rest.
142
+ executor_input = [(i + 1 , len (to_run ), python , options , bench )
143
+ for i , bench in enumerate (to_run [1 :])]
144
+ # It's fine to set a higher worker count, because this is IO-bound anyways.
145
+ with concurrent .futures .ProcessPoolExecutor (max_workers = len (to_run )- 1 ) as executor :
146
+ for bench , venv_root , venv , bench_runid , cons_output in executor .map (setup_single_venv , executor_input ):
147
+ if venv_root is not None :
148
+ venvs .add (venv_root )
149
+ benchmarks [bench ] = (venv , bench_runid )
150
+ print (cons_output )
151
+
152
+ print ("Completed venv installation. Now sleeping 15s to stabilize thermals." )
153
+ time .sleep (15 )
127
154
128
155
suite = None
129
156
run_count = str (len (to_run ))
0 commit comments