Content |
Lösungsvorschlag
In hpc_project.tgz ist jetzt die Cache-optimierte Implementierung der GEMM-Operation enthalten. Wesentliche Änderungen:
-
In hpc_project/ulmblas/level3.h wurde aufgeräumt. Es enthält nur noch die Signatur einer GEMM-Variante:
#ifndef ULMBLAS_LEVEL3_H #define ULMBLAS_LEVEL3_H 1 // // BLAS Level 3 // //-- GEMM ---------------------------------------------------------------------- void dgemm(int m, int n, int k, double alpha, const double *A, int incRowA, int incColA, const double *B, int incRowB, int incColB, double beta, double *C, int incRowC, int incColC); #endif // ULMBLAS_LEVEL3_H
-
In hpc_project/ulmblas/level3.c sind neben dem Frame-Algorithmus auch der der Macro-Kernel für GEMM und die Pack-Prozeduren enthalten.
Benchmark durchführen
Um den Benchmark durchzuführen, muss in hpc_project/ulmblas eine statische Bibliothek für ulmBLAS erzeugt werden:
$shell> pwd /home/numerik/hpc/ss16/session08/example02/hpc_project/ulmblas $shell> make gcc -Wall -mavx -Ofast -I .. -c -o level3.o level3.c gcc -Wall -mavx -Ofast -I .. -c -o lu.o lu.c gcc -Wall -mavx -Ofast -I .. -c -o level1.o level1.c gcc -Wall -mavx -Ofast -I .. -c -o level2.o level2.c as -o ugemm_4_8.o ugemm_4_8.s ar cru ../ulmblas.a level3.o lu.o level1.o level2.o ugemm_4_8.o ranlib ../ulmblas.a $shell>
Anschließend kann im bench-Verzeichnis der Benchmark erzeugt werden:
$shell> pwd /home/numerik/hpc/ss16/session08/example02/hpc_project/bench $shell> make gcc -Wall -mavx -Ofast -I .. -c -o aux.o aux.c gcc -Wall -mavx -Ofast -I .. -c -o refblas.o refblas.c gcc -Wall -mavx -Ofast -I .. -c -o errbound.o errbound.c gcc -Wall -mavx -Ofast -I .. aux.o refblas.o errbound.o -o bench_dgemm_4_8 bench_dgemm_4_8.c ../ulmblas.a rm refblas.o aux.o errbound.o $shell>
Wie üblich kann ein Plot erzeugt werden, indem die Ausgabe zunächst in eine Datei umgelenkt wird und mit einem GNUplot-Skript verarbeitet wird:
$shell> ./bench_dgemm_4_8 > report.gemm_avx $shell> gnuplot plot.gemm $shell>
Damit erhält man:
Assembler-Code für AVX
# void # gemm_micro(long k, # double alpha, # double *A, # double *B, # double beta, # double *C, long incRowC, long incColC); .globl ugemm_4_8 ugemm_4_8: # Arguments: # %rdi long k # %xmm0 double alpha # %rsi double *A # %rdx double *B # %xmm1 double beta # %rcx double *C # %r8 long incRowC # %r9 long incColC vmovlpd %xmm0, -8(%rsp) # push alpha vmovlpd %xmm1, -16(%rsp) # push beta movq %rax, -24(%rsp) movq %rbx, -32(%rsp) vxorpd %ymm8, %ymm8, %ymm8 vxorpd %ymm9, %ymm9, %ymm9 vxorpd %ymm10, %ymm10, %ymm10 vxorpd %ymm11, %ymm11, %ymm11 vxorpd %ymm12, %ymm12, %ymm12 vxorpd %ymm13, %ymm13, %ymm13 vxorpd %ymm14, %ymm14, %ymm14 vxorpd %ymm15, %ymm15, %ymm15 jmp check loop: vbroadcastsd 0*8(%rsi), %ymm0 vbroadcastsd 1*8(%rsi), %ymm1 vbroadcastsd 2*8(%rsi), %ymm2 vbroadcastsd 3*8(%rsi), %ymm3 vmovapd 0*32(%rdx), %ymm4 vmovapd 1*32(%rdx), %ymm5 vmulpd %ymm0, %ymm4, %ymm6 vmulpd %ymm0, %ymm5, %ymm7 vaddpd %ymm6, %ymm8, %ymm8 vaddpd %ymm7, %ymm9, %ymm9 vmulpd %ymm1, %ymm4, %ymm6 vmulpd %ymm1, %ymm5, %ymm7 vaddpd %ymm6, %ymm10, %ymm10 vaddpd %ymm7, %ymm11, %ymm11 vmulpd %ymm2, %ymm4, %ymm6 vmulpd %ymm2, %ymm5, %ymm7 vaddpd %ymm6, %ymm12, %ymm12 vaddpd %ymm7, %ymm13, %ymm13 vmulpd %ymm3, %ymm4, %ymm6 vmulpd %ymm3, %ymm5, %ymm7 vaddpd %ymm6, %ymm14, %ymm14 vaddpd %ymm7, %ymm15, %ymm15 addq $32, %rsi addq $64, %rdx decq %rdi check: testq %rdi, %rdi jg loop vbroadcastsd -8(%rsp), %ymm5 # alpha vmulpd %ymm5, %ymm8, %ymm8 vmulpd %ymm5, %ymm9, %ymm9 vmulpd %ymm5, %ymm10, %ymm10 vmulpd %ymm5, %ymm11, %ymm11 vmulpd %ymm5, %ymm12, %ymm12 vmulpd %ymm5, %ymm13, %ymm13 vmulpd %ymm5, %ymm14, %ymm14 vmulpd %ymm5, %ymm15, %ymm15 leaq (,%r8,8), %r8 leaq (,%r9,8), %r9 leaq (,%r9,2), %r10 leaq (%r10,%r9), %r11 leaq (%rcx,%r10,2), %rdx vbroadcastsd -16(%rsp), %ymm7 # beta # check if beta == 0 vxorpd %ymm0, %ymm0, %ymm0 vucomisd %xmm0, %xmm7 je beta_zero # case: beta != 0 # update C(0,:) vmovlpd (%rcx), %xmm0, %xmm0 vmovhpd (%rcx,%r9), %xmm0, %xmm0 vmovlpd (%rcx,%r10), %xmm1, %xmm1 vmovhpd (%rcx,%r11), %xmm1, %xmm1 vmovlpd (%rdx), %xmm2, %xmm2 vmovhpd (%rdx,%r9), %xmm2, %xmm2 vmovlpd (%rdx,%r10), %xmm3, %xmm3 vmovhpd (%rdx,%r11), %xmm3, %xmm3 vmulpd %xmm7, %xmm0, %xmm0 vmulpd %xmm7, %xmm1, %xmm1 vmulpd %xmm7, %xmm2, %xmm2 vmulpd %xmm7, %xmm3, %xmm3 vextractf128 $1, %ymm8, %xmm4 vextractf128 $1, %ymm9, %xmm5 vaddpd %xmm0, %xmm8, %xmm0 vaddpd %xmm1, %xmm4, %xmm1 vaddpd %xmm2, %xmm9, %xmm2 vaddpd %xmm3, %xmm5, %xmm3 vmovlpd %xmm0, (%rcx) vmovhpd %xmm0, (%rcx,%r9) vmovlpd %xmm1, (%rcx,%r10) vmovhpd %xmm1, (%rcx,%r11) vmovlpd %xmm2, (%rdx) vmovhpd %xmm2, (%rdx,%r9) vmovlpd %xmm3, (%rdx,%r10) vmovhpd %xmm3, (%rdx,%r11) # update pointers rcx, rdx to the next row addq %r8, %rcx addq %r8, %rdx # update C(1,:) vmovlpd (%rcx), %xmm0, %xmm0 vmovhpd (%rcx,%r9), %xmm0, %xmm0 vmovlpd (%rcx,%r10), %xmm1, %xmm1 vmovhpd (%rcx,%r11), %xmm1, %xmm1 vmovlpd (%rdx), %xmm2, %xmm2 vmovhpd (%rdx,%r9), %xmm2, %xmm2 vmovlpd (%rdx,%r10), %xmm3, %xmm3 vmovhpd (%rdx,%r11), %xmm3, %xmm3 vmulpd %xmm7, %xmm0, %xmm0 vmulpd %xmm7, %xmm1, %xmm1 vmulpd %xmm7, %xmm2, %xmm2 vmulpd %xmm7, %xmm3, %xmm3 vextractf128 $1, %ymm10, %xmm4 vextractf128 $1, %ymm11, %xmm5 vaddpd %xmm0, %xmm10, %xmm0 vaddpd %xmm1, %xmm4, %xmm1 vaddpd %xmm2, %xmm11, %xmm2 vaddpd %xmm3, %xmm5, %xmm3 vmovlpd %xmm0, (%rcx) vmovhpd %xmm0, (%rcx,%r9) vmovlpd %xmm1, (%rcx,%r10) vmovhpd %xmm1, (%rcx,%r11) vmovlpd %xmm2, (%rdx) vmovhpd %xmm2, (%rdx,%r9) vmovlpd %xmm3, (%rdx,%r10) vmovhpd %xmm3, (%rdx,%r11) # update pointers rcx, rdx to the next row addq %r8, %rcx addq %r8, %rdx # update C(2,:) vmovlpd (%rcx), %xmm0, %xmm0 vmovhpd (%rcx,%r9), %xmm0, %xmm0 vmovlpd (%rcx,%r10), %xmm1, %xmm1 vmovhpd (%rcx,%r11), %xmm1, %xmm1 vmovlpd (%rdx), %xmm2, %xmm2 vmovhpd (%rdx,%r9), %xmm2, %xmm2 vmovlpd (%rdx,%r10), %xmm3, %xmm3 vmovhpd (%rdx,%r11), %xmm3, %xmm3 vmulpd %xmm7, %xmm0, %xmm0 vmulpd %xmm7, %xmm1, %xmm1 vmulpd %xmm7, %xmm2, %xmm2 vmulpd %xmm7, %xmm3, %xmm3 vextractf128 $1, %ymm12, %xmm4 vextractf128 $1, %ymm13, %xmm5 vaddpd %xmm0, %xmm12, %xmm0 vaddpd %xmm1, %xmm4, %xmm1 vaddpd %xmm2, %xmm13, %xmm2 vaddpd %xmm3, %xmm5, %xmm3 vmovlpd %xmm0, (%rcx) vmovhpd %xmm0, (%rcx,%r9) vmovlpd %xmm1, (%rcx,%r10) vmovhpd %xmm1, (%rcx,%r11) vmovlpd %xmm2, (%rdx) vmovhpd %xmm2, (%rdx,%r9) vmovlpd %xmm3, (%rdx,%r10) vmovhpd %xmm3, (%rdx,%r11) # update pointers rcx, rdx to the next row addq %r8, %rcx addq %r8, %rdx # update C(3,:) vmovlpd (%rcx), %xmm0, %xmm0 vmovhpd (%rcx,%r9), %xmm0, %xmm0 vmovlpd (%rcx,%r10), %xmm1, %xmm1 vmovhpd (%rcx,%r11), %xmm1, %xmm1 vmovlpd (%rdx), %xmm2, %xmm2 vmovhpd (%rdx,%r9), %xmm2, %xmm2 vmovlpd (%rdx,%r10), %xmm3, %xmm3 vmovhpd (%rdx,%r11), %xmm3, %xmm3 vmulpd %xmm7, %xmm0, %xmm0 vmulpd %xmm7, %xmm1, %xmm1 vmulpd %xmm7, %xmm2, %xmm2 vmulpd %xmm7, %xmm3, %xmm3 vextractf128 $1, %ymm14, %xmm4 vextractf128 $1, %ymm15, %xmm5 vaddpd %xmm0, %xmm14, %xmm0 vaddpd %xmm1, %xmm4, %xmm1 vaddpd %xmm2, %xmm15, %xmm2 vaddpd %xmm3, %xmm5, %xmm3 vmovlpd %xmm0, (%rcx) vmovhpd %xmm0, (%rcx,%r9) vmovlpd %xmm1, (%rcx,%r10) vmovhpd %xmm1, (%rcx,%r11) vmovlpd %xmm2, (%rdx) vmovhpd %xmm2, (%rdx,%r9) vmovlpd %xmm3, (%rdx,%r10) vmovhpd %xmm3, (%rdx,%r11) jmp return beta_zero: # case: beta == 0 # update C(0,:) vextractf128 $1, %ymm8, %xmm4 vextractf128 $1, %ymm9, %xmm5 vmovlpd %xmm8, (%rcx) vmovhpd %xmm8, (%rcx,%r9) vmovlpd %xmm4, (%rcx,%r10) vmovhpd %xmm4, (%rcx,%r11) vmovlpd %xmm9, (%rdx) vmovhpd %xmm9, (%rdx,%r9) vmovlpd %xmm5, (%rdx,%r10) vmovhpd %xmm5, (%rdx,%r11) # update pointers rcx, rdx to the next row addq %r8, %rcx addq %r8, %rdx # update C(1,:) vextractf128 $1, %ymm10, %xmm4 vextractf128 $1, %ymm11, %xmm5 vmovlpd %xmm10, (%rcx) vmovhpd %xmm10, (%rcx,%r9) vmovlpd %xmm4, (%rcx,%r10) vmovhpd %xmm4, (%rcx,%r11) vmovlpd %xmm11, (%rdx) vmovhpd %xmm11, (%rdx,%r9) vmovlpd %xmm5, (%rdx,%r10) vmovhpd %xmm5, (%rdx,%r11) # update pointers rcx, rdx to the next row addq %r8, %rcx addq %r8, %rdx # update C(2,:) vextractf128 $1, %ymm12, %xmm4 vextractf128 $1, %ymm13, %xmm5 vmovlpd %xmm12, (%rcx) vmovhpd %xmm12, (%rcx,%r9) vmovlpd %xmm4, (%rcx,%r10) vmovhpd %xmm4, (%rcx,%r11) vmovlpd %xmm13, (%rdx) vmovhpd %xmm13, (%rdx,%r9) vmovlpd %xmm5, (%rdx,%r10) vmovhpd %xmm5, (%rdx,%r11) # update pointers rcx, rdx to the next row addq %r8, %rcx addq %r8, %rdx # update C(3,:) vextractf128 $1, %ymm14, %xmm4 vextractf128 $1, %ymm15, %xmm5 vmovlpd %xmm14, (%rcx) vmovhpd %xmm14, (%rcx,%r9) vmovlpd %xmm4, (%rcx,%r10) vmovhpd %xmm4, (%rcx,%r11) vmovlpd %xmm15, (%rdx) vmovhpd %xmm15, (%rdx,%r9) vmovlpd %xmm5, (%rdx,%r10) vmovhpd %xmm5, (%rdx,%r11) return: movq -24(%rsp), %rax movq -32(%rsp), %rbx retq