The presentation can be downloaded here.
(рис 5.1) The trend in the microprocessor development
Different kinds of parallel:
An
(рис 5.2) Vectorization is an example of data parallelism (SIMD)
(рис 5.3) The approximate scheme of the loop vectorization
A
Vectorization is a
Such optimization can be also performed manually by developer.
A (1: n: k) - section of the array in Fortran is very
(рис 5.4)
MMX is a single instruction, multiple data (SIMD)
MMX (Multimedia Extensions) is a set of instructions perform specific actions for
MMX is:
MMX provides only
Streaming SIMD Extensions (SSE) is a SIMD
SSE is:
Advanced Vector Extensions (AVX) is an extension of the x86
AVX provides new features, new instructions and a new
The size of
The existing 128-bit instructions use the lower half of YMM registers.
| | Bits per element | Data type range | |
|---|---|---|---|
| signed bytes | 16 | 8 | -2**7 to 2**7-1 |
| unsigned bytes | 16 | 8 | 0 до 2**8-1 |
| signed words | 8 | 16 | -2**15 to 2**15-1 |
| unsigned words | 8 | 16 | 0 до 2**16 |
| signed | 4 | 32 | -2**31 to 2**31-1 |
| unsigned | 4 | 32 | 0 до 2**32-1 |
| signed quadwords | 2 | 64 | -2**63 to 2*63-1 |
| unsigned quadwords | 2 | 64 | 0 до 2**64-1 |
| 4 | 32 | 2**-126 to 2**127 | |
| double-precision fps | 2 | 64 | 2**-1022 to 2**1023 |
Selecting the
(рис 5.5) SIMD – SSE, SSE2, SSE3, SSE4.2 Support
| Instruction | Suffix | Description |
|---|---|---|
| move | ||
| move | ||
mova | [ ps, pd ] | move floating-point aligned |
movu | [ ps, pd ] | move floating-point unaligned |
movhl | [ ps ] | move packed floating-point high to low |
movlh | [ ps ] | move packed floating-point low to high |
movh | [ ps, pd ] | move high packed floating-point |
movl | [ ps, pd ] | move low packed floating-point |
mov | [ d, q, ss, sd ] | move scalar data |
| load | ||
| move and duplicate | ||
pextr | [ w ] | extract word |
pinstr | [ w ] | insert word |
pmovmsk | [ b ] | move mask |
movmsk | [ ps, pd ] | move mask |
An aligned data movement instruction cannot be applied to the
| Instruction | Suffix | Description |
|---|---|---|
padd | [ b, w, d, q ] | packed addition (signed and unsigned) |
psub | [ b, w, d, q ] | packed subtraction (signed and unsigned) |
padds | [ b, w ] | packed addition with saturation (signed) |
paddus | [ b, w ] | packed addition with saturation (unsigned) |
psubs | [ b, w ] | packed subtraction with saturation (signed) |
psubus | [ b, w ] | packed subtraction with saturation (unsigned) |
pmins | [ w ] | packed minimum (signed) |
pminu | [ b ] | packed minimum (unsigned) |
pmaxs | [ w ] | packed maximum (signed) |
pmaxu | [ b ] | packed maximum (unsigned) |
| Instruction | Suffix | Description |
|---|---|---|
add | [ ss, ps, sd, pd ] | addition |
div | [ ss, ps, sd, pd ] | division |
min | [ ss, ps, sd, pd ] | minimum |
max | [ ss, ps, sd, pd ] | maximum |
mul | [ ss, ps, sd, pd ] | multiplication |
sqrt | [ ss, ps, sd, pd ] | |
sub | [ ss, ps, sd, pd ] | subtraction |
| [ ss, ps] | approximated |
rsqrt | [ ss, ps] | approximated |
| Instruction | Suffix | Description |
|---|---|---|
pang | [ b, w ] | packed average with rounding (unsigned) |
pmulh/pmulhu/pmull | [ w ] | packed multiplication |
psad | [ bw ] | packed sum of absolute differences (unsigned) |
pmadd | [ wd ] | packed multiplication and addition (signed) |
addsub | [ ps, pd ] | floating-point addition/subtraction |
hadd | [ ps, pd ] | floating-point horizontal addition |
hsub | [ ps, pd ] | floating-point horizontal subtraction |
| Instruction | Suffix | Description |
|---|---|---|
AND | ||
AND-NOT | ||
OR | ||
XOR | ||
and | [ ps, pd ] | AND |
andn | [ ps, pd ] | AND-NOT |
or | [ ps, pd ] | OR |
xor | [ ps, pd ] | XOR |
| Instruction | Suffix | Description |
|---|---|---|
pcmp<cc> | [ b, w, d ] | packed compare |
cmp<cc> | [ ss, ps, sd, pd ] | floating-point compare |
<cc> defines
lt – less, gt – greater, eq - equal
| Instruction | Suffix | Description |
|---|---|---|
packss | [wb, dw] | pack with saturation (signed) |
paсkus | [wb] | pack with saturation (unsigned) |
| conversion | ||
| conversion with truncation |
| Instruction | Suffix | Description |
|---|---|---|
psll | [ w, d, q, dq ] | |
psra | [w, d] | shift right arithmetic (sign in) |
psrl | [ w, d, q, dq ] | shift right logical (zero in) |
| Instruction | Suffix | Description |
|---|---|---|
pshuf | [ w, d ] | packed shuffle |
pshufh | [w] | packed shuffle high |
pshufl | [w] | packed shuffle low |
ырга | [ ps, pd ] | shuffle |
| Instruction | Suffix | Description |
|---|---|---|
punpckh | [bw, wd, dq, qdq] | |
punpckl | [bw, wd, dq, qdq] | |
unpckh | [ps, pd] | |
unpckl | [ps, pd] |
| Instruction | Suffix | Description |
|---|---|---|
movnt | [ ps, pd, q, dq ] | move aligned non- |
State management instructions
These instructions are commonly used by operating system.
A
Description of the foundations of SSE technology can be found in CHAPTER 10 PROGRAMMING WITH STREAMING SIMD EXTENSIONS (SSE) of the document "Intel 64 and IA-32 Intel Architecture Software Developer's Manual" (Volume 1)
Microsoft Visual Studio supports a set of SSE intrinsics that allows you to use SSE instructions directly from C/C++ code. You need to include xmmintrin.h, which defines the vector type __m128 and
For example, we need to vectorize manually the following loop:
for(i=0;i<N;i++) C[i]=A[i]*B[i];
To do this:
#include <stdio.h>
#include <xmmintrin.h>
#define N 40
int main() {
float a[N][N][N],b[N][N][N],c[N][N][N];
int i,j,k,rep; __m128 *xa,*xb,*xc;
for(i=0;i< N;i++)
for(j=0;j< N;j++)
for(k=0;k< N;k++) {
a[i][j][k]=1.0; b[i][j][k]=2.0; }
for(rep=0;rep<10000;rep++) {
#ifdef PERF
for(i=0;i<N;i++)
for(j=0;j<N;j++)
for(k=0;k<N;k+=4) {
xa=(__m128*)(a[i][j][k]); xb=(__m128*)(b[i][j][k]); xc=(__m128*)(c[i][j][k]);
*xc=_mm_mul_ps(*xa,*xb); }
#else
for(i=0;i< N;i++)
for(j=0;j< N;j++)
for(k=0;k<N;k++)
c[i][j][k]=a[i][j][k]*b[i][j][k];
#endif
}
printf("%f\n",c[21][11][18])
}
An example illustrating the vectorization with SSE intrinsics
icl -Od test.c -Fetest1.exe icl -Od test.c -DPERF -Fetest_opt.exe time test1.exe 2.000000
'test1.exe'
real 3.406 sec user 3.391 sec system 0.000 sec time test_opt.exe 2.000000
'test_opt.exe'
real 1.281 sec user 1.250 sec system 0.000 sec
Intel compiler 12.0 was used for this experiment
The resulting
We used aligned by 16 memory access instructions in this example. Alignment was matched
Test-
icl test.c-Qvec_report3-Fetest_intel_opt.exe time test_intel_opt.exe 2.000000
'test_intel_opt.exe'
real 0.328 sec user 0.313 sec system 0.000 sec
Vectorization is a
The simplest case when there are no dependencies inside the processed loop.
In more complicated case there are dependences inside the vectorized loop but its order is the same as inside the initial scalar loop.
Let’s
There is a loop dependency between the statements S1 and S2 in the set of
i and j such that i <j or i = j and there is a path from S1 to S2 inside the loopS1 for iteration i and statement S2 for iteration j refer to the same memory area./Qvec-report[n]
control amount of vectorizer diagnostic information
n=0 no diagnostic informationn=1 indicate vectorized loops (DEFAULT)n=2 indicate vectorized/non-vectorized loopsn=3 indicate vectorized/non-vectorized loops and n=4 indicate non-vectorized loopsn=5 indicate non-vectorized loops and Usage: icl -c -Qvec_report3 loop.c
Diagnostic examples:
Let’s write vectorization of loop with usage of fortran array sections.
A good
(рис 5.6)
There is dependency because A(I+1:I+1+VL) on iteration I and A(I+VL:I+2*VL) for I+1 are intersected.
(рис 5.7)
There is no dependency because A(I-1:I-1+VL) on iteration I and A(I+VL:I+2*VL) for I+1 aren’t intersected.
PROGRAM TEST_VEC INTEGER,PARAMETER :: N=1000 #ifdef PERF INTEGER,PARAMETER :: P=4 #else INTEGER,PARAMETER :: P=3 #endif INTEGER A(N) DO I=1,N-P A(I+P)=A(I) END DO PRINT *,A(50) END
Let’s check an
Loop can be vectorized, if the dependence distance greater or equal to number of
Check this with compiler:
ifort test.F90 -o a.out –vec_report3 echo ------------------------------------- ifort test.F90 -DPERF -o b.out –vec_report3 ./build.sh test.F90(11): (col. 1) remark: loop was not vectorized: existence of vector dependence. ------------------------------------- test.F90(11): (col. 1) remark: LOOP WAS VECTORIZED.
There are two tasks which compiler should perform for dependency evaluation:
Compiler should
There are methods of providing additional information to the compiler:
–ansi_alias (the pointers can refer only to the objects of the same or compatible type).restrict attributes for pointer arguments (C/C++).#pragma ivdep says that there are not dependencies in the following loop. (C/C++)!DEC$ IVDEP Fortran #pragma ivdepINTEGER :: A(1000),B(1000) INTEGER I,K INTEGER, PARAMETER :: REP = 500000 A = 2 DO K=1,REP CALL ADD(A,B) END DO PRINT *,SHIFT,B(101) CONTAINS SUBROUTINE ADD(A,B) INTEGER A(1000),B(1000) INTEGER I !DEC$ UNROLL(0) DO I=1,1000-SHIFT B(I) = A(I+SHIFT)+1 END DO END SUBROUTINE END
Let’s consider some simple test with a assignment which is SHIFT macro.
/fpp – option for 2 or 3. (-O2 or -O3)
Option –Ob0 is used to forbid inlining.
Experiment results
ifort test1.F90 -O2 -Ob0 /fpp /DSHIFT=0 -Fea.exe -Qvec_report >a.out 2>1 ifort test1.F90 -O2 -Ob0 /fpp /DSHIFT=1 -Feb.exe -Qvec_report >b.out 2>1 time.exe a.exe 0 3 CPU time for command: 'a.exe' real 0.125 sec user 0.094 sec system 0.000 sec time.exe b.exe 1 3 CPU time for command: 'b.exe' real 0.297 sec user 0.281 sec system 0.000 sec
ifort test1.F90 -O2 -Ob0 /fpp /DSHIFT=0 /Fas -Ob0 -S –Fafast.s
fast.s
.B2.5: ; Preds .B2.5 .B2.4
$LN83:
;;; B(I) = A(I+SHIFT)+1
movdqa xmm1, XMMWORD PTR [eax+ecx*4] ;17.11
$LN84:
paddd xmm1, xmm0 ;17.4
$LN85:
movdqa XMMWORD PTR [edx+ecx*4], xmm1 ;17.4
$LN86:
add ecx, 4 ;16.3
$LN87:
cmp ecx, 1000 ;16.3
$LN88:
jb .B2.5 ; Prob 99% ;16.3
ifort test1.F90 -O2 -Ob0 /fpp /DSHIFT=1 /Fas -Ob0 -S –Faslow.s
slow.s
.B2.5: ; Preds .B2.5 .B2.4
$LN81:
;;; B(I) = A(I+SHIFT)+1
movdqu xmm1, XMMWORD PTR [4+eax+ecx*4] ;17.11
$LN82:
paddd xmm1, xmm0 ;17.4
$LN83:
movdqa XMMWORD PTR [edx+ecx*4], xmm1 ;17.4
$LN84:
add ecx, 4 ;16.3
$LN85:
cmp ecx, 996 ;16.3
$LN86:
jb .B2.5 ; Prob 99% ;16.3
CONCLUSION:
MOVDQA—Move Aligned
MOVDQU—Move Unaligned
In fast version aligned instructions are used and
Unaligned instructions are slower. For latest architectures they shows the same performance as aligned instructions if applied to the aligned data.
Performance of vectorized loop depends on the
Filling data structures involves insertion of unnamed fields into the
Information about the alignment can be obtained with __alignof__. The size and the default alignment of the variable of a type may depend on the compiler. (ia32 or intel64)
printf("int: sizeof=%d align=%d\n",sizeof(a),__alignof__(a));
Alignment for ia32 Intel C++ compiler:
bool sizeof = 1 alignof = 1 wchar_t sizeof = 2 alignof = 2 short int sizeof = 2 alignof = 2 int sizeof = 4 alignof = 4 long int sizeof = 4 alignof = 4 long long int sizeof = 8 alignof = 8 float sizeof = 4 alignof = 4 double sizeof = 8 alignof = 8 long double sizeof = 8 alignof = 8 void* sizeof = 4 alignof = 4
The same rules are used for array alignment.
There is the possibility to force the compiler to align object in a certain way:
__declspec(align(16)) float x[N];
(рис 5.8) Data Structure Alignment
The order of fields in the structure affects the size of the object of a __declspec to align structure fields.
typedef struct aStuct{
__declspec(align(16)) float x[N];
__declspec(align(16)) float y[N];
__declspec(align(16)) float z[N];
};
(рис 5.9) The approximate scheme of the loop vectorization
Vector.c
void Calculate(float * a,float * b,
float * c , int n) {
int i;
for(i=0;i<n;i++) {
a[i] = a[i]+b[i]+c[i];
}
return;
}
First argument alignment differs
Main.c
#include <stdio.h>
#define N 1000
extern void Calculate(float *,float *, float *,int);
int main() {
float x[N],y[N],z[N];
int i,rep;
for(i=0;i<N;i++) {
x[i] = 1;y[i] = 0; z[i] = 1;
}
for(rep=0;rep<10000000;rep++) {
Calculate(x[1],y[0],z[0],N-1);
}
printf("x[1]=%f\n",x[1]);
}
icl main.c vec.c -O1 –FeA
time a.exe 12.6 s.
–O2 or –O3.
Option -Qvec_report informs about vectorized loops. icl main.c vec.c –O2 –Qvec_report –Feb vec.c(3): (col. 3) remark: LOOP WAS VECTORIZED. time b.exe 3.67 s.
Vectorization is possible because the compiler inserts run-time check for vectorizing when some of the pointers may be not aliased. The application size is
void Calculate(float * resrtict a,float * restrict b, float * restrict c , int n) {
To restrict align attribute we need to add option –Qstd=c99
icl main.c vec.c –Qstd=c99 –O2 –Qvec_report –Fec vec.c(3): (col. 3) remark: LOOP WAS VECTORIZED. time c.exe 3.55 s.
Small improvement because of avoiding run-time check
Useful fact: For modern calculation
int main() {
__declspec(align(16)) float x[N];
__declspec(align(16)) float y[N];
__declspec(align(16)) float z[N];
Calculate(x[0],y[0],z[0],N-1);
void Calculate (float * resrtict a,float * restrict b, float * restrict c , int n) {
Int n;
__assume_aligned(a,16);
__assume_aligned(b,16);
__assume_aligned(c,16);
icl main.c vec.c –Qstd=c99 –O2 –Qvec_report –Fed
vec.c(3): (col. 3) remark: LOOP WAS VECTORIZED.
time d.exe 3.20 s.
This update __assume_aligned directive. It allows to remove the first scalar loop.
Good array
__declspec(align(16)) float X[N];float X[N] __attribute__ ((aligned (16));!DIR$ ATTRIBUTES ALIGN: 16:: A_aligned_malloc()_mm_malloc()__assume_aligned(p,16);!DIR$ ASSUME_ALIGNED A(1):16#pragma vector aligned!DIR$ VECTOR ALIGNEDWell aligned data is better for vectorization because in this case
Auto vectorizer cooperates with
There are
C/C++
#pragma vector{aligned|unaligned|always}
#pragma novector
Fortran
!DEC$ VECTOR ALWAYS !DEC$ NOVECTOR
Usually auto
#define N 200
#include<stdio.h>
int main() {
int A[N][N],B[N][N],C[N][N];
int i,j,rep;
for(i=0;i<N;i++)
for(j=0;j<N;j++) {
A[i][j]=i+j;
B[i][j]=2*j-i;
C[i][j]=0;
}
for(rep=0;rep<10000000;rep++) {
#pragma simd
for(i=0;i<N;i++) {
j=0;
while(A[i][j]<=B[i][j] j<N) {
C[i][j]=C[i][j]+B[j][i]-A[j][i];
j++;
}
}
}
printf("%d\n"C[0][2]);
}
icl vec.c -O3 -Qvec- -Fea (Qvec- disable vectorization) 20.7 s icl vec.c -O3 -Qvec_report -Feb 17.s vec.c(17): (col. 3) remark: SIMD LOOP WAS VECTORIZED.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.