mirror of
https://github.com/clearlinux/clear-linux-documentation.git
synced 2026-07-10 22:55:54 +00:00
Add the FMV tutorial content.
The Function Multi-versioning tutorial content was provided by Victor Rodriguez. This version has been edited and the markup fixed to comply with the documentation repo's guidelines. Signed-off-by: Rodrigo Caballero <rodrigo.caballero.abraham@intel.com>
This commit is contained in:
@@ -0,0 +1,268 @@
|
||||
.. _fmv:
|
||||
|
||||
Use the Function Multi Version patch generator
|
||||
##############################################
|
||||
|
||||
CPU architectures often gain interesting new instructions as they evolve but
|
||||
application developers find it difficult to take advantage of those
|
||||
instructions. The reluctance to lose backward-compatibility is one of the
|
||||
main roadblocks slowing developers from using advancements in newer computing
|
||||
architectures. :abbr:`FMV (Function multi-versioning)`, which first appeared
|
||||
in GCC 4.8, is a way to have multiple implementations of a function, each
|
||||
using a different architecture's specialized instruction-set extensions. GCC
|
||||
6 introduces changes to FMV to make it even easier to bring architecture-
|
||||
based optimizations to the application code.
|
||||
|
||||
In this tutorial we will use FMV on general code and on :abbr:`FFT Fast
|
||||
Fourier Transform` library code. Upon completing the tutorial, you will be
|
||||
able to use this technology on your code and use the libraries to deploy
|
||||
architecture-based optimizations to your application code.
|
||||
|
||||
Install and configure a Clear Linux host on bare metal
|
||||
******************************************************
|
||||
|
||||
First, follow our guide to :ref:`bare-metal-install`.
|
||||
|
||||
Once the bare metal installation and initial configuration are complete,
|
||||
add the `desktop-dev` bundle to the system.
|
||||
|
||||
desktop-dev: contains the necessary development tools like GCC\* and Perl\*.
|
||||
|
||||
To install the bundles, run the following command in the :file:`$HOME`
|
||||
directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo swupd bundle-add desktop-dev
|
||||
|
||||
Detect loop vectorization candidates
|
||||
************************************
|
||||
|
||||
Now, we need to detect the loop vectorization candidates to be cloned for
|
||||
multiple platforms with FMV. As an example, we will use the following
|
||||
simple C code:
|
||||
|
||||
.. code-block:: c
|
||||
:linenos:
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#define MAX 1000000
|
||||
|
||||
int a[256], b[256], c[256];
|
||||
|
||||
void foo(){
|
||||
int i,x;
|
||||
for (x=0; x<MAX; x++){
|
||||
for (i=0; i<256; i++){
|
||||
a[i] = b[i] + c[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(){
|
||||
foo();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Save the example code as :file:`example.c` and build with the
|
||||
following flags:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
gcc -O3 -fopt-info-vec example.c -o example
|
||||
|
||||
The build generates the following output:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
example.c:11:9: note: loop vectorized
|
||||
example.c:11:9: note: loop vectorized
|
||||
|
||||
The output shows that line 11 is a good candidate for vectorization:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
for (i=0; i<256; i++){
|
||||
a[i] = b[i] + c[i];
|
||||
|
||||
Generate the FMV patch
|
||||
**********************
|
||||
|
||||
To generate the FMV patch with the `make-fmv-patch`_ project, we
|
||||
must clone the project and generate a log file with the loop vectorized
|
||||
information:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/clearlinux/make-fmv-patch.git
|
||||
gcc -O3 -fopt-info-vec example.c -o example &> log
|
||||
|
||||
To generate the patch files, execute:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
perl ./make-fmv-patch/make-fmv-patch.pl log .
|
||||
|
||||
The make-fmv-patch.pl take two arguments: <buildlog> and <sourcecode>. Replace with the proper values and execute:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
perl make-fmv-patch.pl <buildlog> <sourcecode>
|
||||
|
||||
The command generates the following :file:`example.c.patch` patch:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
--- ./example.c 2017-09-27 16:05:42.279505430 +0000
|
||||
+++ ./example.c~ 2017-09-27 16:19:11.691544026 +0000
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
int a[256], b[256], c[256];
|
||||
|
||||
+__attribute__((target_clones("avx2","arch=atom","default")))
|
||||
void foo(){
|
||||
int i,x;
|
||||
for (x=0; x<MAX; x++){
|
||||
|
||||
The `make-fmv-patch` is recommended to add the attribute generating the
|
||||
target clones on the function foo. Thus, we can have the following code:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#define MAX 1000000
|
||||
|
||||
int a[256], b[256], c[256];
|
||||
|
||||
__attribute__((target_clones("avx2","arch=atom","default")))
|
||||
void foo(){
|
||||
int i,x;
|
||||
for (x=0; x<MAX; x++){
|
||||
for (i=0; i<256; i++){
|
||||
a[i] = b[i] + c[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(){
|
||||
foo();
|
||||
return 0;
|
||||
}
|
||||
|
||||
By changing the value of the `$avx2` variable, we can change the target clones when adding the patches or in the make-fmv-patch.pl script:
|
||||
|
||||
.. code-block:: perl
|
||||
|
||||
my $avx2 = '__attribute__((target_clones("avx2","arch=atom","default")))'."\n";
|
||||
|
||||
Compile the code again with FMV and add the option to analyze the `objdump`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
gcc -O3 example.c -o example -g
|
||||
objdump -S example | less
|
||||
|
||||
You can see the multiple clones of the foo function:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
foo
|
||||
foo.avx2.0
|
||||
foo.arch_atom.1
|
||||
|
||||
The cloned functions use AVX2 registers and vectorized instructions. You can verify this with:
|
||||
|
||||
.. code-block:: assembly
|
||||
|
||||
vpaddd (%r8,%rax,1),%ymm0,%ymm0
|
||||
vmovdqu %ymm0,(%rcx,%rax,1)
|
||||
|
||||
FTT project example
|
||||
*******************
|
||||
|
||||
To follow the same approach with a package like FFT, we must get the build log file with the `-fopt-info-vec` flag:
|
||||
|
||||
::
|
||||
|
||||
~/make-fmv-patch/make-fmv-patch.pl results/build.log fftw-3.3.6-pl2/
|
||||
|
||||
patching fftw-3.3.6-pl2/libbench2/verify-lib.c @ lines (36 114 151 162 173 195 215 284)
|
||||
patching fftw-3.3.6-pl2/tools/fftw-wisdom.c @ lines (150)
|
||||
patching fftw-3.3.6-pl2/libbench2/speed.c @ lines (26)
|
||||
patching fftw-3.3.6-pl2/tests/bench.c @ lines (27)
|
||||
patching fftw-3.3.6-pl2/libbench2/util.c @ lines (181)
|
||||
patching fftw-3.3.6-pl2/libbench2/problem.c @ lines (229)
|
||||
patching fftw-3.3.6-pl2/tests/fftw-bench.c @ lines (101 147 162 249)
|
||||
patching fftw-3.3.6-pl2/libbench2/mp.c @ lines (79 190 215)
|
||||
patching fftw-3.3.6-pl2/libbench2/caset.c @ lines (5)
|
||||
patching fftw-3.3.6-pl2/libbench2/verify-r2r.c @ lines (44 187 197 207 316 333 723)
|
||||
|
||||
Thus, files like :file:`fftw-3.3.6-pl2/tools/fftw-wisdom.c.patch` generate
|
||||
patches like:
|
||||
|
||||
.. code-block:: git
|
||||
|
||||
1 --- fftw-3.3.6-pl2/libbench2/verify-lib.c 2017-01-27 21:08:13.000000000 +0000
|
||||
2 +++ fftw-3.3.6-pl2/libbench2/verify-lib.c~ 2017-09-27 17:49:21.913802006 +0000
|
||||
3 @@ -33,6 +33,7 @@
|
||||
4
|
||||
5 double dmax(double x, double y) { return (x > y) ? x : y; }
|
||||
6
|
||||
7 +__attribute__((target_clones("avx2","arch=atom","default")))
|
||||
8 static double aerror(C *a, C *b, int n)
|
||||
9 {
|
||||
10 if (n > 0) {
|
||||
11 @@ -111,6 +112,7 @@
|
||||
12 }
|
||||
13
|
||||
14 /* make array hermitian */
|
||||
15 +__attribute__((target_clones("avx2","arch=atom","default")))
|
||||
16 void mkhermitian(C *A, int rank, const bench_iodim *dim, int stride)
|
||||
17 {
|
||||
18 if (rank == 0)
|
||||
19 @@ -148,6 +150,7 @@
|
||||
20 }
|
||||
21
|
||||
22 /* C = A + B */
|
||||
23 +__attribute__((target_clones("avx2","arch=atom","default")))
|
||||
24 void aadd(C *c, C *a, C *b, int n)
|
||||
25 {
|
||||
26 int i;
|
||||
27 @@ -159,6 +162,7 @@
|
||||
28 }
|
||||
29
|
||||
30 /* C = A - B */
|
||||
31 +__attribute__((target_clones("avx2","arch=atom","default")))
|
||||
32 void asub(C *c, C *a, C *b, int n)
|
||||
33 {
|
||||
34 int i;
|
||||
35 @@ -170,6 +174,7 @@
|
||||
36 }
|
||||
37
|
||||
38 /* B = rotate left A (complex) */
|
||||
39 +__attribute__((target_clones("avx2","arch=atom","default")))
|
||||
40 void arol(C *b, C *a, int n, int nb, int na)
|
||||
41 {
|
||||
42 int i, ib, ia;
|
||||
43 @@ -192,6 +197,7 @@
|
||||
44 }
|
||||
45 }
|
||||
|
||||
With these patches, we can select where to apply the FMV technology making
|
||||
bringing architecture-based optimizations to application code even easier.
|
||||
|
||||
**Congratulations! **
|
||||
|
||||
You have successfully installed an FMV development environment on Clear
|
||||
Linux. Furthermore, you used cutting edge compiler technology to improve the
|
||||
performance of your application based on Intel Architecture technology and
|
||||
profiling of the specific execution of your application.
|
||||
|
||||
|
||||
.. _make-fmv-patch: https://github.com/clearlinux/make-fmv-patch
|
||||
@@ -14,3 +14,4 @@ specific |CLOSIA| use cases.
|
||||
machine-learning/machine-learning
|
||||
azure
|
||||
multi-boot/multi-boot
|
||||
fmv
|
||||
|
||||
Reference in New Issue
Block a user