summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Upton <oliver.upton@linux.dev>2024-02-26 18:08:33 +0000
committerOliver Upton <oliver.upton@linux.dev>2024-02-26 18:08:33 +0000
commit81d3391617f216f74e3712c82310c2dea5753707 (patch)
tree8ef7f9a78b79e8b61376c769bd144344a660cae8
parent60ad5c2833b090583eae724a6e1917f4efe0c702 (diff)
downloadaarch64-memcpy-81d3391617f216f74e3712c82310c2dea5753707.tar.gz
Test dcache CMOs before copying memory
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
-rw-r--r--Makefile2
-rw-r--r--main.c37
2 files changed, 37 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index c4b94f2..9f3902f 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/main.c b/main.c
index 6f28f68..315ff3a 100644
--- a/main.c
+++ b/main.c
@@ -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);
}