5.3.1 Inversion de boucle

Une manière d'améliorer l'utilisation des ressources (la lecture des valeurs des matrices) est l'inversion de l'ordre des boucles, mais bien sur, pas n'importe lesquelles.

Nous allons faire une nouvelle fonction, dans laquelle nous allons inversé la boucle sur i, et la boucle sur k :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void sgemmOptim(float* r, const float* a, const float* b, size_t size){
	size_t i,j,k;
	for(i = 0; i < size*size; ++i){
		r[i] = 0.0f;
	}
	size_t jSize,kSize;
	for(j = 0; j < size; ++j){
		jSize = j*size;
		for(k = 0; k < size; ++k){
			kSize = k*size;
			for(i = 0; i < size; ++i){
				r[jSize + i] += a[jSize + k]*b[kSize + i];
			}
		}
	}
}

Pourquoi utiliser 0.0f et pas 0.0 ?

Tout simplement parce que si vous mettez 0.0, le compilateur va prendre ça comme un double et pas un float, et il fera une conversion inutile qui perdra du temps.

Et n'oubliez pas d'ajouter le prototype de cette fonction dans le fichier calcul.h, et appelez la dans la fonction main.

Recompilez (Et n'oubliez pas de revenir en -O2) :

make
-- Configuring done
-- Generating done
-- Build files have been written to: /...../build
[ 50%] Building C object CMakeFiles/libcalcul.dir/calcul.c.o
Linking C static library liblibcalcul.a
[ 50%] Built target libcalcul
[100%] Building C object CMakeFiles/optimisationsgemm.dir/main.c.o
Linking C executable optimisationsgemm
[100%] Built target optimisationsgemm

Si on exécute le programme on obtient ceci :

./optimisationsgemm 
3.716025 cy/fma

Et nous avons gagner quasiment un facteur 2, juste en inversant les boucles sur i et k, et en faisant un parcours complet de toutes les valeurs de la matrice r pour les initialisées à 0.