44import sys
55import time
66import traceback
7+ import concurrent .futures
8+ import io
9+ import contextlib
710
811import pyperformance
912from . import _utils , _python , _pythoninfo
@@ -67,47 +70,40 @@ def get_loops_from_file(filename):
6770 return loops
6871
6972
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
7775
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 )
8080
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+ )
9389 bench_runid = runid ._replace (bench = bench )
9490 assert bench_runid .name , (bench , bench_runid )
9591 name = bench_runid .name
9692 venv_root = _venv .get_venv_root (name , python = info )
93+ bench_status = f'({ i + 1 :>2} /{ num_benchmarks } )'
9794 print ()
9895 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 } )' )
10097 print ()
10198 if not unique :
102- print (' (trying common venv first)' )
99+ print (f' { bench_status } (trying common venv first)' )
103100 # Try the common venv first.
104101 try :
105102 common .ensure_reqs (bench )
106103 except _venv .RequirementsInstallationFailedError :
107- print (' (falling back to unique venv)' )
104+ print (f' { bench_status } (falling back to unique venv)' )
108105 else :
109- benchmarks [bench ] = (common , bench_runid )
110- continue
106+ return (bench , None , common , bench_runid , stdout .getvalue ())
111107 try :
112108 venv = VenvForBenchmarks .ensure (
113109 venv_root ,
@@ -118,12 +114,43 @@ def run_benchmarks(should_run, python, options):
118114 # XXX Do not override when there is a requirements collision.
119115 venv .ensure_reqs (bench )
120116 except _venv .RequirementsInstallationFailedError :
121- print (' (benchmark will be skipped)' )
117+ print (f' { bench_status } (benchmark will be skipped)' )
122118 print ()
123119 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 :
124137 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 )
127154
128155 suite = None
129156 run_count = str (len (to_run ))
0 commit comments