From e947b47598e0eabdb2bc97b072bf4a4d8f57b3c9 Mon Sep 17 00:00:00 2001 From: KazushiM <85604869+KazushiMe@users.noreply.github.com> Date: Mon, 25 Oct 2021 22:20:36 +0800 Subject: [PATCH] TinyMemBenchNX multi-threads support, but max_threads = 2 ? --- SdOut/switch/TinyMemBenchNX.nro | Bin 293061 -> 297157 bytes Source/Atmosphere/ldr_pcv_patch.cpp | 6 +- Source/TinyMemBenchNX/Makefile | 6 +- Source/TinyMemBenchNX/source/aarch64-asm.h | 6 + Source/TinyMemBenchNX/source/aarch64-asm.s | 24 +- .../source/{main.cpp => main.c} | 335 +++++++++++------- 6 files changed, 239 insertions(+), 138 deletions(-) rename Source/TinyMemBenchNX/source/{main.cpp => main.c} (78%) diff --git a/SdOut/switch/TinyMemBenchNX.nro b/SdOut/switch/TinyMemBenchNX.nro index 2379d0834218067e71fcb18cfd538e77d8fa5d79..774456488a4fe271d4037ff897ff712b08d47de2 100644 GIT binary patch delta 59987 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 #include #include -#include #include +// Multi-thread support +#include +#include +#include + #define __ASM_OPT_H__ #define SIZE (32 * 1024 * 1024) #define BLOCKSIZE 2048 @@ -49,10 +55,79 @@ #include "aarch64-asm.h" #include -using namespace std; - PadState pad; +struct f_data +{ + void (*func)(int64_t *, int64_t *, int); + int64_t *arg1; + int64_t *arg2; + int arg3; +}; + +pthread_cond_t p_ready, p_start; +pthread_mutex_t p_lock; +pthread_t *p_worker = NULL; +struct f_data *worker_data = NULL; +int p_worker_not_ready, p_workers_ready; + +void *thread_func(void *data) +{ + struct f_data *data_ptr = data; + + pthread_mutex_lock(&p_lock); + p_worker_not_ready--; + + if (!p_worker_not_ready) + pthread_cond_signal(&p_ready); + + while (p_workers_ready != 1) + pthread_cond_wait(&p_start, &p_lock); + + pthread_mutex_unlock(&p_lock); + + (data_ptr->func)(data_ptr->arg1, data_ptr->arg2, data_ptr->arg3); + + pthread_exit(NULL); +} + +static void parallel_run(void) +{ + pthread_mutex_lock(&p_lock); + p_workers_ready = 1; + pthread_mutex_unlock(&p_lock); + pthread_cond_broadcast(&p_start); +} + +static void parallel_init(int threads) +{ + pthread_attr_t attr; + + pthread_cond_init(&p_ready, NULL); + pthread_cond_init(&p_start, NULL); + pthread_mutex_init(&p_lock, NULL); + p_worker_not_ready = threads; + p_workers_ready = 0; + pthread_attr_init(&attr); + + if (!p_worker || !worker_data) + { + p_worker = (pthread_t *)malloc(threads * sizeof(pthread_t)); + worker_data = (struct f_data *)malloc(threads * sizeof(struct f_data)); + } + + for (int i = 0; i < threads; i++) + { + pthread_create(p_worker + i, &attr, thread_func, worker_data + i); + } + + pthread_mutex_lock(&p_lock); + while (p_worker_not_ready != 0) + pthread_cond_wait(&p_ready, &p_lock); + + pthread_mutex_unlock(&p_lock); +} + typedef struct { const char *description; @@ -240,6 +315,24 @@ void aligned_block_copy_pf64(int64_t * __restrict dst_, } } +void aligned_block_fetch(int64_t * __restrict dst, + int64_t * __restrict src_, + int size) +{ + volatile int64_t *src = src_; + while ((size -= 64) >= 0) + { + *src++; + *src++; + *src++; + *src++; + *src++; + *src++; + *src++; + *src++; + } +} + void aligned_block_fill(int64_t * __restrict dst_, int64_t * __restrict src, int size) @@ -326,7 +419,8 @@ double gettime(void) return (double)((int64_t)tv.tv_sec * 1000000 + tv.tv_usec) / 1000000.; } -static double bandwidth_bench_helper(int64_t *dstbuf, int64_t *srcbuf, +static double bandwidth_bench_helper(int threads, + int64_t *dstbuf, int64_t *srcbuf, int64_t *tmpbuf, int size, int blocksize, const char *indent_prefix, @@ -335,19 +429,30 @@ static double bandwidth_bench_helper(int64_t *dstbuf, int64_t *srcbuf, const char *description) { int i, j, loopcount, innerloopcount, n; - double t1, t2; + double t, t1, t2; double speed, maxspeed; double s, s0, s1, s2; /* do up to MAXREPEATS measurements */ - s = s0 = s1 = s2 = 0; - maxspeed = 0; + s = s0 = s1 = s2 = 0.; + maxspeed = 0.; for (n = 0; n < MAXREPEATS; n++) { - f(dstbuf, srcbuf, size); + parallel_init(threads); + for (int pt = 0; pt < threads; pt++) + { + (worker_data + pt)->func = f; + (worker_data + pt)->arg1 = dstbuf + size * pt / sizeof(int64_t); + (worker_data + pt)->arg2 = srcbuf + size * pt / sizeof(int64_t); + (worker_data + pt)->arg3 = size; + } + parallel_run(); + for (int pt = 0; pt < threads; pt++) + pthread_join(p_worker[pt], NULL); + loopcount = 0; innerloopcount = 1; - t1 = gettime(); + t = 0.; do { loopcount += innerloopcount; @@ -355,33 +460,49 @@ static double bandwidth_bench_helper(int64_t *dstbuf, int64_t *srcbuf, { for (i = 0; i < innerloopcount; i++) { + t1 = gettime(); for (j = 0; j < size; j += blocksize) - { + { f(tmpbuf, srcbuf + j / sizeof(int64_t), blocksize); f(dstbuf + j / sizeof(int64_t), tmpbuf, blocksize); } + t2 = gettime(); + t += t2 - t1; } } else { for (i = 0; i < innerloopcount; i++) { - f(dstbuf, srcbuf, size); + parallel_init(threads); + for (int pt = 0; pt < threads; ++pt) + { + (worker_data + pt)->func = f; + (worker_data + pt)->arg1 = dstbuf + size * pt / sizeof(int64_t); + (worker_data + pt)->arg2 = srcbuf + size * pt / sizeof(int64_t); + (worker_data + pt)->arg3 = size; + } + + t1 = gettime(); + parallel_run(); + for (int pt = 0; pt < threads; ++pt) + pthread_join(p_worker[pt], NULL); + t2 = gettime(); + t += t2 - t1; } } innerloopcount *= 2; - t2 = gettime(); - } while (t2 - t1 < 0.5); - speed = (double)size * loopcount / (t2 - t1) / 1000000.; + } while (t < 0.5); + speed = (double)size * (use_tmpbuf ? 1 : threads) * loopcount / t / 1000000.; - s0 += 1; + s0 += 1.; s1 += speed; s2 += speed * speed; if (speed > maxspeed) maxspeed = speed; - if (s0 > 2) + if (s0 > 2.) { s = sqrt((s0 * s2 - s1 * s1) / (s0 * (s0 - 1))); if (s < maxspeed / 1000.) @@ -391,24 +512,27 @@ static double bandwidth_bench_helper(int64_t *dstbuf, int64_t *srcbuf, if (maxspeed > 0 && s / maxspeed * 100. >= 0.1) { - printf("%s%-52s : %8.1f MB/s (%.1f%%)\n", indent_prefix, description, + printf("%s%-40s : %8.1f MB/s (%.1f%%)\n", indent_prefix, description, maxspeed, s / maxspeed * 100.); } else { - printf("%s%-52s : %8.1f MB/s\n", indent_prefix, description, maxspeed); + printf("%s%-40s : %8.1f MB/s\n", indent_prefix, description, maxspeed); } + consoleUpdate(NULL); return maxspeed; } -void bandwidth_bench(int64_t *dstbuf, int64_t *srcbuf, int64_t *tmpbuf, +void bandwidth_bench(int threads, + int64_t *dstbuf, int64_t *srcbuf, int64_t *tmpbuf, int size, int blocksize, const char *indent_prefix, bench_info *bi) { while (bi->f) { - bandwidth_bench_helper(dstbuf, srcbuf, tmpbuf, size, blocksize, + bandwidth_bench_helper(threads, + dstbuf, srcbuf, tmpbuf, size, blocksize, indent_prefix, bi->use_tmpbuf, bi->f, bi->description); @@ -428,14 +552,16 @@ void memset_wrapper(int64_t *dst, int64_t *src, int size) static bench_info aarch64_neon[] = { + { "NEON LDP", 0, aligned_block_read_ldp_q_aarch64 }, { "NEON LDP/STP copy", 0, aligned_block_copy_ldpstp_q_aarch64 }, - { "NEON LDP/STP copy pldl2strm (32 bytes step)", 0, aligned_block_copy_ldpstp_q_pf32_l2strm_aarch64 }, - { "NEON LDP/STP copy pldl2strm (64 bytes step)", 0, aligned_block_copy_ldpstp_q_pf64_l2strm_aarch64 }, - { "NEON LDP/STP copy pldl1keep (32 bytes step)", 0, aligned_block_copy_ldpstp_q_pf32_l1keep_aarch64 }, - { "NEON LDP/STP copy pldl1keep (64 bytes step)", 0, aligned_block_copy_ldpstp_q_pf64_l1keep_aarch64 }, + { "NEON LDP/STP copy pldl2strm (32B step)", 0, aligned_block_copy_ldpstp_q_pf32_l2strm_aarch64 }, + { "NEON LDP/STP copy pldl2strm (64B step)", 0, aligned_block_copy_ldpstp_q_pf64_l2strm_aarch64 }, + { "NEON LDP/STP copy pldl1keep (32B step)", 0, aligned_block_copy_ldpstp_q_pf32_l1keep_aarch64 }, + { "NEON LDP/STP copy pldl1keep (64B step)", 0, aligned_block_copy_ldpstp_q_pf64_l1keep_aarch64 }, { "NEON LD1/ST1 copy", 0, aligned_block_copy_ld1st1_aarch64 }, { "NEON STP fill", 0, aligned_block_fill_stp_q_aarch64 }, { "NEON STNP fill", 0, aligned_block_fill_stnp_q_aarch64 }, + { "ARM LDP", 0, aligned_block_read_ldp_x_aarch64 }, { "ARM LDP/STP copy", 0, aligned_block_copy_ldpstp_x_aarch64 }, { "ARM STP fill", 0, aligned_block_fill_stp_x_aarch64 }, { "ARM STNP fill", 0, aligned_block_fill_stnp_x_aarch64 }, @@ -450,18 +576,19 @@ bench_info *get_asm_benchmarks(void) static bench_info c_benchmarks[] = { { "C copy backwards", 0, aligned_block_copy_backwards }, - { "C copy backwards (32 byte blocks)", 0, aligned_block_copy_backwards_bs32 }, - { "C copy backwards (64 byte blocks)", 0, aligned_block_copy_backwards_bs64 }, + { "C copy backwards (32B blocks)", 0, aligned_block_copy_backwards_bs32 }, + { "C copy backwards (64B blocks)", 0, aligned_block_copy_backwards_bs64 }, { "C copy", 0, aligned_block_copy }, - { "C copy prefetched (32 bytes step)", 0, aligned_block_copy_pf32 }, - { "C copy prefetched (64 bytes step)", 0, aligned_block_copy_pf64 }, - { "C 2-pass copy", 1, aligned_block_copy }, - { "C 2-pass copy prefetched (32 bytes step)", 1, aligned_block_copy_pf32 }, - { "C 2-pass copy prefetched (64 bytes step)", 1, aligned_block_copy_pf64 }, + { "C copy prefetched (32B step)", 0, aligned_block_copy_pf32 }, + { "C copy prefetched (64B step)", 0, aligned_block_copy_pf64 }, + // { "C 2-pass copy", 1, aligned_block_copy }, + // { "C 2-pass copy prefetched (32B step)", 1, aligned_block_copy_pf32 }, + // { "C 2-pass copy prefetched (64B step)", 1, aligned_block_copy_pf64 }, + { "C fetch", 0, aligned_block_fetch }, { "C fill", 0, aligned_block_fill }, - { "C fill (shuffle within 16 byte blocks)", 0, aligned_block_fill_shuffle16 }, - { "C fill (shuffle within 32 byte blocks)", 0, aligned_block_fill_shuffle32 }, - { "C fill (shuffle within 64 byte blocks)", 0, aligned_block_fill_shuffle64 }, + { "C fill (shuffle within 16B blocks)", 0, aligned_block_fill_shuffle16 }, + { "C fill (shuffle within 32B blocks)", 0, aligned_block_fill_shuffle32 }, + { "C fill (shuffle within 64B blocks)", 0, aligned_block_fill_shuffle64 }, { NULL, 0, NULL } }; @@ -525,41 +652,7 @@ static void __attribute__((noinline)) random_read_test(char *zerobuffer, uint32_t seed = 0; uintptr_t addrmask = (1 << nbits) - 1; uint32_t v; - static volatile uint32_t dummy; -#ifdef __arm__ - uint32_t tmp; - __asm__ volatile ( - "subs %[count], %[count], #16\n" - "blt 1f\n" - "0:\n" - "subs %[count], %[count], #16\n" - ".rept 16\n" - "mla %[seed], %[c1103515245], %[seed], %[c12345]\n" - "and %[v], %[xFF], %[seed], lsr #16\n" - "mla %[seed], %[c1103515245], %[seed], %[c12345]\n" - "and %[tmp], %[xFF00], %[seed], lsr #8\n" - "mla %[seed], %[c1103515245], %[seed], %[c12345]\n" - "orr %[v], %[v], %[tmp]\n" - "and %[tmp], %[x7FFF0000], %[seed]\n" - "orr %[v], %[v], %[tmp]\n" - "and %[v], %[v], %[addrmask]\n" - "ldrb %[v], [%[zerobuffer], %[v]]\n" - "orr %[seed], %[seed], %[v]\n" - ".endr\n" - "bge 0b\n" - "1:\n" - "add %[count], %[count], #16\n" - : [count] "+&r" (count), - [seed] "+&r" (seed), [v] "=&r" (v), - [tmp] "=&r" (tmp) - : [c1103515245] "r" (1103515245), [c12345] "r" (12345), - [xFF00] "r" (0xFF00), [xFF] "r" (0xFF), - [x7FFF0000] "r" (0x7FFF0000), - [zerobuffer] "r" (zerobuffer), - [addrmask] "r" (addrmask) - : "cc"); -#else #define RANDOM_MEM_ACCESS() \ seed = seed * 1103515245 + 12345; \ v = (seed >> 16) & 0xFF; \ @@ -588,8 +681,6 @@ static void __attribute__((noinline)) random_read_test(char *zerobuffer, RANDOM_MEM_ACCESS(); count -= 16; } -#endif - dummy = seed; #undef RANDOM_MEM_ACCESS } @@ -599,51 +690,6 @@ static void __attribute__((noinline)) random_dual_read_test(char *zerobuffer, uint32_t seed = 0; uintptr_t addrmask = (1 << nbits) - 1; uint32_t v1, v2; - static volatile uint32_t dummy; - -#ifdef __arm__ - uint32_t tmp; - __asm__ volatile ( - "subs %[count], %[count], #16\n" - "blt 1f\n" - "0:\n" - "subs %[count], %[count], #16\n" - ".rept 16\n" - "mla %[seed], %[c1103515245], %[seed], %[c12345]\n" - "and %[v1], %[xFF00], %[seed], lsr #8\n" - "mla %[seed], %[c1103515245], %[seed], %[c12345]\n" - "and %[v2], %[xFF00], %[seed], lsr #8\n" - "mla %[seed], %[c1103515245], %[seed], %[c12345]\n" - "and %[tmp], %[x7FFF0000], %[seed]\n" - "mla %[seed], %[c1103515245], %[seed], %[c12345]\n" - "orr %[v1], %[v1], %[tmp]\n" - "and %[tmp], %[x7FFF0000], %[seed]\n" - "mla %[seed], %[c1103515245], %[seed], %[c12345]\n" - "orr %[v2], %[v2], %[tmp]\n" - "and %[tmp], %[xFF], %[seed], lsr #16\n" - "orr %[v2], %[v2], %[seed], lsr #24\n" - "orr %[v1], %[v1], %[tmp]\n" - "and %[v2], %[v2], %[addrmask]\n" - "eor %[v1], %[v1], %[v2]\n" - "and %[v1], %[v1], %[addrmask]\n" - "ldrb %[v2], [%[zerobuffer], %[v2]]\n" - "ldrb %[v1], [%[zerobuffer], %[v1]]\n" - "orr %[seed], %[seed], %[v2]\n" - "add %[seed], %[seed], %[v1]\n" - ".endr\n" - "bge 0b\n" - "1:\n" - "add %[count], %[count], #16\n" - : [count] "+&r" (count), - [seed] "+&r" (seed), [v1] "=&r" (v1), [v2] "=&r" (v2), - [tmp] "=&r" (tmp) - : [c1103515245] "r" (1103515245), [c12345] "r" (12345), - [xFF00] "r" (0xFF00), [xFF] "r" (0xFF), - [x7FFF0000] "r" (0x7FFF0000), - [zerobuffer] "r" (zerobuffer), - [addrmask] "r" (addrmask) - : "cc"); -#else #define RANDOM_MEM_ACCESS() \ seed = seed * 1103515245 + 12345; \ v1 = (seed >> 8) & 0xFF00; \ @@ -680,8 +726,6 @@ static void __attribute__((noinline)) random_dual_read_test(char *zerobuffer, RANDOM_MEM_ACCESS(); count -= 16; } -#endif - dummy = seed; #undef RANDOM_MEM_ACCESS } @@ -697,8 +741,8 @@ static uint32_t rand32() int latency_bench(int size, int count, int use_hugepage) { double t, t2, t_before, t_after, t_noaccess, t_noaccess2 = 0; - double xs, xs0, xs1, xs2; - double ys, ys0, ys1, ys2; + double xs, xs1, xs2; + double ys, ys1, ys2; double min_t, min_t2; int nbits, n; char *buffer, *buffer_alloc; @@ -852,13 +896,14 @@ int main(int argc, char* argv[]) int64_t *srcbuf, *dstbuf, *tmpbuf; void *poolbuf; size_t bufsize = SIZE; + int threads = 2; - printf("tinymembench v0.4.9 (simple benchmark for memory throughput and latency)\n"); + printf("TinyMemBenchNX v0.4.10\n\ +(based on tinymembench-pthread, a multi-thread fork of simple benchmark for memory throughput and latency)\n"); - - poolbuf = alloc_four_nonaliased_buffers((void **)&srcbuf, bufsize, - (void **)&dstbuf, bufsize, - (void **)&tmpbuf, BLOCKSIZE, + poolbuf = alloc_four_nonaliased_buffers((void **)&srcbuf, bufsize * threads, + (void **)&dstbuf, bufsize * threads, + (void **)&tmpbuf, BLOCKSIZE * threads, NULL, 0); printf("\n"); printf("==========================================================================\n"); @@ -875,21 +920,49 @@ int main(int argc, char* argv[]) printf("== brackets ==\n"); printf("==========================================================================\n\n"); + printf("!!! Memory bandwidth heavily depends on CPU clock. !!!\n\n"); + printf("\ +Press A to start bandwidth test @ 1 thread.\n\ +Press B to start bandwidth test @ 2 threads.\n\ +Press any other key to exit.\n\n"); + consoleUpdate(NULL); - printf("!!! Memory bandwidth heavily depends on CPU clock. !!!\n\n"); - printClock(); - printf("Press A to start bandwidth test, any other key to exit.\n\n"); - waitForKeyA(); + while (appletMainLoop()) + { + padUpdate(&pad); - bandwidth_bench(dstbuf, srcbuf, tmpbuf, bufsize, BLOCKSIZE, " ", c_benchmarks); + u64 kDown = padGetButtonsDown(&pad); + + if (kDown & HidNpadButton_A) + { + threads = 1; + break; + } + else if (kDown & HidNpadButton_B) + { + threads = 2; + break; + } + else if (kDown) + { + consoleExit(NULL); + exit(0); + } + } + + printClock(); + printf("== Thread: %d ==\n", threads); + consoleUpdate(NULL); + + bandwidth_bench(threads, dstbuf, srcbuf, tmpbuf, bufsize, BLOCKSIZE, " ", c_benchmarks); printf(" ---\n"); - bandwidth_bench(dstbuf, srcbuf, tmpbuf, bufsize, BLOCKSIZE, " ", libc_benchmarks); + bandwidth_bench(threads, dstbuf, srcbuf, tmpbuf, bufsize, BLOCKSIZE, " ", libc_benchmarks); bench_info *bi = get_asm_benchmarks(); if (bi->f) { printf(" ---\n"); - bandwidth_bench(dstbuf, srcbuf, tmpbuf, bufsize, BLOCKSIZE, " ", bi); + bandwidth_bench(threads, dstbuf, srcbuf, tmpbuf, bufsize, BLOCKSIZE, " ", bi); } free(poolbuf);