4.3.2.2.2 : La fonction de calcul avec des intrinsèques
Commençons avec la documentation (j'insisterai toujours) suivit de la définition de notre fonction :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
///Propagate the U and V species in the matVecVecU and matVecV
/** @param[out] outMatVecU : updated matrix U version (with vectorial neighbours)
* @param[out] outMatVecV : updated matrix V version (with vectorial neighbours)
* @param matVecVecU : input of matrix U (with vectorial neighbours)
* @param matVecV : input of matrix V (with vectorial neighbours)
* @param nbRow : number of rows of the matrices
* @param nbCol : number of columns of the matrices
* @param matBroadcastDeltaSquare : matrix of the delta square values (with broadcast neighbours)
* @param nbStencilRow : number of rows of the matrix matBroadcastDeltaSquare
* @param nbStencilCol : number of columns of the matrix matBroadcastDeltaSquare
* @param diffusionRateU : diffusion rate of the U specie
* @param diffudionRateV : diffusion rate of the V specie
* @param feedRate : rate of the process which feeds U and drains U, V and P
* @param killRate : rate of the process which converts V into P
* @param dt : time interval between two steps
*/
void grayscott_propagation(float * outMatVecU, float * outMatVecV, const float * matVecVecU, const float * matVecVecV, long nbRow, long nbCol,
const float * matBroadcastDeltaSquare, long nbStencilRow, long nbStencilCol,
float diffusionRateU, float diffusionRateV, float feedRate, float killRate, float dt)
{
|
Ici, nous n'avons pas besoin de dire au compilateur que nos pointeurs sont alignés car l'utilisation des fonction intrinsèques va le forcer à vectoriser.
Nous déterminons les
offset de notre
stencil (le nombre de couches à partir de la cellule centrale) :
1
2
|
long offsetStencilRow((nbStencilRow - 1l)/2l);
long offsetStencilCol((nbStencilCol - 1l)/2l);
|
Nous découpons nos colonnes en fonction de la taille des registres vectoriels. Dans le cas d'une matrice où les voisins sont vectoriels, le nombre de colonne sera toujours proportionnel à la taille des registres vectoriels, nous n'avons donc pas besoin de prendre en compte cela avec un calcul dit de
tail :
1
|
long nbVecCol(nbCol/PLIB_VECTOR_SIZE_FLOAT);
|
Nous initialisons des constantes vectorielles, dont certaines correspondent au scalaires passés en paramètres :
1
2
3
4
5
6
|
PRegVecf vecOne(plib_broadcast_ss(1.0f));
PRegVecf vecFeedRate(plib_broadcast_ss(feedRate));
PRegVecf vecKillRate(plib_broadcast_ss(killRate));
PRegVecf vecDiffudionRateU(plib_broadcast_ss(diffusionRateU));
PRegVecf vecDiffudionRateV(plib_broadcast_ss(diffusionRateV));
PRegVecf vecDt(plib_broadcast_ss(dt));
|
Nous bouclons sur les lignes de nos matrices pour mettre à jour toutes nos cellules. Il faut se rappeler que nous avons une première et une dernière ligne supplémentaires dans nos matrices (voir section
4.3.1) :
1
|
for(long i(1l); i < nbRow - 1l; ++i){
|
Il faut maintenant déterminer les bornes de nos calculs en ligne (voir section
4.1.1.1) :
1
2
|
long firstRowStencil(std::max(i - offsetStencilRow, 0l));
long lastRowStencil(std::min(i + offsetStencilRow + 1l, nbRow));
|
Nous bouclons sur les colonnes de nos matrices pour mettre à jour toutes nos cellules :
1
|
for(long j(0l); j < nbVecCol; ++j){
|
Il faut maintenant déterminer les bornes de nos calculs en colonne (voir section
4.1.1.1) :
1
2
|
long firstColStencil(std::max(j - offsetStencilCol, 0l));
long lastColStencil(std::min(j + offsetStencilCol + 1l, nbVecCol));
|
Définissons quelques variables temporaires (Les commentaires sont là pour rappeler la fonction scalaire) :
1
2
3
4
5
6
7
8
9
|
long stencilIndexRow(0l);
PRegVecf vecU(plib_load_ps(matVecVecU + (i*nbVecCol + j)*PLIB_VECTOR_SIZE_FLOAT));
PRegVecf vecV(plib_load_ps(matVecVecV + (i*nbVecCol + j)*PLIB_VECTOR_SIZE_FLOAT));
PRegVecf vecFullU(plib_broadcast_ss(0.0f)), vecFullV(plib_broadcast_ss(0.0f));
|
Nous devons maintenant boucler sur les lignes et les colonnes de notre
stencil :
1
2
3
|
for(long k(firstRowStencil); k < lastRowStencil; ++k){
long stencilIndexCol(0l);
for(long l(firstColStencil); l < lastColStencil; ++l){
|
Nous pouvons enfin calculer notre gradient. Les commentaires sont encore là pour aider, car l'utilisation de fonctions intrinsèques oblige à décomposer tous les calculs ce qui les rend difficiles à appréhender :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
PRegVecf vecDeltaSquare(plib_load_ps(matBroadcastDeltaSquare +
(stencilIndexRow*nbStencilCol + stencilIndexCol)*PLIB_VECTOR_SIZE_FLOAT));
PRegVecf vecKLU(plib_load_ps(matVecVecU + (k*nbVecCol + l)*PLIB_VECTOR_SIZE_FLOAT));
PRegVecf vecKLV(plib_load_ps(matVecVecV + (k*nbVecCol + l)*PLIB_VECTOR_SIZE_FLOAT));
PRegVecf vecKLUminU(plib_sub_ps(vecKLU, vecU));
PRegVecf vecKLVminV(plib_sub_ps(vecKLV, vecV));
PRegVecf vecKLUminUdMultDeltaSquare(plib_mul_ps(vecKLUminU, vecDeltaSquare));
PRegVecf vecKLVminVdMultDeltaSquare(plib_mul_ps(vecKLVminV, vecDeltaSquare));
vecFullU = plib_add_ps(vecFullU, vecKLUminUdMultDeltaSquare);
vecFullV = plib_add_ps(vecFullV, vecKLVminVdMultDeltaSquare);
|
Il ne faut pas oublier d'incrémenter les indices qui nous permettent de parcourir la matrice
matDeltaSquare] :
1
2
3
4
|
++stencilIndexCol;
}
++stencilIndexRow;
}
|
On finalise le calcul :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
PRegVecf vecUVSquare(plib_mul_ps(vecU, plib_mul_ps(vecV, vecV)));
PRegVecf vecOneMinusU(plib_sub_ps(vecOne, vecU));
PRegVecf vecFeedPlusKill(plib_add_ps(vecFeedRate, vecKillRate));
PRegVecf vecDiffFullU(plib_mul_ps(vecDiffudionRateU, vecFullU));
PRegVecf vecDiffFullV(plib_mul_ps(vecDiffudionRateV, vecFullV));
PRegVecf vecFeedRateMultOneMinusU(plib_mul_ps(vecFeedRate, vecOneMinusU));
PRegVecf vecFeedPlusKillMultV(plib_mul_ps(vecFeedPlusKill, vecV));
PRegVecf vecDiffFullUMinusUVSquare(plib_sub_ps(vecDiffFullU, vecUVSquare));
PRegVecf vecDiffFullVPlusUVSquare(plib_add_ps(vecDiffFullV, vecUVSquare));
PRegVecf vecDu(plib_add_ps(vecDiffFullUMinusUVSquare, vecFeedRateMultOneMinusU));
PRegVecf vecDv(plib_sub_ps(vecDiffFullVPlusUVSquare, vecFeedPlusKillMultV));
|
Et on sauvegarde le résultat :
1
2
3
4
5
6
7
8
9
10
11
|
PRegVecf vecDuDt(plib_mul_ps(vecDu, vecDt));
PRegVecf vecDvDt(plib_mul_ps(vecDv, vecDt));
PRegVecf vecUPlusDuDt(plib_add_ps(vecU, vecDuDt));
PRegVecf vecVPlusDvDt(plib_add_ps(vecV, vecDvDt));
plib_store_ps(outMatVecU + (i*nbVecCol + j)*PLIB_VECTOR_SIZE_FLOAT, vecUPlusDuDt);
plib_store_ps(outMatVecV + (i*nbVecCol + j)*PLIB_VECTOR_SIZE_FLOAT, vecVPlusDvDt);
|
Fin des deux boucles sur les lignes et les colonnes :
Fin de la fonction :