• Aucun résultat trouvé

CHAPITRE 3 MODÈLE PROPOSÉ

3.1 Méthodologie

Le modèle proposé dans ce chapitre permet de calculer le nombre d’accès à la mémoire en effec- tuant une analyse du code ainsi que de la matrice cible. Le modèle utilise une méthode semblable à un profilage statique puisqu’il analyse les instructions utilisées dans le code de l’implémentation utilisée sans l’exécuter. Le modèle utilise aussi des informations de la matrice creuse cible, dont sa taille et l’emplacement des éléments non nuls qui la compose.

Ce chapitre utilisera les variables présentées au Tableau 2.1, présentant les paramètres d’une ma- trice creuse, et au Tableau 3.1.

Tableau 3.1 : Variables utilisées dans le modèle proposé

Variables Description

a Nombre d’éléments manquants à l’alignement

IR Nombre d’instructions demandant une requête d’accès à la mémoire

Ne Nombre d’éléments demandés en mémoire

Nt Nombre de fils

Nw Nombre de chaînes

R Nombre de requêtes à la mémoire

rem Nombre de fils dans la dernière chaîne

Sb Taille d’un bloc; nombre de fils dans un bloc

Se Taille, en octet, des éléments en mémoire

Stx Taille d’un transfert en octets; taille d’une ligne de cache

Sw Taille d’une chaîne; nombre de fils dans une chaîne

T Nombre de transactions à la mémoire

W Nombre de chaînes

La variable Srow, du Tableau 2.1, peut être facilement calculée au préalable pour chaque matrice. Puisqu’elles sont d’abord toute en format COO, il est possible d’utiliser le vecteur row afin de construire le tableau Srow comme à la Figure 3.1. Dans le vecteur row, le nombre d’occurrences

de chaque indice de ligne est additionné et le total est répertorié dans le vecteur Srow à l’indice correspondant. La variable maxRow, qui représente la plus longue ligne, correspond alors à l’élé- ment le plus élevé du tableau Srow.

1 for i = 0 to NNZ-1 do 2 Srow[row[i]] ++ 3 end for

Figure 3.1 : Calcul du nombre d’éléments de chaque ligne de la matrice

Les accès à la mémoire peuvent être mesurés en nombre de transactions et en nombre de requêtes. Une requête représente une demande de lecture ou d’écriture par les fils faisant partie d’une même chaîne. Comme présenté à la section 2.4.2.2 portant sur la mémoire globale, une requête demandant des adresses séquentielles correspondant à une région alignée de la mémoire est plus efficace. C’est-à-dire qu’elle requiert moins de transactions à la mémoire.

Pour mesurer le nombre de requêtes, il est nécessaire de connaître le nombre d’instructions effec- tuant une demande d’accès à la mémoire ainsi que le nombre de chaînes de fils d’exécution effec- tuant cette instruction (3.1).

𝑅 = 𝐼𝑅𝑊 (3.1)

Une requête a besoin d’une seule transaction à la mémoire lorsque la taille de la région demandée est inférieure ou égale à la taille d’un transfert et que la première adresse est alignée (3.2). Une requête est alignée lorsque la première adresse de l’ensemble demandé est un multiple du rapport de la taille de transfert Stx par la taille des éléments Se. En principe, ce rapport est un entier.

𝑇 = ⌈(𝑁𝑒+ 𝑎) × 𝑆𝑒

𝑆𝑡𝑥 ⌉ (3.2)

Le calcul du nombre de transactions ne tiendra pas compte de la cache dans ce chapitre. Par exemple, si deux instructions qui se suivent dans un noyau requièrent des adresses similaires, le nombre de transactions total de chaque instruction sera calculé indépendamment. En effet, bien que deux instructions se suivent dans le noyau, cela ne veut pas dire qu’elles seront exécutées l’une à la suite de l’autre. Il n’est pas possible de prédire l’ordre dans lequel les chaînes de fils d’exécu- tions seront lancées. Il se peut que suite à une instruction, une autre chaîne qui a besoin d’effectuer

une instruction totalement différente soit lancée. Nous estimons donc qu’à chaque fois, les éléments mis dans la cache se font écraser par d’autres.

Puisque la SpMV requiert beaucoup d’accès à la mémoire, nous posons l’hypothèse que le temps d’exécution est lié au nombre de transferts à la mémoire T. Nous proposons d’estimer la perfor- mance de la SpMV selon différents formats de représentation à l’aide du nombre de transactions à la mémoire. Une implémentation ayant un plus grand nombre de transactions qu’une autre est moins performante que cette dernière.

Dans les sections qui suivent, nous présenterons les équations permettant de calculer le nombre de transactions à la mémoire de 5 implémentations de la SpMV. Deux implémentations seront pré- sentées pour le format CSR, la première ayant une distribution des tâches où chaque fil est associé à une ligne de la matrice et une deuxième où une chaîne de fils est associée à une ligne. Ensuite, nous verrons une implémentation pour chacun des formats ELL, COO et HYB. Ces formats ont été choisis de façon à ce qu’ils soient compatibles avec n’importe quel type de matrice. De plus, ce sont des formats utilisés dans les bibliothèques de résolution de problèmes avec matrices creuses basées sur le langage CUDA : CUSP [14] et CUSPARSE [13]. Les implémentations présentées sont d’ailleurs inspirées de ces bibliothèques.

Pour chacune des implémentations, le nombre de transactions et de requêtes à la mémoire sera scindé en une somme de plusieurs nombres comme le montre les équations (3.3) et (3.4). La valeur maximale de i varie d’un format à l’autre. Les nombres de transactions de Ti et Ri sont chacun

associés à un différent vecteur de données à accéder en mémoire. Dans certains cas, ces nombres de transactions et de requêtes peuvent être calculés par une expression analytique et dans d’autres cas, ils sont calculés par profilage statique, c’est-à-dire que leur valeur est calculée par un code essayant de reproduire le comportement de l’implémentation de la SpMV.

𝑇𝑓𝑜𝑟𝑚𝑎𝑡 = ∑ 𝑇𝑖 𝑖 (3.3) 𝑅𝑓𝑜𝑟𝑚𝑎𝑡 = ∑ 𝑅𝑖 𝑖 (3.4)

Documents relatifs