@@ -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