4x8 GEMM and IGEMM microkernels for AARCH32 Cortex A55. 11.5% faster end to end:
Was f32_gemm_4x8__aarch32_neon_cortex_a53/mobilenet_v2/real_time 154006 us
Now f32_gemm_4x8__aarch32_neon_cortex_a55/mobilenet_v2/real_time 138030 us
23% faster GEMM on mobilenet_v2
Was f32_gemm_4x8__aarch32_neon_cortex_a53 59909460
Now f32_gemm_4x8__aarch32_neon_cortex_a55 48681160
19.2% faster IGEMM on mobilenet_v2
Was f32_igemm_4x8__aarch32_neon_cortex_a53 67209225
Now f32_igemm_4x8__aarch32_neon_cortex_a55 56380323
End2end benchmark
Was
MobileNetV1/T:1/real_time 236793 us
MobileNetV2/T:1/real_time 154689 us
MobileNetV3Large/T:1/real_time 130964 us
MobileNetV3Small/T:1/real_time 42383 us
Now
MobileNetV1/T:1/real_time 199053 us
MobileNetV2/T:1/real_time 140262 us
MobileNetV3Large/T:1/real_time 120468 us
MobileNetV3Small/T:1/real_time 39952 us
The rev 1 version of Cortex A55 can co-issue a 64 bit
vector load with each FMA, so re-arrange the Cortex-A53
microkernel with 3 FMA paired with 2 loads.
Basic code block is 3 VMLA with 2 VLD64:
// BLOCK 0
VMLA.F32 q8, q4, d4[0]
VLD1.32 {d0}, [r3]! // A0
VMLA.F32 q10, q4, d5[0]
VLD1.32 {d1}, [r12]! // A1
VMLA.F32 q12, q4, d6[0]
PiperOrigin-RevId: 300384515
diff --git a/bench/f32-gemm-e2e.cc b/bench/f32-gemm-e2e.cc
index 2523fda..190d55c 100644
--- a/bench/f32-gemm-e2e.cc
+++ b/bench/f32-gemm-e2e.cc
@@ -283,6 +283,15 @@
4 /* mr */, 8 /* nr */, 0 /* log2_kr */, 0 /* log2_sr */,
benchmark::utils::CheckNEON);
}
+ static void f32_gemm_4x8__aarch32_neon_cortex_a55(benchmark::State& state, models::ExecutionPlanFactory model) {
+ GEMMEnd2EndBenchmark(state, model,
+ xnn_f32_gemm_ukernel_4x8__aarch32_neon_cortex_a55,
+ xnn_f32_igemm_ukernel_4x8__aarch32_neon_cortex_a55,
+ xnn_f32_gemm_ukernel_1x8__neon_lane_ld64,
+ xnn_f32_igemm_ukernel_1x8__neon_lane_ld64,
+ 4 /* mr */, 8 /* nr */, 0 /* log2_kr */, 0 /* log2_sr */,
+ benchmark::utils::CheckNEON);
+ }
static void f32_gemm_4x8__aarch32_neon_cortex_a75(benchmark::State& state, models::ExecutionPlanFactory model) {
GEMMEnd2EndBenchmark(state, model,
xnn_f32_gemm_ukernel_4x8__aarch32_neon_cortex_a75,
@@ -304,6 +313,7 @@
BENCHMARK_END2END(f32_gemm_4x8__aarch32_neon_ld64);
BENCHMARK_END2END(f32_gemm_4x8__aarch32_neon_cortex_a53);
+ BENCHMARK_END2END(f32_gemm_4x8__aarch32_neon_cortex_a55);
BENCHMARK_END2END(f32_gemm_4x8__aarch32_neon_cortex_a75);
BENCHMARK_END2END(f32_gemm_4x8__aarch32_neon_pld_cortex_a75);
#endif // XNN_ARCH_ARM && XNN_ENABLE_ASSEMBLY
diff --git a/bench/f32-gemm.cc b/bench/f32-gemm.cc
index 8788f23..c68578f 100644
--- a/bench/f32-gemm.cc
+++ b/bench/f32-gemm.cc
@@ -457,6 +457,9 @@
static void f32_gemm_4x8__aarch32_neon_cortex_a53(benchmark::State& state, const char* net) {
GEMMBenchmark(state, xnn_f32_gemm_ukernel_4x8__aarch32_neon_cortex_a53, 4, 8, 1, 1, benchmark::utils::CheckNEON);
}
+ static void f32_gemm_4x8__aarch32_neon_cortex_a55(benchmark::State& state, const char* net) {
+ GEMMBenchmark(state, xnn_f32_gemm_ukernel_4x8__aarch32_neon_cortex_a55, 4, 8, 1, 1, benchmark::utils::CheckNEON);
+ }
static void f32_gemm_4x8__aarch32_neon_cortex_a75(benchmark::State& state, const char* net) {
GEMMBenchmark(state, xnn_f32_gemm_ukernel_4x8__aarch32_neon_cortex_a75, 4, 8, 1, 1, benchmark::utils::CheckNEON);
}
@@ -466,6 +469,7 @@
BENCHMARK_GEMM(f32_gemm_4x8__aarch32_neon_ld64)
BENCHMARK_GEMM(f32_gemm_4x8__aarch32_neon_cortex_a53)
+ BENCHMARK_GEMM(f32_gemm_4x8__aarch32_neon_cortex_a55)
BENCHMARK_GEMM(f32_gemm_4x8__aarch32_neon_cortex_a75)
BENCHMARK_GEMM(f32_gemm_4x8__aarch32_neon_pld_cortex_a75)
#endif // XNN_ARCH_ARM
diff --git a/bench/f32-igemm.cc b/bench/f32-igemm.cc
index 10bcbee..1aa6fcd 100644
--- a/bench/f32-igemm.cc
+++ b/bench/f32-igemm.cc
@@ -262,8 +262,24 @@
static void f32_igemm_4x8__aarch32_neon_ld64(benchmark::State& state, const char* net) {
IGEMMBenchmark(state, xnn_f32_igemm_ukernel_4x8__aarch32_neon_ld64, 4, 8, 1, 1);
}
+ static void f32_igemm_4x8__aarch32_neon_cortex_a53(benchmark::State& state, const char* net) {
+ IGEMMBenchmark(state, xnn_f32_igemm_ukernel_4x8__aarch32_neon_cortex_a53, 4, 8, 1, 1);
+ }
+ static void f32_igemm_4x8__aarch32_neon_cortex_a55(benchmark::State& state, const char* net) {
+ IGEMMBenchmark(state, xnn_f32_igemm_ukernel_4x8__aarch32_neon_cortex_a55, 4, 8, 1, 1);
+ }
+ static void f32_igemm_4x8__aarch32_neon_pld_cortex_a75(benchmark::State& state, const char* net) {
+ IGEMMBenchmark(state, xnn_f32_igemm_ukernel_4x8__aarch32_neon_pld_cortex_a75, 4, 8, 1, 1);
+ }
+ static void f32_igemm_4x8__aarch32_neon_cortex_a75(benchmark::State& state, const char* net) {
+ IGEMMBenchmark(state, xnn_f32_igemm_ukernel_4x8__aarch32_neon_cortex_a75, 4, 8, 1, 1);
+ }
BENCHMARK_CONV(f32_igemm_4x8__aarch32_neon_ld64)
+ BENCHMARK_CONV(f32_igemm_4x8__aarch32_neon_cortex_a53)
+ BENCHMARK_CONV(f32_igemm_4x8__aarch32_neon_cortex_a55)
+ BENCHMARK_CONV(f32_igemm_4x8__aarch32_neon_pld_cortex_a75)
+ BENCHMARK_CONV(f32_igemm_4x8__aarch32_neon_cortex_a75)
#endif /* XNN_ARCH_ARM */
#if XNN_ARCH_ARM64 && XNN_ENABLE_ASSEMBLY
@@ -379,22 +395,6 @@
BENCHMARK_CONV(f32_igemm_6x8__neonfma_lane_ld128)
#endif /* XNN_ARCH_ARM64 */
-#if XNN_ARCH_ARM && XNN_ENABLE_ASSEMBLY
- static void f32_igemm_4x8__aarch32_neon_pld_cortex_a75(benchmark::State& state, const char* net) {
- IGEMMBenchmark(state, xnn_f32_igemm_ukernel_4x8__aarch32_neon_pld_cortex_a75, 4, 8, 1, 1);
- }
- static void f32_igemm_4x8__aarch32_neon_cortex_a75(benchmark::State& state, const char* net) {
- IGEMMBenchmark(state, xnn_f32_igemm_ukernel_4x8__aarch32_neon_cortex_a75, 4, 8, 1, 1);
- }
- static void f32_igemm_4x8__aarch32_neon_cortex_a53(benchmark::State& state, const char* net) {
- IGEMMBenchmark(state, xnn_f32_igemm_ukernel_4x8__aarch32_neon_cortex_a53, 4, 8, 1, 1);
- }
-
- BENCHMARK_CONV(f32_igemm_4x8__aarch32_neon_pld_cortex_a75)
- BENCHMARK_CONV(f32_igemm_4x8__aarch32_neon_cortex_a75)
- BENCHMARK_CONV(f32_igemm_4x8__aarch32_neon_cortex_a53)
-#endif /* XNN_ARCH_ARM */
-
#if XNN_ARCH_X86 || XNN_ARCH_X86_64
static void f32_igemm_1x8__sse_load1(benchmark::State& state, const char* net) {
IGEMMBenchmark(state, xnn_f32_igemm_ukernel_1x8__sse_load1, 1, 8, 1, 1);