@@ -25,6 +25,7 @@ int COUNT = 16;
2525static  int  parse_jobs_count (const  char *  key , const  char *  value , struct  tf_framework *  tf );
2626static  int  parse_iterations (const  char *  key , const  char *  value , struct  tf_framework *  tf );
2727static  int  parse_seed (const  char *  key , const  char *  value , struct  tf_framework *  tf );
28+ static  int  parse_target (const  char *  key , const  char *  value , struct  tf_framework *  tf );
2829
2930/* Mapping table: key -> handler */ 
3031typedef  int  (* ArgHandler )(const  char *  key , const  char *  value , struct  tf_framework *  tf );
@@ -41,6 +42,7 @@ struct ArgMap {
4142 *   converted to the appropriate type, and stored in 'tf->args' struct. 
4243 */ 
4344static  struct  ArgMap  arg_map [] =  {
45+     { "t" , parse_target  }, { "target" , parse_target  },
4446    { "j" , parse_jobs_count  }, { "jobs" , parse_jobs_count  },
4547    { "i" , parse_iterations  }, { "iterations" , parse_iterations  },
4648    { "seed" , parse_seed  },
@@ -82,6 +84,8 @@ static void help(void) {
8284    printf ("    --jobs=<num>, -j=<num>               Number of parallel worker processes (default: 0 = sequential)\n" );
8385    printf ("    --iterations=<num>, -i=<num>         Number of iterations for each test (default: 16)\n" );
8486    printf ("    --seed=<hex>                         Set a specific RNG seed (default: random)\n" );
87+     printf ("    --target=<test name>, -t=<name>      Run a specific test (can be provided multiple times)\n" );
88+     printf ("    --target=<module name>, -t=<module>  Run all tests within a specific module (can be provided multiple times)\n" );
8589    printf ("\n" );
8690    printf ("Notes:\n" );
8791    printf ("    - All arguments must be provided in the form '--key=value', '-key=value' or '-k=value'.\n" );
@@ -152,6 +156,34 @@ static const char* normalize_key(const char* arg, const char** err_msg) {
152156    return  key ;
153157}
154158
159+ static  int  parse_target (const  char *  key , const  char *  value , struct  tf_framework *  tf ) {
160+     int  group , idx ;
161+     const  struct  tf_test_entry *  entry ;
162+     UNUSED (key );
163+     /* Find test index in the registry */ 
164+     for  (group  =  0 ; group  <  tf -> num_modules ; group ++ ) {
165+         const  struct  tf_test_module *  module  =  & tf -> registry_modules [group ];
166+         int  add_all  =  strcmp (value , module -> name ) ==  0 ; /* select all from module */ 
167+         for  (idx  =  0 ; idx  <  module -> size ; idx ++ ) {
168+             entry  =  & module -> data [idx ];
169+             if  (add_all  ||  strcmp (value , entry -> name ) ==  0 ) {
170+                 if  (tf -> args .targets .size  >= MAX_ARGS ) {
171+                     fprintf (stderr , "Too many -target args (max: %d)\n" , MAX_ARGS );
172+                     return  -1 ;
173+                 }
174+                 tf -> args .targets .slots [tf -> args .targets .size ++ ] =  entry ;
175+                 /* Matched a single test, we're done */ 
176+                 if  (!add_all ) return  0 ;
177+             }
178+         }
179+         /* If add_all was true, we added all tests in the module, so return */ 
180+         if  (add_all ) return  0 ;
181+     }
182+     fprintf (stderr , "Error: target '%s' not found (missing or module disabled).\n" 
183+                     "Run program with -print_tests option to display available tests and modules.\n" , value );
184+     return  -1 ;
185+ }
186+ 
155187/* Read args: all must be in the form -key=value, --key=value or -key=value */ 
156188static  int  read_args (int  argc , char * *  argv , int  start , struct  tf_framework *  tf ) {
157189    int  i ;
@@ -203,26 +235,32 @@ static void run_test(const struct tf_test_entry* t) {
203235
204236/* Process tests in sequential order */ 
205237static  int  run_sequential (struct  tf_framework *  tf ) {
206-     tf_test_ref  ref ;
207-     const  struct  tf_test_module *  mdl ;
208-     for  (ref .group  =  0 ; ref .group  <  tf -> num_modules ; ref .group ++ ) {
209-         mdl  =  & tf -> registry_modules [ref .group ];
210-         for  (ref .idx  =  0 ; ref .idx  <  mdl -> size ; ref .idx ++ ) {
211-             run_test (& mdl -> data [ref .idx ]);
212-         }
238+     int  it ;
239+     for  (it  =  0 ; it  <  tf -> args .targets .size ; it ++ ) {
240+         run_test (tf -> args .targets .slots [it ]);
213241    }
214242    return  EXIT_SUCCESS ;
215243}
216244
217245#if  defined(SUPPORTS_CONCURRENCY )
246+ static  const  int  MAX_TARGETS  =  255 ;
247+ 
218248/* Process tests in parallel */ 
219249static  int  run_concurrent (struct  tf_framework *  tf ) {
220250    /* Sub-processes info */ 
221251    pid_t  workers [MAX_SUBPROCESSES ];
222252    int  pipefd [2 ];
223253    int  status  =  EXIT_SUCCESS ;
224254    int  it ; /* loop iterator */ 
225-     tf_test_ref  ref ; /* test index */ 
255+     unsigned char   idx ; /* test index */ 
256+ 
257+     if  (tf -> args .targets .size  >  MAX_TARGETS ) {
258+         fprintf (stderr , "Internal Error: the number of targets (%d) exceeds the maximum supported (%d). " 
259+                 "If you need more, extend 'run_concurrent()' to handle additional targets.\n" ,
260+                 tf -> args .targets .size , MAX_TARGETS );
261+         exit (EXIT_FAILURE );
262+     }
263+ 
226264
227265    if  (pipe (pipefd ) !=  0 ) {
228266        perror ("Error during pipe setup" );
@@ -239,8 +277,8 @@ static int run_concurrent(struct tf_framework* tf) {
239277        if  (pid  ==  0 ) {
240278            /* Child worker: read jobs from the shared pipe */ 
241279            close (pipefd [1 ]); /* children never write */ 
242-             while  (read (pipefd [0 ], & ref , sizeof (ref )) ==  sizeof (ref )) {
243-                 run_test (& tf -> registry_modules [ ref . group ]. data [ ref . idx ]);
280+             while  (read (pipefd [0 ], & idx , sizeof (idx )) ==  sizeof (idx )) {
281+                 run_test (tf -> args . targets . slots [( int ) idx ]);
244282            }
245283            _exit (EXIT_SUCCESS ); /* finish child process */ 
246284        } else  {
@@ -251,14 +289,12 @@ static int run_concurrent(struct tf_framework* tf) {
251289
252290    /* Parent: write all tasks into the pipe */ 
253291    close (pipefd [0 ]); /* close read end */ 
254-     for  (ref .group  =  0 ; ref .group  <  tf -> num_modules ; ref .group ++ ) {
255-         const  struct  tf_test_module *  mdl  =  & tf -> registry_modules [ref .group ];
256-         for  (ref .idx  =  0 ; ref .idx  <  mdl -> size ; ref .idx ++ ) {
257-             if  (write (pipefd [1 ], & ref , sizeof (ref )) ==  -1 ) {
258-                 perror ("Error during workload distribution" );
259-                 close (pipefd [1 ]);
260-                 return  EXIT_FAILURE ;
261-             }
292+     for  (it  =  0 ; it  <  tf -> args .targets .size ; it ++ ) {
293+         idx  =  (unsigned char  )it ;
294+         if  (write (pipefd [1 ], & idx , sizeof (idx )) ==  -1 ) {
295+             perror ("Error during workload distribution" );
296+             close (pipefd [1 ]);
297+             return  EXIT_FAILURE ;
262298        }
263299    }
264300    /* Close write end to signal EOF */ 
@@ -287,6 +323,7 @@ static int tf_init(struct tf_framework* tf, int argc, char** argv)
287323    tf -> args .num_processes  =  0 ;
288324    tf -> args .custom_seed  =  NULL ;
289325    tf -> args .help  =  0 ;
326+     tf -> args .targets .size  =  0 ;
290327
291328    /* Disable buffering for stdout to improve reliability of getting 
292329     * diagnostic information. Happens right at the start of main because 
@@ -331,19 +368,40 @@ static int tf_init(struct tf_framework* tf, int argc, char** argv)
331368static  int  tf_run (struct  tf_framework *  tf ) {
332369    /* Process exit status */ 
333370    int  status ;
371+     /* Whether to run all tests */ 
372+     int  run_all ;
334373    /* Loop iterator */ 
335374    int  it ;
336375    /* Initial test time */ 
337376    int64_t  start_time  =  gettime_i64 ();
338377
378+     /* Populate targets with all tests if none were explicitly specified */ 
379+     run_all  =  tf -> args .targets .size  ==  0 ;
380+     if  (run_all ) {
381+         int  group , idx ;
382+         for  (group  =  0 ; group  <  tf -> num_modules ; group ++ ) {
383+             const  struct  tf_test_module *  module  =  & tf -> registry_modules [group ];
384+             for  (idx  =  0 ; idx  <  module -> size ; idx ++ ) {
385+                 if  (tf -> args .targets .size  >= MAX_ARGS ) {
386+                     fprintf (stderr , "Internal Error: Number of tests (%d) exceeds MAX_ARGS (%d). " 
387+                                     "Increase MAX_ARGS to accommodate all tests.\n" , tf -> args .targets .size , MAX_ARGS );
388+                     return  EXIT_FAILURE ;
389+                 }
390+                 tf -> args .targets .slots [tf -> args .targets .size ++ ] =  & module -> data [idx ];
391+             }
392+         }
393+     }
394+ 
339395    /* Log configuration */ 
340396    print_args (& tf -> args );
341397
342398    /* Run test RNG tests (must run before we really initialize the test RNG) */ 
343399    /* Note: currently, these tests are executed sequentially because there */ 
344400    /* is really only one test. */ 
345401    for  (it  =  0 ; tf -> registry_no_rng  &&  it  <  tf -> registry_no_rng -> size ; it ++ ) {
346-         run_test (& tf -> registry_no_rng -> data [it ]);
402+         if  (run_all ) { /* future: support filtering */ 
403+             run_test (& tf -> registry_no_rng -> data [it ]);
404+         }
347405    }
348406
349407    /* Initialize test RNG and library contexts */ 
0 commit comments