diff options
author | Oliver Upton <oliver.upton@linux.dev> | 2024-02-26 18:08:33 +0000 |
---|---|---|
committer | Oliver Upton <oliver.upton@linux.dev> | 2024-02-26 18:08:33 +0000 |
commit | 81d3391617f216f74e3712c82310c2dea5753707 (patch) | |
tree | 8ef7f9a78b79e8b61376c769bd144344a660cae8 | |
parent | 60ad5c2833b090583eae724a6e1917f4efe0c702 (diff) | |
download | aarch64-memcpy-81d3391617f216f74e3712c82310c2dea5753707.tar.gz |
Test dcache CMOs before copying memory
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | main.c | 37 |
2 files changed, 37 insertions, 2 deletions
@@ -1,5 +1,5 @@ CC := aarch64-linux-gnu-gcc -CFLAGS += -O3 -Wall -Werror +CFLAGS += -O3 -Wall -Werror -static OBJS = main.o OBJS += memcpy_ldp_str.o @@ -21,6 +21,7 @@ enum mode { LDTR_STP, LDP_STP, PRFM_2K_LDP_STR, + LDP_STP_DC_CIVAC, NR_MODES }; @@ -42,6 +43,7 @@ static void pr_modes(void) PR_MODE(LDTR_STP); PR_MODE(LDP_STP); PR_MODE(PRFM_2K_LDP_STR); + PR_MODE(LDP_STP_DC_CIVAC); } static void pr_help(const char *progname) @@ -76,6 +78,17 @@ static void destroy_test_buffer(void *buf) munmap(buf, test_size); } +static void dcache_clean_invalidate(const void *buf, size_t size) +{ + const void *addr; + + for (addr = buf; addr < buf + size; addr += 64) + asm volatile("dc civac, %0" : : "r"(addr) + : "memory"); + + asm volatile("dsb ish"); +} + static void do_memcpy(void *dst, const void *src, size_t chunk_size) { switch (test_mode) { @@ -92,6 +105,7 @@ static void do_memcpy(void *dst, const void *src, size_t chunk_size) memcpy_ldtr_stp(dst, src, chunk_size); break; case LDP_STP: + case LDP_STP_DC_CIVAC: memcpy_ldp_stp(dst, src, chunk_size); break; case PRFM_2K_LDP_STR: @@ -103,6 +117,8 @@ static void do_memcpy(void *dst, const void *src, size_t chunk_size) } #define NSEC_PER_SEC 1000000000UL +#define NSEC_PER_MSEC 1000000UL +#define MSEC_PER_SEC 1000UL static void report_bandwidth(struct timespec *start, struct timespec *end) { @@ -114,11 +130,21 @@ static void report_bandwidth(struct timespec *start, struct timespec *end) printf("Rate: %.03f GiB/sec\n", rate); } +static void report_dcache_time(struct timespec *start, struct timespec *end) +{ + unsigned long msecs; + + msecs = (end->tv_sec - start->tv_sec) * MSEC_PER_SEC; + msecs = (end->tv_nsec - start->tv_nsec) / NSEC_PER_MSEC; + + printf("cache maintenance took %lu milliseconds\n", msecs); +} + static void run_test(void) { void *dst = setup_test_buffer(); void *src = setup_test_buffer(); - struct timespec start, end; + struct timespec start, end, dc_start, dc_end; size_t offset, i; printf("Iters: %lu\n", test_iterations); @@ -129,6 +155,12 @@ static void run_test(void) assert(!clock_gettime(CLOCK_MONOTONIC, &start)); for (i = 0; i < test_iterations; i++) { + if (test_mode == LDP_STP_DC_CIVAC) { + assert(!clock_gettime(CLOCK_MONOTONIC, &dc_start)); + dcache_clean_invalidate(src, test_size); + assert(!clock_gettime(CLOCK_MONOTONIC, &dc_end)); + } + for (offset = 0; offset < test_size; offset += chunk_size) { do_memcpy(dst + offset, src + offset, chunk_size); assert(!memchr(dst + offset, 0, chunk_size)); @@ -139,6 +171,9 @@ static void run_test(void) report_bandwidth(&start, &end); + if (test_mode == LDP_STP_DC_CIVAC) + report_dcache_time(&dc_start, &dc_end); + destroy_test_buffer(dst); destroy_test_buffer(src); } |