Vectorization Example Using SSE/SSE2 Instructions. STMicroelectronics PGI
જાહેરાત
જાહેરાત
Vectorization using –Mvect introduced on Pentium 4, Xeon and Opteron processors, operate on double-precision floating-point data.
Prefetch instructions, first introduced on Pentium III and AthlonXP processors, can be used to improve the performance of vectorizable loops that operate on either 32-bit or 64-bit floating-point data. Refer to the PGI
Release Notes for a concise list of processors that support SSE, SSE2 and prefetch instructions.
Note
Program units compiled with
–Mvect=sse
will not execute on Pentium, Pentium Pro, Pentium II or first generation AMD Athlon processors. They will only execute correctly on Pentium III, Pentium 4,
Xeon, EM64T, AthlonXP, Athlon64 and Opteron systems running an SSE-enabled operating system.
Prefetch Option
The option
–Mvect=prefetch
instructs the vectorizer to automatically generate prefetch instructions when vectorizable loops are encountered, even in cases where SSE or SSE2 instructions are not generated. Usually, explicit prefetching is not necessary on Pentium 4, Xeon and Opteron because these processors support hardware prefetching; nonetheless, it sometimes can be worthwhile to experiment with explicit prefetching.
Prefetching can be controlled on a loop-by-loop level using prefetch directives, which are described in detail
in “Prefetch Directives and Pragmas,” on page 111
.
Note
Program units compiled with
–Mvect=prefetch
will not execute correctly on Pentium, Pentium
Pro, or Pentium II processors. They will execute correctly only on Pentium III, Pentium 4, Xeon,
EM64T, AthlonXP, Athlon64 or Opteron systems. In addition, the prefetch
instruction is only supported on AthlonXP, Athlon64 or Opteron systems and can cause instruction faults on non-AMD processors. For this reason, the PGI compilers do not generate prefetch
instructions by default on any target.
In addition to these sub-options to
–Mvect
, several other sub-options are supported. Refer to the description of
–M
[no]vect
Command-Line Options Reference
for a detailed description of all available sub-options.
Vectorization Example Using SSE/SSE2 Instructions
One of the most important vectorization options is
-Mvect=sse
. When you use this option, the compiler automatically generates SSE and SSE2 instructions, where possible, when targeting processors on which these instructions are supported. This process can improve performance by up to a factor of two compared with the equivalent scalar code. All of the PGI Fortran, C and C++ compilers support this capability. The PGI Release
Notes show which x86 and x64 processors support these instructions.
Prior to release 7.0,
-Mvect=sse
was omitted from the compiler switch
-fast
but was included in the switch
-fastsse
. Since release 7.0 ,
-fast
is synonymous with
-fastsse
; therefore, both options include
-Mvect=sse
.
In the program in Example 3.3, “Vector operation using SSE instructions” , the vectorizer recognizes the vector operation in subroutine 'loop' when either the compiler switch
-Mvect=sse
or
-fast
is used. This example shows the compilation, informational messages, and run-time results using the SSE instructions on an AMD
Opteron processor-based system, along with issues that affect SSE performance.
32
Chapter 3. Optimizing & Parallelizing
First note that the arrays in Example 3.3
are single-precision and that the vector operation is done using a unit stride loop. Thus, this loop can potentially be vectorized using SSE instructions on any processor that supports SSE or SSE2 instructions. SSE operations can be used to operate on pairs of single-precision floatingpoint numbers, and do not apply to double-precision floating-point numbers. SSE2 instructions can be used to operate on quads of single-precision floating-point numbers or on pairs of double-precision floating-point numbers.
Loops vectorized using SSE or SSE2 instructions operate much more efficiently when processing vectors that are aligned to a cache-line boundary. You can cause unconstrained data objects of size 16 bytes or greater to be cache-aligned by compiling with the
–Mcache_align
switch. An unconstrained data object is a data object that is not a common block member and not a member of an aggregate data structure.
Note
For stack-based local variables to be properly aligned, the main program or function must be compiled with
–Mcache_align
.
The
–Mcache_align
switch has no effect on the alignment of Fortran allocatable or automatic arrays. If you have arrays that are constrained, such as vectors that are members of Fortran common blocks, you must specifically pad your data structures to ensure proper cache alignment. You can use
–Mcache_align
for only the beginning address of each common block to be cache-aligned.
The following examples show the results of compiling the sample code in Example 3.3
both with and without the option
–Mvect=sse
.
Example 3.3. Vector operation using SSE instructions program vector_op
parameter (N = 9999)
real*4 x(N), y(N), z(N), W(N)
do i = 1, n
y(i) = i
z(i) = 2*i
w(i) = 4*i
enddo
do j = 1, 200000
call loop(x,y,z,w,1.0e0,N)
enddo
print *, x(1),x(771),x(3618),x(6498),x(9999) end subroutine loop(a,b,c,d,s,n)
integer i, n
real*4 a(n), b(n), c(n), d(n),s
do i = 1, n
a(i) = b(i) + c(i) - s * d(i)
enddo end
Assume the preceding program is compiled as follows, where
-Mvect=nosse
disables SSE vectorization:
% pgf95 -fast -Mvect=nosse -Minfo vadd.f
vector_op:
4, Loop unrolled 4 times
loop:
18, Loop unrolled 4 times
33
Vectorization using –Mvect
34
The following output shows a sample result if the generated executable is run and timed on a standalone AMD
Opteron 2.2 Ghz system:
% /bin/time vadd
-1.000000 -771.000 -3618.000 -6498.00 -9999.00
5.39user 0.00system 0:05.40elapsed 99%CP
Now, recompile with SSE vectorization enabled, and you see results similar to these:
% pgf95 -fast -Minfo vadd.f -o vadd
vector_op:
4, Unrolled inner loop 8 times
Loop unrolled 7 times (completely unrolled)
loop:
18, Generated 4 alternate loops for the inner loop
Generated vector sse code for inner loop
Generated 3 prefetch instructions for this loop
Notice the informational message for the loop at line 18.
• The first two lines of the message indicate that the loop was vectorized, SSE instructions were generated, and four alternate versions of the loop were also generated. The loop count and alignments of the arrays determine which of these versions is executed.
• The last line of the informational message indicates that prefetch instructions have been generated for three loads to minimize latency of data transfers from main memory.
Executing again, you should see results similar to the following:
% /bin/time vadd
-1.000000 -771.000 -3618.00 -6498.00
-9999.0
3.59user 0.00system 0:03.59elapsed 100%CPU
The result is a 50% speed-up over the equivalent scalar, that is, the non-SSE, version of the program.
Speed-up realized by a given loop or program can vary widely based on a number of factors:
• When the vectors of data are resident in the data cache, performance improvement using vector SSE or SSE2 instructions is most effective.
• If data is aligned properly, performance will be better in general than when using vector SSE operations on unaligned data.
• If the compiler can guarantee that data is aligned properly, even more efficient sequences of SSE instructions can be generated.
• The efficiency of loops that operate on single-precision data can be higher. SSE2 vector instructions can operate on four single-precision elements concurrently, but only two double-precision elements.
Note
Compiling with
–Mvect=sse
can result in numerical differences from the executables generated with less optimization. Certain vectorizable operations, for example dot products, are sensitive to order of operations and the associative transformations necessary to enable vectorization (or parallelization).
ડાઉનલોડ કરો
જાહેરાત