From a0a404a43117d99d962b4dbbf03b76a7b2f04fe3 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Tue, 10 Sep 2024 01:59:46 -0700 Subject: [PATCH] Fix issues with previous commit --- libc/calls/getrandom.c | 23 +++++--- libc/intrin/rand64.c | 2 +- libc/proc/fork.c | 2 +- libc/testlib/benchmark.h | 85 +++++++++++++++++++++++------ libc/thread/thread.h | 3 + test/libc/intrin/memset_test.c | 37 ++----------- test/libc/stdio/lemur64_test.c | 24 ++++++++ tool/viz/clock_nanosleep_accuracy.c | 3 +- 8 files changed, 122 insertions(+), 57 deletions(-) diff --git a/libc/calls/getrandom.c b/libc/calls/getrandom.c index 2b16815d4..9bb079c77 100644 --- a/libc/calls/getrandom.c +++ b/libc/calls/getrandom.c @@ -86,19 +86,28 @@ static ssize_t GetRandomBsd(char *p, size_t n, void impl(char *, size_t)) { } } -static ssize_t GetDevUrandom(char *p, size_t n) { +static ssize_t GetDevUrandom(char *p, size_t n, unsigned f) { int fd; + int oflags; ssize_t rc; - BLOCK_SIGNALS; - BLOCK_CANCELATION; - fd = sys_openat(AT_FDCWD, "/dev/urandom", O_RDONLY | O_CLOEXEC, 0); + const char *dev; + BEGIN_CANCELATION_POINT; + if (f & GRND_RANDOM) { + dev = "/dev/random"; + } else { + dev = "/dev/urandom"; + } + oflags = O_RDONLY | O_CLOEXEC; + if (f & GRND_NONBLOCK) + oflags |= O_NONBLOCK; + fd = sys_openat(AT_FDCWD, dev, oflags, 0); if (fd != -1) { rc = sys_read(fd, p, n); + sys_close(fd); } else { rc = -1; } - ALLOW_CANCELATION; - ALLOW_SIGNALS; + END_CANCELATION_POINT; return rc; } @@ -122,7 +131,7 @@ ssize_t __getrandom(void *p, size_t n, unsigned f) { #endif } else { BEGIN_CANCELATION_POINT; - rc = GetDevUrandom(p, n); + rc = GetDevUrandom(p, n, f); END_CANCELATION_POINT; } return rc; diff --git a/libc/intrin/rand64.c b/libc/intrin/rand64.c index 73308daa2..e6aa1fd20 100644 --- a/libc/intrin/rand64.c +++ b/libc/intrin/rand64.c @@ -27,7 +27,7 @@ static int _rand64_pid; static unsigned __int128 _rand64_pool; -pthread_mutex_t _rand64_lock_obj = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +pthread_mutex_t _rand64_lock_obj = PTHREAD_SIGNAL_SAFE_MUTEX_INITIALIZER_NP; /** * Returns nondeterministic random data. diff --git a/libc/proc/fork.c b/libc/proc/fork.c index e201e712e..bd0201517 100644 --- a/libc/proc/fork.c +++ b/libc/proc/fork.c @@ -85,7 +85,7 @@ static void _onfork_child(void) { if (IsWindows()) __proc_wipe(); __fds_lock_obj = (pthread_mutex_t)PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; - _rand64_lock_obj = (pthread_mutex_t)PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + _rand64_lock_obj = (pthread_mutex_t)PTHREAD_SIGNAL_SAFE_MUTEX_INITIALIZER_NP; _pthread_lock_obj = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER; atomic_store_explicit(&__maps.lock, 0, memory_order_relaxed); if (_weaken(_pthread_onfork_child)) diff --git a/libc/testlib/benchmark.h b/libc/testlib/benchmark.h index aef83f17d..0cc9c3e63 100644 --- a/libc/testlib/benchmark.h +++ b/libc/testlib/benchmark.h @@ -4,23 +4,76 @@ #include "libc/stdio/stdio.h" COSMOPOLITAN_C_START_ -#define BENCHMARK(ITERATIONS, WORK_PER_RUN, CODE) \ - do { \ - struct timespec start = timespec_mono(); \ - for (int __i = 0; __i < ITERATIONS; ++__i) { \ - asm volatile("" ::: "memory"); \ - CODE; \ - } \ - long long work = ((WORK_PER_RUN) ? (WORK_PER_RUN) : 1) * (ITERATIONS); \ - double nanos = \ - (timespec_tonanos(timespec_sub(timespec_mono(), start)) + work - 1) / \ - (double)work; \ - if (nanos < 1000) { \ - printf("%10g ns %2dx %s\n", nanos, (ITERATIONS), #CODE); \ - } else { \ - printf("%10lld ns %2dx %s\n", (long long)nanos, (ITERATIONS), #CODE); \ - } \ +#define X(x) __expropriate(x) +#define V(x) __veil("r", x) + +#define BENCHMARK(ITERATIONS, WORK_PER_RUN, CODE) \ + do { \ + struct timespec start = timespec_mono(); \ + for (int __i = 0; __i < ITERATIONS; ++__i) { \ + asm volatile("" ::: "memory"); \ + CODE; \ + } \ + double total_nanos = \ + (double)timespec_tonanos(timespec_sub(timespec_mono(), start)); \ + double total_work = \ + (double)((WORK_PER_RUN) ? (WORK_PER_RUN) : 1) * (ITERATIONS); \ + _print_benchmark_result(total_nanos, total_work, ITERATIONS, #CODE); \ } while (0) +static void _print_benchmark_result(double total_nanos, double total_work, + int iterations, const char* code) { + double time_per_op = total_nanos / iterations; + double throughput = total_work / (total_nanos * 1e-9); + const char* throughput_unit; + const char* time_unit; + double time_value; + + // Determine throughput unit + if (throughput >= 1e9) { + throughput /= 1e9; + throughput_unit = "G"; + } else if (throughput >= 1e6) { + throughput /= 1e6; + throughput_unit = "M"; + } else if (throughput >= 1e3) { + throughput /= 1e3; + throughput_unit = "K"; + } else { + throughput_unit = " "; + } + + // Determine time unit + if (time_per_op >= 1e6) { + time_value = time_per_op / 1e6; + time_unit = "ms"; + } else if (time_per_op >= 1e3) { + time_value = time_per_op / 1e3; + time_unit = "µs"; + } else { + time_value = time_per_op; + time_unit = "ns"; + } + + // Determine work unit + const char* work_unit; + double work_value = total_work / iterations; + if (work_value >= 1e9) { + work_value /= 1e9; + work_unit = "G"; + } else if (work_value >= 1e6) { + work_value /= 1e6; + work_unit = "M"; + } else if (work_value >= 1e3) { + work_value /= 1e3; + work_unit = "K"; + } else { + work_unit = " "; + } + + printf("%8.2f %-2s %6.2f %s/s %6.2f %s %2dx %s\n", time_value, time_unit, + throughput, throughput_unit, work_value, work_unit, iterations, code); +} + COSMOPOLITAN_C_END_ #endif /* COSMOPOLITAN_LIBC_TESTLIB_BENCHMARK_H_ */ diff --git a/libc/thread/thread.h b/libc/thread/thread.h index 4418bb3cd..4f4cd3eb4 100644 --- a/libc/thread/thread.h +++ b/libc/thread/thread.h @@ -47,6 +47,9 @@ COSMOPOLITAN_C_START_ #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP {0, {}, PTHREAD_MUTEX_RECURSIVE} +#define PTHREAD_SIGNAL_SAFE_MUTEX_INITIALIZER_NP \ + {0, {}, PTHREAD_MUTEX_RECURSIVE | PTHREAD_PROCESS_SHARED} + #ifndef __cplusplus #define _PTHREAD_ATOMIC(x) _Atomic(x) #else diff --git a/test/libc/intrin/memset_test.c b/test/libc/intrin/memset_test.c index 4d818845a..f935e8bfa 100644 --- a/test/libc/intrin/memset_test.c +++ b/test/libc/intrin/memset_test.c @@ -21,7 +21,7 @@ #include "libc/mem/mem.h" #include "libc/stdio/rand.h" #include "libc/str/str.h" -#include "libc/testlib/ezbench.h" +#include "libc/testlib/benchmark.h" #include "libc/testlib/testlib.h" static void *golden(void *p, int c, size_t n) { @@ -64,36 +64,11 @@ TEST(bzero, hug) { } } -BENCH(memset, bench) { - int n, max = 8 * 1024 * 1024; - char *volatile p = gc(malloc(max)); - - EZBENCH_N("memset", 0, memset(p, -1, 0)); - for (n = 2; n <= max; n *= 2) { - EZBENCH_N("memset", n - 1, memset(p, -1, n - 1)); - EZBENCH_N("memset", n, memset(p, -1, n)); - } - - EZBENCH_N("memset16", 0, memset16((char16_t *)p, -1, 0)); - for (n = 2; n <= max; n *= 2) { - EZBENCH_N("memset16", n, memset16((char16_t *)p, -1, n / 2)); - } - - EZBENCH_N("bzero", 0, bzero(p, 0)); - for (n = 2; n <= max; n *= 2) { - EZBENCH_N("bzero", n - 1, bzero(p, n - 1)); - EZBENCH_N("bzero", n, bzero(p, n)); - } -} +#define N (256 * 1024 * 1024) BENCH(strlen, bench) { - int n, max = 8 * 1024 * 1024; - char *volatile p = gc(calloc(max + 1, 1)); - EZBENCH_N("strlen", 0, strlen(p)); - for (n = 2; n <= max; n *= 2) { - memset(p, -1, n - 1); - EZBENCH_N("strlen", n - 1, strlen(p)); - p[n - 1] = -1; - EZBENCH_N("strlen", n, strlen(p)); - } + static char A[N]; + memset(A, 2, N); + for (int n = 1; n <= N; n *= 2) + BENCHMARK(100, n, X(memset(V(A), 1, n))); } diff --git a/test/libc/stdio/lemur64_test.c b/test/libc/stdio/lemur64_test.c index fb6af0b2e..f17700398 100644 --- a/test/libc/stdio/lemur64_test.c +++ b/test/libc/stdio/lemur64_test.c @@ -16,10 +16,34 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/stdio/rand.h" +#include "libc/testlib/benchmark.h" #include "libc/testlib/testlib.h" +uint64_t getrandom64(void) { + uint64_t x; + unassert(getrandom(&x, 8, 0) == 8); + return x; +} + +uint64_t getentropy64(void) { + uint64_t x; + unassert(!getentropy(&x, 8)); + return x; +} + TEST(lemur64, test) { EXPECT_EQ(1819718037028923529, lemur64()); EXPECT_EQ(-3120132252617434764, lemur64()); } + +BENCH(lemur64, bench) { + BENCHMARK(10000, 8, X(lemur64())); + BENCHMARK(10000, 4, X(rand())); + BENCHMARK(10000, 8, X(_rand64())); + BENCHMARK(10000, 8, X(rdrand())); + BENCHMARK(10000, 8, X(rdseed())); + BENCHMARK(10000, 8, X(getrandom64())); + BENCHMARK(10000, 8, X(getentropy64())); +} diff --git a/tool/viz/clock_nanosleep_accuracy.c b/tool/viz/clock_nanosleep_accuracy.c index 977fb6ac1..0875ab26f 100644 --- a/tool/viz/clock_nanosleep_accuracy.c +++ b/tool/viz/clock_nanosleep_accuracy.c @@ -19,6 +19,7 @@ #include #include #include +#include "libc/assert.h" #define MAXIMUM 1e9 #define ITERATIONS 10 @@ -45,7 +46,7 @@ void TestSleepRelative(int clock) { if (clock_gettime(clock, &t1)) return; for (int i = 0; i < ITERATIONS; ++i) { - assert(!clock_nanosleep(clock, 0, &wf, 0)); + unassert(!clock_nanosleep(clock, 0, &wf, 0)); } clock_gettime(clock, &t2); long took = timespec_tonanos(timespec_sub(t2, t1)) / ITERATIONS;