// CPU ReLU efficiency: current SSE-1-thread vs AVX2 auto-vec vs AVX2+OpenMP. // Compile: icx -O3 -xHost -qopenmp cpu_relu.cpp -o cpu_relu (i9-13900K = AVX2) #include #include #include #include #include #include #include // --- current backend: explicit SSE (128-bit = 4 floats), single thread --- void relu_sse(float* out, const float* in, size_t n){ size_t i=0; for(; i+4<=n; i+=4){ __m128 v=_mm_loadu_ps(in+i); // (use unaligned: aligned would segfault) _mm_storeu_ps(out+i, _mm_max_ps(v, _mm_setzero_ps())); } for(; i0.f?in[i]:0.f; } // --- clean loop, compiler auto-vectorizes to AVX2 (8 floats) with -xHost, 1 thread --- void relu_autovec(float* __restrict out, const float* __restrict in, size_t n){ for(size_t i=0;i0.f?in[i]:0.f; } // --- AVX2 + OpenMP across cores --- void relu_omp(float* __restrict out, const float* __restrict in, size_t n){ #pragma omp parallel for schedule(static) for(size_t i=0;i0.f?in[i]:0.f; } // --- AVX2 + OpenMP + non-temporal stores (skip write-allocate/RFO traffic) --- void relu_omp_nt(float* __restrict out, const float* __restrict in, size_t n){ #pragma omp parallel for schedule(static) for(size_t j=0;j double bench(F f, float* out, const float* in, size_t n){ for(int w=0;w<3;w++) f(out,in,n); double best=1e30; for(int r=0;r<10;r++){ auto t0=std::chrono::high_resolution_clock::now(); f(out,in,n); auto t1=std::chrono::high_resolution_clock::now(); best=std::min(best,std::chrono::duration(t1-t0).count()); } return best; } int main(){ printf("OpenMP max threads: %d\n", omp_get_max_threads()); const size_t n=256ull*1024*1024; // 1 GB/array -> DRAM-bound float* in =(float*)aligned_alloc(64, n*sizeof(float)); float* out=(float*)aligned_alloc(64, n*sizeof(float)); for(size_t i=0;i0?in[i]:0; if(out[i]!=e){printf(" %s FAIL@%zu\n",nm,i);return;} } }; check(relu_sse,"sse"); check(relu_autovec,"autovec"); check(relu_omp,"omp"); check(relu_omp_nt,"omp_nt"); printf("CPU ReLU, 256M fp32 (1 GB/array, DRAM-bound):\n"); report("SSE 4-wide 1-thread", bench(relu_sse, out, in, n)); report("AVX2 auto-vec 1-thread", bench(relu_autovec, out, in, n)); report("AVX2 + OpenMP", bench(relu_omp, out, in, n)); report("AVX2 + OpenMP + NT-store", bench(relu_omp_nt, out, in, n)); free(in); free(out); return 0; }