Vectorization

Vectorization

3/4/2013 Program Optimization Through Loop Vectorization Program Optimization Materials for this tutorial can be found: Through Loop Vectorization http://polaris.cs.uiuc.edu/~garzaran/pldi-polv.zip María Garzarán, Saeed Maleki William Gropp and David Padua Questions? Send an email to [email protected] Department of Computer Science University of Illinois at Urbana-Champaign 2 Topics covered in this tutorial Outline • What are the microprocessor vector extensions or SIMD (Single Instruction Multiple Data Units) 1. Intro 2. Data Dependences (Definition) • How to use them 3. Overcoming limitations to SIMD-Vectorization – Through the compiler via automatic vectorization – Data Dependences • Manual transformations that enable vectorization – Data Alignment • Directives to guide the compiler – Aliasing – Through intrinsics – Non-unit strides • Main focus on vectorizing through the compiler. – Conditional Statements – Code more readable 4. Vectorization with intrinsics – Code portable 3 4 1 3/4/2013 Simple Example SIMD Vectorization • Loop vectorization transforms a program so that the • The use of SIMD units can speed up the program. same operation is performed at the same time on • Intel SSE and IBM Altivec have 128-bit vector registers and several vector elements functional units ldv vr1, addr1 – 4 32-bit single precision floating point numbers n ld r1, addr1 for (i=0; i<n; i++) n/4 ldv vr2, addr2 ld r2, addr2 – 2 64-bit double precision floating point numbers times c[i] = a[i] + b[i]; times addv vr3, vr1, vr2 add r3, r1, r2 stv vr3, addr3 – 4 32-bit integer numbers st r3, addr3 – 2 64 bit integer 32 bits – 8 16-bit integer or shorts 32 bits – 16 8-bit bytes or chars Y1 X1 • Assuming a single ALU, these SIMD units can execute 4 single precision floating point number or 2 double precision operations in Register File Scalar Unit + Vector … Unit the time it takes to do only one of these operations by a scalar unit. Z1 32 bits 5 6 Executing Our Simple Example How do we access the SIMD units? S000 • Three choices for (i=0; i<LEN; i++) for (i=0; i<n; i++) c[i] = a[i] + b[i]; c[i] = a[i] + b[i]; 1. C code and a vectorizing compiler Intel Nehalem IBM Power 7 void example(){ Exec. Time scalar code: 6.1 Exec. Time scalar code: 2.1 __m128 rA, rB, rC; Exec. Time vector code: 3.2 Exec. Time vector code: 1.0 for (int i = 0; i <LEN; i+=4){ Speedup: 1.8 Speedup: 2.1 1. Macros or Vector Intrinsics rA = _mm_load_ps(&a[i]); rB = _mm_load_ps(&b[i]); rC = _mm_add_ps(rA,rB); _mm_store_ps(&C[i], rC); 32 bits }} Y1 X 1 ..B8.5 movaps a(,%rdx,4), %xmm0 Register File Scalar Unit + Vector addps b(,%rdx,4), %xmm0 … Unit 1. Assembly Language movaps %xmm0, c(,%rdx,4) addq $4, %rdx Z1 cmpq $rdi, %rdx 32 bits jl ..B8.5 7 8 2 3/4/2013 Why should the compiler vectorize? How well do compilers vectorize? 1. Easier 2. Portable across vendors and machines Compiler XLC ICC GCC – Although compiler directives differ across compilers Loops 3. Better performance of the compiler generated code Total 159 Vectorized 74 75 32 – Compiler applies other transformations Not vectorized 85 84 127 Average Speed Up 1.73 1.85 1.30 Compilers make your codes (almost) machine independent Compiler XLC but ICC but Loops not ICC not XLC But, compilers fail: Vectorized 25 26 - Programmers need to provide the necessary information - Programmers need to transform the code 10 9 How well do compilers vectorize? How much programmer intervention? Compiler XLC ICC GCC • Next, three examples to illustrate what the programmer Loops may need to do: Total 159 – Add compiler directives Vectorized 74 75 32 – Transform the code Not vectorized 85 84 127 Average Speed Up 1.73 1.85 1.30 – Program using vector intrinsics Compiler XLC but ICC but Loops not ICC not XLC Vectorized 25 26 By adding manual vectorization the average speedup was 3.78 (versus 1.73 obtained by the XLC compiler) 11 12 3 3/4/2013 Experimental results Compiler directives • The tutorial shows results for two different platforms with their compilers: void test(float* A,float* B,float* C,float* D, float* E) { – Report generated by the compiler for (int i = 0; i <LEN; i++){ – Execution Time for each platform A[i]=B[i]+C[i]+D[i]+E[i]; } } Platform 1: Intel Nehalem Platform 2: IBM Power 7 Intel Core i7 CPU [email protected] IBM Power 7, 3.55 GHz Intel ICC compiler, version 11.1 IBM xlc compiler, version 11.0 OS Ubuntu Linux 9.04 OS Red Hat Linux Enterprise 5.4 The examples use single precision floating point numbers 13 14 Compiler directives Compiler directives S1111 S1111 S1111 S1111 void test(float* __restrict__ A, void test(float* __restrict__ A, void test(float* A, float* B, float* float* __restrict__ B, void test(float* A, float* B, float* float* __restrict__ B, C, float* D, float* E) float* __restrict__ C, C, float* D, float* E) float* __restrict__ C, { float* __restrict__ D, { float* __restrict__ D, for (int i = 0; i <LEN; i++){ float* __restrict__ E) for (int i = 0; i <LEN; i++){ float* __restrict__ E) A[i]=B[i]+C[i]+D[i]+E[i]; { A[i]=B[i]+C[i]+D[i]+E[i]; { } for (int i = 0; i <LEN; i++){ } for (int i = 0; i <LEN; i++){ } A[i]=B[i]+C[i]+D[i]+E[i]; } A[i]=B[i]+C[i]+D[i]+E[i]; } } } } S1111 S1111 S1111 S1111 Intel Nehalem Intel Nehalem Power 7 Power 7 Compiler report: Loop was not Compiler report: Loop was Compiler report: Loop was not Compiler report: Loop was vectorized. vectorized. vectorized. vectorized. Exec. Time scalar code: 5.6 Exec. Time scalar code: 5.6 Exec. Time scalar code: 2.3 Exec. Time scalar code: 1.6 Exec. Time vector code: -- Exec. Time vector code: 2.2 Exec. Time vector code: -- Exec. Time vector code: 0.6 Speedup: -- Speedup: 2.5 Speedup: -- Speedup: 2.7 15 16 4 3/4/2013 Loop Transformations Loop Transformations S136 S136_1 S136_2 for (int i=0;i<LEN;i++){ for (int i=0;i<LEN;i++) for (int i=0;i<LEN;i++) sum = (float) 0.0; sum[i] = (float) 0.0; B[i] = (float) 0.0; for (int i=0;i<LEN;i++){ for (int i=0;i<size;i++){ for (int j=0;j<LEN;j++){ for (int j=0;j<LEN;j++){ for (int j=0;j<LEN;j++){ sum = (float) 0.0; sum[i] =0; sum += A[j][i]; sum[i] += A[j][i]; B[i] += A[j][i]; for (int j=0;j<LEN;j++){ for (int j=0;j<size;j++){ } } } sum += A[j][i]; B[i] = sum; B[i]=sum[i]; } sum[i] += A[j][i]; } } } } B[i] = sum; B[i] = sum[i]; } } i S136 S136_1 S136_2 Intel Nehalem Intel Nehalem Intel Nehalem j Compiler report: Loop was not A report: Permuted loop report: Permuted loop vectorized. Vectorization was vectorized. was vectorized. possible but seems inefficient scalar code: 1.6 scalar code: 1.6 Exec. Time scalar code: 3.7 vector code: 0.6 vector code: 0.6 B Exec. Time vector code: -- Speedup: 2.6 Speedup: 2.6 Speedup: -- 17 18 Loop Transformations Intrinsics (SSE) S136 S136_1 S136_2 #define n 1024 for (int i=0;i<LEN;i++){ for (int i=0;i<LEN;i++) for (int i=0;i<LEN;i++) __attribute__ ((aligned(16))) float a[n], b[n], c[n]; sum = (float) 0.0; sum[i] = (float) 0.0; B[i] = (float) 0.0; int main() { for (int j=0;j<LEN;j++){ for (int j=0;j<LEN;j++){ for (int j=0;j<LEN;j++){ sum += A[j][i]; sum[i] += A[j][i]; B[i] += A[j][i]; for (i = 0; i < n; i++) { } } } c[i]=a[i]*b[i]; B[i] = sum; B[i]=sum[i]; } } } } } #include <xmmintrin.h> S136 S136_1 S136_2 #define n 1024 __attribute__((aligned(16))) float a[n], b[n], c[n]; IBM Power 7 IBM Power 7 IBM Power 7 report: Loop int main() { Compiler report: Loop was report: Loop interchanging applied. __m128 rA, rB, rC; interchanging applied. not SIMD vectorized Loop was SIMD for (i = 0; i < n; i+=4) { Loop was SIMD Exec. Time scalar code: 2.0 vectorized rA = _mm_load_ps(&a[i]); Exec. Time vector code: -- scalar code: 0.4 scalar code: 0.4 rB = _mm_load_ps(&b[i]); Speedup: -- vector code: 0.2 vector code: 0.16 rC= _mm_mul_ps(rA,rB); Speedup: 2.0 Speedup: 2.7 _mm_store_ps(&c[i], rC); }} 19 20 5 3/4/2013 Intrinsics (Altivec) Outline #define n 1024 1. Intro __attribute__ ((aligned(16))) float a[n],b[n],c[n]; ... for (int i=0; i<LEN; i++) 2. Data Dependences (Definition) c[i]=a[i]*b[i]; 3. Overcoming limitations to SIMD-Vectorization – Data Dependences – Data Alignment vector float rA,rB,rC,r0; // Declares vector registers r0 = vec_xor(r0,r0); // Sets r0 to {0,0,0,0} – Aliasing for (int i=0; i<LEN; i+=4){ // Loop stride is 4 rA = vec_ld(0, &a[i]); // Load values to rA – Non-unit strides rB = vec_ld(0, &b[i]); // Load values to rB – Conditional Statements rC = vec_madd(rA,rB,r0); // rA and rB are multiplied vec_st(rC, 0, &c[i]); // rC is stored to the c[i:i+3] 4. Vectorization with intrinsics } 21 22 Data dependences Definition of Dependence • A statement S is said to be data dependent on • The notion of dependence is the foundation of the process statement T if of vectorization.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    72 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us