locale: Optimize tst-localedef-path-norm

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.

Tested-by: Mark Wielaard <mark@klomp.org>
This commit is contained in:
Adhemerval Zanella 2022-07-19 10:30:34 -03:00
parent ac8047cdf3
commit 6c4ed247bf
2 changed files with 128 additions and 111 deletions

View File

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

View File

@ -29,6 +29,7 @@
present, regardless of verbosity. POSIX requires that any warnings cause the present, regardless of verbosity. POSIX requires that any warnings cause the
exit status to be non-zero. */ exit status to be non-zero. */
#include <array_length.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
@ -37,9 +38,10 @@
#include <support/check.h> #include <support/check.h>
#include <support/support.h> #include <support/support.h>
#include <support/xunistd.h> #include <support/xunistd.h>
#include <support/xthread.h>
/* Full path to localedef. */ /* Full path to localedef. */
char *prog; static const char *prog;
/* Execute localedef in a subprocess. */ /* Execute localedef in a subprocess. */
static void static void
@ -63,12 +65,13 @@ struct test_closure
/* Run localedef with DATA.ARGV arguments (NULL terminated), and expect path to /* Run localedef with DATA.ARGV arguments (NULL terminated), and expect path to
the compiled locale is "DATA.COMPLOCALEDIR/DATA.EXP". */ the compiled locale is "DATA.COMPLOCALEDIR/DATA.EXP". */
static void static void *
run_test (struct test_closure data) run_test (void *closure)
{ {
const char * const *args = data.argv; struct test_closure *data = closure;
const char *exp = data.exp; const char * const *args = data->argv;
const char *complocaledir = data.complocaledir; const char *exp = data->exp;
const char *complocaledir = data->complocaledir;
struct stat64 fs; struct stat64 fs;
/* Expected output path. */ /* Expected output path. */
@ -82,8 +85,14 @@ run_test (struct test_closure data)
/* Verify path is present and is a directory. */ /* Verify path is present and is a directory. */
xstat (path, &fs); xstat (path, &fs);
TEST_VERIFY_EXIT (S_ISDIR (fs.st_mode)); if (!S_ISDIR (fs.st_mode))
printf ("info: Directory '%s' exists.\n", path); {
support_record_failure ();
printf ("error: Directory '%s' does not exist.\n", path);
return (void *) -1ULL;
}
return NULL;
} }
static int static int
@ -99,31 +108,29 @@ do_test (void)
#define ABSDIR "/output" #define ABSDIR "/output"
xmkdirp (ABSDIR, 0777); xmkdirp (ABSDIR, 0777);
/* It takes ~10 seconds to serially execute 9 localedef test. We /* It takes ~10 seconds to serially execute 9 localedef test. We run the
could run the compilations in parallel if we want to reduce test compilations in parallel to reduce test time. We don't want to split
time. We don't want to split this out into distinct tests because this out into distinct tests because it would require multiple chroots.
it would require multiple chroots. Batching the same localedef Batching the same localedef tests saves disk space during testing. */
tests saves disk space during testing. */
struct test_closure tests[] =
{
/* Test 1: Expected normalization. /* Test 1: Expected normalization.
Run localedef and expect output in $(complocaledir)/en_US1.utf8, Run localedef and expect output in $(complocaledir)/en_US1.utf8,
with normalization changing UTF-8 to utf8. */ with normalization changing UTF-8 to utf8. */
run_test ((struct test_closure)
{ {
.argv = { prog, .argv = { (const char *const) prog,
"--no-archive", "--no-archive",
"-i", "en_US", "-i", "en_US",
"-f", "UTF-8", "-f", "UTF-8",
"en_US1.UTF-8", NULL }, "en_US1.UTF-8", NULL },
.exp = "en_US1.utf8", .exp = "en_US1.utf8",
.complocaledir = support_complocaledir_prefix .complocaledir = support_complocaledir_prefix
}); },
/* Test 2: No normalization past '@'. /* Test 2: No normalization past '@'.
Run localedef and expect output in $(complocaledir)/en_US2.utf8@tEsT, Run localedef and expect output in $(complocaledir)/en_US2.utf8@tEsT,
with normalization changing UTF-8@tEsT to utf8@tEsT (everything after with normalization changing UTF-8@tEsT to utf8@tEsT (everything after
@ is untouched). */ @ is untouched). */
run_test ((struct test_closure)
{ {
.argv = { prog, .argv = { prog,
"--no-archive", "--no-archive",
@ -132,13 +139,11 @@ do_test (void)
"en_US2.UTF-8@tEsT", NULL }, "en_US2.UTF-8@tEsT", NULL },
.exp = "en_US2.utf8@tEsT", .exp = "en_US2.utf8@tEsT",
.complocaledir = support_complocaledir_prefix .complocaledir = support_complocaledir_prefix
}); },
/* Test 3: No normalization past '@' despite period. /* Test 3: No normalization past '@' despite period.
Run localedef and expect output in $(complocaledir)/en_US3@tEsT.UTF-8, Run localedef and expect output in $(complocaledir)/en_US3@tEsT.UTF-8,
with normalization changing nothing (everything after @ is untouched) with normalization changing nothing (everything after @ is untouched)
despite there being a period near the end. */ despite there being a period near the end. */
run_test ((struct test_closure)
{ {
.argv = { prog, .argv = { prog,
"--no-archive", "--no-archive",
@ -147,12 +152,10 @@ do_test (void)
"en_US3@tEsT.UTF-8", NULL }, "en_US3@tEsT.UTF-8", NULL },
.exp = "en_US3@tEsT.UTF-8", .exp = "en_US3@tEsT.UTF-8",
.complocaledir = support_complocaledir_prefix .complocaledir = support_complocaledir_prefix
}); },
/* Test 4: Normalize numeric codeset by adding 'iso' prefix. /* Test 4: Normalize numeric codeset by adding 'iso' prefix.
Run localedef and expect output in $(complocaledir)/en_US4.88591, Run localedef and expect output in $(complocaledir)/en_US4.88591,
with normalization changing 88591 to iso88591. */ with normalization changing 88591 to iso88591. */
run_test ((struct test_closure)
{ {
.argv = { prog, .argv = { prog,
"--no-archive", "--no-archive",
@ -161,12 +164,10 @@ do_test (void)
"en_US4.88591", NULL }, "en_US4.88591", NULL },
.exp = "en_US4.iso88591", .exp = "en_US4.iso88591",
.complocaledir = support_complocaledir_prefix .complocaledir = support_complocaledir_prefix
}); },
/* Test 5: Don't add 'iso' prefix if first char is alpha. /* Test 5: Don't add 'iso' prefix if first char is alpha.
Run localedef and expect output in $(complocaledir)/en_US5.a88591, Run localedef and expect output in $(complocaledir)/en_US5.a88591,
with normalization changing nothing. */ with normalization changing nothing. */
run_test ((struct test_closure)
{ {
.argv = { prog, .argv = { prog,
"--no-archive", "--no-archive",
@ -175,12 +176,10 @@ do_test (void)
"en_US5.a88591", NULL }, "en_US5.a88591", NULL },
.exp = "en_US5.a88591", .exp = "en_US5.a88591",
.complocaledir = support_complocaledir_prefix .complocaledir = support_complocaledir_prefix
}); },
/* Test 6: Don't add 'iso' prefix if last char is alpha. /* Test 6: Don't add 'iso' prefix if last char is alpha.
Run localedef and expect output in $(complocaledir)/en_US6.88591a, Run localedef and expect output in $(complocaledir)/en_US6.88591a,
with normalization changing nothing. */ with normalization changing nothing. */
run_test ((struct test_closure)
{ {
.argv = { prog, .argv = { prog,
"--no-archive", "--no-archive",
@ -189,12 +188,10 @@ do_test (void)
"en_US6.88591a", NULL }, "en_US6.88591a", NULL },
.exp = "en_US6.88591a", .exp = "en_US6.88591a",
.complocaledir = support_complocaledir_prefix .complocaledir = support_complocaledir_prefix
}); },
/* Test 7: Don't normalize anything with an absolute path. /* Test 7: Don't normalize anything with an absolute path.
Run localedef and expect output in ABSDIR/en_US7.UTF-8, Run localedef and expect output in ABSDIR/en_US7.UTF-8,
with normalization changing nothing. */ with normalization changing nothing. */
run_test ((struct test_closure)
{ {
.argv = { prog, .argv = { prog,
"--no-archive", "--no-archive",
@ -203,12 +200,10 @@ do_test (void)
ABSDIR "/en_US7.UTF-8", NULL }, ABSDIR "/en_US7.UTF-8", NULL },
.exp = "en_US7.UTF-8", .exp = "en_US7.UTF-8",
.complocaledir = ABSDIR .complocaledir = ABSDIR
}); },
/* Test 8: Don't normalize anything with an absolute path. /* Test 8: Don't normalize anything with an absolute path.
Run localedef and expect output in ABSDIR/en_US8.UTF-8@tEsT, Run localedef and expect output in ABSDIR/en_US8.UTF-8@tEsT,
with normalization changing nothing. */ with normalization changing nothing. */
run_test ((struct test_closure)
{ {
.argv = { prog, .argv = { prog,
"--no-archive", "--no-archive",
@ -217,12 +212,10 @@ do_test (void)
ABSDIR "/en_US8.UTF-8@tEsT", NULL }, ABSDIR "/en_US8.UTF-8@tEsT", NULL },
.exp = "en_US8.UTF-8@tEsT", .exp = "en_US8.UTF-8@tEsT",
.complocaledir = ABSDIR .complocaledir = ABSDIR
}); },
/* Test 9: Don't normalize anything with an absolute path. /* Test 9: Don't normalize anything with an absolute path.
Run localedef and expect output in ABSDIR/en_US9@tEsT.UTF-8, Run localedef and expect output in ABSDIR/en_US9@tEsT.UTF-8,
with normalization changing nothing. */ with normalization changing nothing. */
run_test ((struct test_closure)
{ {
.argv = { prog, .argv = { prog,
"--no-archive", "--no-archive",
@ -231,7 +224,29 @@ do_test (void)
ABSDIR "/en_US9@tEsT.UTF-8", NULL }, ABSDIR "/en_US9@tEsT.UTF-8", NULL },
.exp = "en_US9@tEsT.UTF-8", .exp = "en_US9@tEsT.UTF-8",
.complocaledir = ABSDIR .complocaledir = ABSDIR
}); }
};
/* 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 (xpthread_join (thr[j]) == NULL);
}
return 0; return 0;
} }