[PATCH] locale: Optimize tst-localedef-path-norm

Mark Wielaard mark@klomp.org
Tue Jul 19 19:43:28 GMT 2022


Hi Adhemerval,

On Tue, Jul 19, 2022 at 11:01:13AM -0300, Adhemerval Zanella wrote:
> The locale generation are issues in parallel to try speed locale
> generation.  The maximum number of jobs are limited to the online
> CPU (in hope to not overcommit on environments with lower cores
> than tests).
> 
> On a Ryzen 9, the test execution improves from ~6.7s to ~1.4s.

Very nice, on the glibc-fedora-arm64 builder it went from:

real	0m45.440s
user	0m43.361s
sys	0m2.020s

to:

real	0m10.865s
user	0m45.975s
sys	0m1.777s

Tested-by: Mark Wielaard <mark@klomp.org>

I am not sure I qualify as reviewer given how little experience I have
with glibc tests, but here goes:

> diff --git a/locale/Makefile b/locale/Makefile
> index c315683b3f..eb55750496 100644
> --- a/locale/Makefile
> +++ b/locale/Makefile
> @@ -116,3 +116,5 @@ include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
>  $(objpfx)tst-locale-locpath.out : tst-locale-locpath.sh $(objpfx)locale
>  	$(SHELL) $< '$(common-objpfx)' '$(test-wrapper-env)' '$(run-program-env)' > $@; \
>  	$(evaluate-test)
> +
> +$(objpfx)tst-localedef-path-norm: $(shared-thread-library)

OK, we are using pthreads now.

> diff --git a/locale/tst-localedef-path-norm.c b/locale/tst-localedef-path-norm.c
> index 68995a415d..97cc1cc396 100644
> --- a/locale/tst-localedef-path-norm.c
> +++ b/locale/tst-localedef-path-norm.c
> @@ -29,6 +29,7 @@
>     present, regardless of verbosity.  POSIX requires that any warnings cause the
>     exit status to be non-zero.  */
>  
> +#include <array_length.h>
>  #include <sys/types.h>
>  #include <sys/stat.h>
>  #include <unistd.h>
> @@ -37,9 +38,10 @@
>  #include <support/check.h>
>  #include <support/support.h>
>  #include <support/xunistd.h>
> +#include <support/xthread.h>
>  
>  /* Full path to localedef.  */
> -char *prog;
> +static const char *prog;

Not a required change, but obvious better.
prog is assigned once at the start of do_test.

>  /* Execute localedef in a subprocess.  */
>  static void
> @@ -63,12 +65,13 @@ struct test_closure
>  
>  /* Run localedef with DATA.ARGV arguments (NULL terminated), and expect path to
>     the compiled locale is "DATA.COMPLOCALEDIR/DATA.EXP".  */
> -static void
> -run_test (struct test_closure data)
> +static void *
> +run_test (void *closure)
>  {
> -  const char * const *args = data.argv;
> -  const char *exp = data.exp;
> -  const char *complocaledir = data.complocaledir;
> +  struct test_closure *data = closure;
> +  const char * const *args = data->argv;
> +  const char *exp = data->exp;
> +  const char *complocaledir = data->complocaledir;
>    struct stat64 fs;

OK, signature change so run_test can be used with pthread_create.
Variables now come through void * -> struct test_closure * instead of
struct passed by value.

>    /* Expected output path.  */
> @@ -82,8 +85,14 @@ run_test (struct test_closure data)
>  
>    /* Verify path is present and is a directory.  */
>    xstat (path, &fs);
> -  TEST_VERIFY_EXIT (S_ISDIR (fs.st_mode));
> -  printf ("info: Directory '%s' exists.\n", path);
> +  if (!S_ISDIR (fs.st_mode))
> +    {
> +      support_record_failure ();
> +      printf ("error: Directory '%s' does not exist.\n", path);
> +      return (void *) -1ULL;
> +    }
> +
> +  return NULL;
>  }

pthread function should return a void *.
Will later be checked to call TEST_VERIFY_EXIT in main thread.
Is this to avoid exit () race conditions?

support_record_failure is for reporting issues through support_test_main?

>  static int
> @@ -99,139 +108,145 @@ do_test (void)
>  #define ABSDIR "/output"
>    xmkdirp (ABSDIR, 0777);
>  
> -  /* It takes ~10 seconds to serially execute 9 localedef test.  We
> -     could run the compilations in parallel if we want to reduce test
> -     time.  We don't want to split this out into distinct tests because
> -     it would require multiple chroots.  Batching the same localedef
> -     tests saves disk space during testing.  */
> +  /* It takes ~10 seconds to serially execute 9 localedef test.  We run the
> +     compilations in parallel to reduce test time.  We don't want to split
> +     this out into distinct tests because it would require multiple chroots.
> +     Batching the same localedef tests saves disk space during testing.  */
>  
> +  struct test_closure tests[] =
> +  {
>    /* Test 1: Expected normalization.
>       Run localedef and expect output in $(complocaledir)/en_US1.utf8,
>       with normalization changing UTF-8 to utf8.  */
> -  run_test ((struct test_closure)
> -	    {
> -	      .argv = { prog,
> -			"--no-archive",
> -			"-i", "en_US",
> -			"-f", "UTF-8",
> -			"en_US1.UTF-8", NULL },
> -	      .exp = "en_US1.utf8",
> -	      .complocaledir = support_complocaledir_prefix
> -	    });
> -
> +    {
> +      .argv = { (const char *const) prog,
> +		"--no-archive",
> +		"-i", "en_US",
> +		"-f", "UTF-8",
> +		"en_US1.UTF-8", NULL },
> +      .exp = "en_US1.utf8",
> +      .complocaledir = support_complocaledir_prefix
> +    },

OK array of struct test_closure instead of calling run_runtest
directly on each struct. Idem for Test 2 .. Test 9

> +  /* Do not run more threads than the maximum of online CPUs.  */
> +  size_t ntests = array_length (tests);
> +  long int cpus = sysconf (_SC_NPROCESSORS_ONLN);
> +  cpus = cpus == -1 ? 1 : cpus;
> +  printf ("info: cpus=%ld ntests=%zu\n", cpus, ntests);
> +
> +  pthread_t thr[ntests];
> +
> +  for (int i = 0; i < ntests; i += cpus)
> +    {
> +      int max = i + cpus;
> +      if (max > ntests)
> +	max = ntests;
> +
> +      for (int j = i; j < max; j++)
> +	thr[j] = xpthread_create (NULL, run_test, &tests[j]);
> +
> +      for (int j = i; j < max; j++)
> +	TEST_VERIFY_EXIT (xpthread_join (thr[j]) == NULL);
> +    }

Nice pthread loop. We really only need thr[max] inside the loop, but
thr[ntests] makes things simpler to understand (also it is only 9
tests anyway, so who cares).

TEST_VERIFY_EXIT will call exit if the run_test returns (void *)-1.

Cheers,

Mark


More information about the Libc-alpha mailing list