@@ -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,13 +235,9 @@ 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}
@@ -222,7 +250,7 @@ static int run_concurrent(struct tf_framework* tf) {
222250 int pipefd [2 ];
223251 int status = EXIT_SUCCESS ;
224252 int it ; /* loop iterator */
225- tf_test_ref ref ; /* test index */
253+ unsigned char idx ; /* test index */
226254
227255 if (pipe (pipefd ) != 0 ) {
228256 perror ("Error during pipe setup" );
@@ -239,8 +267,8 @@ static int run_concurrent(struct tf_framework* tf) {
239267 if (pid == 0 ) {
240268 /* Child worker: read jobs from the shared pipe */
241269 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 ]);
270+ while (read (pipefd [0 ], & idx , sizeof (idx )) == sizeof (idx )) {
271+ run_test (tf -> args . targets . slots [( int ) idx ]);
244272 }
245273 _exit (EXIT_SUCCESS ); /* finish child process */
246274 } else {
@@ -251,14 +279,12 @@ static int run_concurrent(struct tf_framework* tf) {
251279
252280 /* Parent: write all tasks into the pipe */
253281 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- }
282+ for (it = 0 ; it < tf -> args .targets .size ; it ++ ) {
283+ idx = (unsigned char )it ;
284+ if (write (pipefd [1 ], & idx , sizeof (idx )) == -1 ) {
285+ perror ("Error during workload distribution" );
286+ close (pipefd [1 ]);
287+ return EXIT_FAILURE ;
262288 }
263289 }
264290 /* Close write end to signal EOF */
@@ -287,6 +313,7 @@ static int tf_init(struct tf_framework* tf, int argc, char** argv)
287313 tf -> args .num_processes = 0 ;
288314 tf -> args .custom_seed = NULL ;
289315 tf -> args .help = 0 ;
316+ tf -> args .targets .size = 0 ;
290317
291318 /* Disable buffering for stdout to improve reliability of getting
292319 * diagnostic information. Happens right at the start of main because
@@ -331,19 +358,40 @@ static int tf_init(struct tf_framework* tf, int argc, char** argv)
331358static int tf_run (struct tf_framework * tf ) {
332359 /* Process exit status */
333360 int status ;
361+ /* Whether to run all tests */
362+ int run_all ;
334363 /* Loop iterator */
335364 int it ;
336365 /* Initial test time */
337366 int64_t start_time = gettime_i64 ();
338367
368+ /* Populate targets with all tests if none were explicitly specified */
369+ run_all = tf -> args .targets .size == 0 ;
370+ if (run_all ) {
371+ int group , idx ;
372+ for (group = 0 ; group < tf -> num_modules ; group ++ ) {
373+ const struct tf_test_module * module = & tf -> registry_modules [group ];
374+ for (idx = 0 ; idx < module -> size ; idx ++ ) {
375+ if (tf -> args .targets .size >= MAX_ARGS ) {
376+ fprintf (stderr , "Internal Error: Number of tests (%d) exceeds MAX_ARGS (%d). "
377+ "Increase MAX_ARGS to accommodate all tests.\n" , tf -> args .targets .size , MAX_ARGS );
378+ return EXIT_FAILURE ;
379+ }
380+ tf -> args .targets .slots [tf -> args .targets .size ++ ] = & module -> data [idx ];
381+ }
382+ }
383+ }
384+
339385 /* Log configuration */
340386 print_args (& tf -> args );
341387
342388 /* Run test RNG tests (must run before we really initialize the test RNG) */
343389 /* Note: currently, these tests are executed sequentially because there */
344390 /* is really only one test. */
345391 for (it = 0 ; tf -> registry_no_rng && it < tf -> registry_no_rng -> size ; it ++ ) {
346- run_test (& tf -> registry_no_rng -> data [it ]);
392+ if (run_all ) { /* future: support filtering */
393+ run_test (& tf -> registry_no_rng -> data [it ]);
394+ }
347395 }
348396
349397 /* Initialize test RNG and library contexts */
0 commit comments