2010-10-05 10 views
3

disons que je veux multiplier deux matrices ensemble, 50 par 50. J'ai 2 façons d'arranger les discussions et les blocs.multiplication matricielle en cuda

a) un fil pour calculer chaque élément de la matrice de résultat. J'ai donc une boucle dans le fil multiplie une ligne et une colonne.

b) un thread pour chaque multiplication. Chaque élément de la matrice de résultat nécessite 50 threads. Une fois les multiplications terminées, je peux utiliser la réduction binaire pour additionner les résultats.

Je ne savais pas quel chemin prendre, donc je pris b. Ce n'était pas idéal. En fait c'était lent. Une idée pourquoi? Je suppose qu'il y a trop de discussions et qu'elles attendent des ressources la plupart du temps, est-ce vrai?

Répondre

4

Comme tant de choses dans le calcul haute performance, la clé de la performance compréhension est de comprendre ici l'utilisation de la mémoire .

Si vous utilisez un thread pour faire une multiplication, alors pour ce thread vous devez tirer deux morceaux de données de la mémoire, les multiplier, puis faire un nombre logarithmique d'additions. C'est trois accès mémoire pour un mult et un add et un bit - l'intensité arithmatique est très faible. La bonne nouvelle est qu'il y a beaucoup de tâches de ce type, chacune ayant seulement besoin d'un peu de mémoire/registres, ce qui est bon pour l'occupation; mais le taux d'accès mémoire au travail est faible.

Le simple fil faisant une approche produit scalaire a le même genre de problème - chaque multiplication nécessite deux accès à la mémoire à charger. La bonne nouvelle est qu'il n'y a qu'un seul magasin dans la mémoire globale pour tout le produit scalaire, et vous évitez la réduction binaire qui n'est pas aussi importante et nécessite beaucoup de synchronisation; l'inconvénient est qu'il y a beaucoup moins de threads maintenant, ce qui au moins votre approche (b) a fonctionné pour vous.

Maintenant, vous savez qu'il devrait y avoir une façon de faire plus d'opérations par accès à la mémoire que cela; pour les matrices NxN carrées, il y a N^3 travail pour faire la multiplication, mais seulement 3xN^2 éléments - donc vous devriez être capable de trouver un moyen de faire plus de 1 calcul par 2 accès mémoire.

L'approche adoptée dans le SDK CUDA est la meilleure façon - les matricies sont divisées en tuiles, et votre (b) approche - un fil par élément de sortie - est utilisé. Mais la clé est dans la façon dont les discussions sont organisées. En extrayant des petites sous-matrices entières de la mémoire globale lente dans la mémoire partagée, et en faisant des calculs à partir de là, il est possible de faire plusieurs multiplications et d'ajouter sur chaque numéro que vous avez lu de la mémoire. Cette approche est la plus efficace dans de nombreuses applications, car l'obtention de données - que ce soit sur un réseau ou depuis la mémoire principale d'un processeur ou un accès hors puce pour un GPU - prend souvent beaucoup plus de temps que le traitement des données.

Il existe des documents dans les pages CUDA de NVidia (notamment http://developer.nvidia.com/object/cuda_training.html) qui décrivent très bien leur exemple SDK.

1

Avez-vous regardé

$SDK/nvidia-gpu-sdk-3.1/C/src/matrixMul 

à savoir l'exemple de multiplication de la matrice dans le SDK?

0

Si vous n'avez pas besoin de mettre en œuvre vous-même, il suffit d'utiliser une bibliothèque - CUBLAS, MAGMA, etc., fournir des implémentations de multiplication de la matrice à l'écoute.