@@ -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,32 @@ 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+ TestRef i = {/*group=*/ 0 , /*idx=*/ 0 };
161+ UNUSED (key );
162+ /* Find test index in the registry */
163+ for (i .group = 0 ; i .group < tf -> num_modules ; i .group ++ ) {
164+ const struct tf_test_module * module = & tf -> registry_modules [i .group ];
165+ int add_all = strcmp (value , module -> name ) == 0 ; /* select all from module */
166+ for (i .idx = 0 ; i .idx < module -> size ; i .idx ++ ) {
167+ if (add_all || strcmp (value , module -> data [i .idx ].name ) == 0 ) {
168+ if (tf -> args .targets .size >= MAX_ARGS ) {
169+ fprintf (stderr , "Too many -target args (max: %d)\n" , MAX_ARGS );
170+ return -1 ;
171+ }
172+ tf -> args .targets .slots [tf -> args .targets .size ++ ] = i ;
173+ /* Matched a single test, we're done */
174+ if (!add_all ) return 0 ;
175+ }
176+ }
177+ /* If add_all was true, we added all tests in the module, so return */
178+ if (add_all ) return 0 ;
179+ }
180+ fprintf (stderr , "Error: target '%s' not found (missing or module disabled).\n"
181+ "Run program with -print_tests option to display available tests and modules.\n" , value );
182+ return -1 ;
183+ }
184+
155185/* Read args: all must be in the form -key=value, --key=value or -key=value */
156186static int read_args (int argc , char * * argv , int start , struct tf_framework * tf ) {
157187 int i ;
@@ -203,13 +233,10 @@ static void run_test(const struct tf_test_entry* t) {
203233
204234/* Process tests in sequential order */
205235static int run_sequential (struct tf_framework * tf ) {
206- TestRef 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- }
236+ int it ;
237+ for (it = 0 ; it < tf -> args .targets .size ; it ++ ) {
238+ const TestRef * index = & tf -> args .targets .slots [it ];
239+ run_test (& tf -> registry_modules [index -> group ].data [index -> idx ]);
213240 }
214241 return EXIT_SUCCESS ;
215242}
@@ -227,7 +254,7 @@ static int run_concurrent(struct tf_framework* tf) {
227254 /* Loop iterator */
228255 int it ;
229256 /* Loop ref */
230- TestRef ref ;
257+ TestRef * ref ;
231258 /* Launch worker processes */
232259 for (it = 0 ; it < tf -> args .num_processes ; it ++ ) {
233260 pid_t pid ;
@@ -244,9 +271,10 @@ static int run_concurrent(struct tf_framework* tf) {
244271
245272 if (pid == 0 ) {
246273 /* Child worker: run tests assigned via pipe */
274+ TestRef tref ;
247275 close (pipes [it ][1 ]); /* Close write end */
248- while (read (pipes [it ][0 ], & ref , sizeof (ref )) == sizeof (ref )) {
249- run_test (& tf -> registry_modules [ref .group ].data [ref .idx ]);
276+ while (read (pipes [it ][0 ], & tref , sizeof (tref )) == sizeof (tref )) {
277+ run_test (& tf -> registry_modules [tref .group ].data [tref .idx ]);
250278 }
251279 _exit (EXIT_SUCCESS ); /* finish child process */
252280 } else {
@@ -258,15 +286,13 @@ static int run_concurrent(struct tf_framework* tf) {
258286
259287 /* Now that we have all sub-processes, distribute workload in round-robin */
260288 worker_idx = 0 ;
261- for (ref .group = 0 ; ref .group < tf -> num_modules ; ref .group ++ ) {
262- const struct tf_test_module * mdl = & tf -> registry_modules [ref .group ];
263- for (ref .idx = 0 ; ref .idx < mdl -> size ; ref .idx ++ ) {
264- if (write (pipes [worker_idx ][1 ], & ref , sizeof (ref )) == -1 ) {
265- perror ("Error during workload distribution" );
266- return EXIT_FAILURE ;
267- }
268- if (++ worker_idx >= tf -> args .num_processes ) worker_idx = 0 ;
289+ for (it = 0 ; it < tf -> args .targets .size ; it ++ ) {
290+ ref = & tf -> args .targets .slots [it ];
291+ if (write (pipes [worker_idx ][1 ], ref , sizeof (* ref )) == -1 ) {
292+ perror ("Error during workload distribution" );
293+ return EXIT_FAILURE ;
269294 }
295+ if (++ worker_idx >= tf -> args .num_processes ) worker_idx = 0 ;
270296 }
271297
272298 /* Close all pipes to signal workers to exit */
@@ -295,6 +321,7 @@ static int tf_init(struct tf_framework* tf, int argc, char** argv)
295321 tf -> args .num_processes = 0 ;
296322 tf -> args .custom_seed = NULL ;
297323 tf -> args .help = 0 ;
324+ tf -> args .targets .size = 0 ;
298325
299326 /* Disable buffering for stdout to improve reliability of getting
300327 * diagnostic information. Happens right at the start of main because
@@ -339,19 +366,40 @@ static int tf_init(struct tf_framework* tf, int argc, char** argv)
339366static int tf_run (struct tf_framework * tf ) {
340367 /* Process exit status */
341368 int status ;
369+ /* Whether to run all tests */
370+ int run_all ;
342371 /* Loop iterator */
343372 int it ;
344373 /* Initial test time */
345374 int64_t start_time = gettime_i64 ();
346375
376+ /* Populate targets with all tests if none were explicitly specified */
377+ run_all = tf -> args .targets .size == 0 ;
378+ if (run_all ) {
379+ TestRef ref ;
380+ for (ref .group = 0 ; ref .group < tf -> num_modules ; ref .group ++ ) {
381+ const struct tf_test_module * group = & tf -> registry_modules [ref .group ];
382+ for (ref .idx = 0 ; ref .idx < group -> size ; ref .idx ++ ) {
383+ if (tf -> args .targets .size >= MAX_ARGS ) {
384+ fprintf (stderr , "Internal Error: Number of tests (%d) exceeds MAX_ARGS (%d). "
385+ "Increase MAX_ARGS to accommodate all tests.\n" , tf -> args .targets .size , MAX_ARGS );
386+ return EXIT_FAILURE ;
387+ }
388+ tf -> args .targets .slots [tf -> args .targets .size ++ ] = ref ;
389+ }
390+ }
391+ }
392+
347393 /* Log configuration */
348394 print_args (& tf -> args );
349395
350396 /* Run test RNG tests (must run before we really initialize the test RNG) */
351397 /* Note: currently, these tests are executed sequentially because there */
352398 /* is really only one test. */
353399 for (it = 0 ; tf -> registry_no_rng && it < tf -> registry_no_rng -> size ; it ++ ) {
354- run_test (& tf -> registry_no_rng -> data [it ]);
400+ if (run_all ) { /* future: support filtering */
401+ run_test (& tf -> registry_no_rng -> data [it ]);
402+ }
355403 }
356404
357405 /* Initialize test RNG and library contexts */
0 commit comments