@@ -5,6 +5,7 @@ use crate::run::runner::interfaces::RunData;
55use crate :: run:: runner:: valgrind:: executor:: ValgrindExecutor ;
66use crate :: run:: { RunnerMode , runner:: wall_time:: executor:: WallTimeExecutor } ;
77use tempfile:: TempDir ;
8+ use tokio:: sync:: { OnceCell , Semaphore , SemaphorePermit } ;
89
910const SIMPLE_ECHO_SCRIPT : & str = "echo 'Hello, World!'" ;
1011const MULTILINE_ECHO_SCRIPT : & str = "echo \" Working\"
@@ -25,6 +26,41 @@ if [ \"$output\" != \"Hello\" ]; then
2526 exit 1
2627fi" ;
2728
29+ async fn get_valgrind_executor ( ) -> & ' static ValgrindExecutor {
30+ static VALGRIND_EXECUTOR : OnceCell < ValgrindExecutor > = OnceCell :: const_new ( ) ;
31+
32+ VALGRIND_EXECUTOR
33+ . get_or_init ( || async {
34+ let executor = ValgrindExecutor ;
35+ let system_info = SystemInfo :: new ( ) . unwrap ( ) ;
36+ executor. setup ( & system_info) . await . unwrap ( ) ;
37+ executor
38+ } )
39+ . await
40+ }
41+
42+ async fn get_walltime_executor ( ) -> ( SemaphorePermit < ' static > , WallTimeExecutor ) {
43+ static WALLTIME_INIT : OnceCell < ( ) > = OnceCell :: const_new ( ) ;
44+ static WALLTIME_SEMAPHORE : OnceCell < Semaphore > = OnceCell :: const_new ( ) ;
45+
46+ WALLTIME_INIT
47+ . get_or_init ( || async {
48+ let executor = WallTimeExecutor :: new ( ) ;
49+ let system_info = SystemInfo :: new ( ) . unwrap ( ) ;
50+ executor. setup ( & system_info) . await . unwrap ( ) ;
51+ } )
52+ . await ;
53+
54+ // We can't execute multiple walltime executors in parallel because perf isn't thread-safe (yet). We have to
55+ // use a semaphore to limit concurrent access.
56+ let semaphore = WALLTIME_SEMAPHORE
57+ . get_or_init ( || async { Semaphore :: new ( 1 ) } )
58+ . await ;
59+ let permit = semaphore. acquire ( ) . await . unwrap ( ) ;
60+
61+ ( permit, WallTimeExecutor :: new ( ) )
62+ }
63+
2864async fn create_test_setup ( ) -> ( SystemInfo , RunData , TempDir ) {
2965 let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
3066
@@ -44,9 +80,7 @@ async fn create_test_setup() -> (SystemInfo, RunData, TempDir) {
4480#[ tokio:: test]
4581async fn test_valgrind_executor ( #[ case] cmd : & str ) {
4682 let ( system_info, run_data, _temp_dir) = create_test_setup ( ) . await ;
47-
48- let executor = ValgrindExecutor ;
49- executor. setup ( & system_info) . await . unwrap ( ) ;
83+ let executor = get_valgrind_executor ( ) . await ;
5084
5185 eprintln ! ( "Running command: {cmd}" ) ;
5286
@@ -78,9 +112,8 @@ async fn test_valgrind_executor(#[case] cmd: &str) {
78112#[ tokio:: test]
79113async fn test_walltime_executor ( #[ case] cmd : & str , #[ case] enable_perf : bool ) {
80114 let ( system_info, run_data, _temp_dir) = create_test_setup ( ) . await ;
81-
82- let executor = WallTimeExecutor :: new ( ) ;
83- executor. setup ( & system_info) . await . unwrap ( ) ;
115+ let ( _permit, executor) = get_walltime_executor ( ) . await ;
116+ let executor = executor;
84117
85118 eprintln ! ( "Running command: {cmd}" ) ;
86119
@@ -108,9 +141,7 @@ async fn test_valgrind_executor_with_env(
108141 #[ case] cmd : & str ,
109142) {
110143 let ( system_info, run_data, _temp_dir) = create_test_setup ( ) . await ;
111-
112- let executor = ValgrindExecutor ;
113- executor. setup ( & system_info) . await . unwrap ( ) ;
144+ let executor = get_valgrind_executor ( ) . await ;
114145
115146 let config = Config {
116147 mode : RunnerMode :: Instrumentation ,
@@ -140,9 +171,8 @@ async fn test_walltime_executor_with_env(
140171 #[ case] enable_perf : bool ,
141172) {
142173 let ( system_info, run_data, _temp_dir) = create_test_setup ( ) . await ;
143-
144- let executor = WallTimeExecutor :: new ( ) ;
145- executor. setup ( & system_info) . await . unwrap ( ) ;
174+ let ( _permit, executor) = get_walltime_executor ( ) . await ;
175+ let executor = executor;
146176
147177 let config = Config {
148178 mode : RunnerMode :: Walltime ,
0 commit comments