Comment faire pour accélérer la multiplication de matrice en C++?
Je suis d'effectuer la multiplication de matrice avec cet algorithme simple. Pour être plus souple, j'ai utilisé des objets de la matricies qui contiennent dynamicly créé des tableaux.
Comparant cette solution pour mon premier avec des tableaux statiques, c'est 4 fois plus lent. Que puis-je faire pour accélérer l'accès aux données? Je ne veux pas modifier l'algorithme.
matrix mult_std(matrix a, matrix b) {
matrix c(a.dim(), false, false);
for (int i = 0; i < a.dim(); i++)
for (int j = 0; j < a.dim(); j++) {
int sum = 0;
for (int k = 0; k < a.dim(); k++)
sum += a(i,k) * b(k,j);
c(i,j) = sum;
}
return c;
}
MODIFIER
J'ai corrigé ma Question avove! J'ai ajouté le code source complet ci-dessous et essayé quelques-uns de vos conseils:
- échangé
k
etj
itérations de boucle -> l'amélioration de la performance - déclaré
dim()
etoperator()()
commeinline
-> l'amélioration de la performance - passage des arguments par référence const -> perte de performance! pourquoi? donc je ne l'utilise pas.
La performance est maintenant de plus près le même qu'il était dans l'ancien porgram. Peut-être il devrait y avoir un peu plus d'amélioration.
Mais j'ai un autre problème: j'obtiens une erreur de mémoire dans la fonction mult_strassen(...)
. Pourquoi?
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
ANCIEN
principal.c http://pastebin.com/qPgDWGpW
c99 main.c -o matrix -O3
NOUVEAU PROGRAMME
la matrice.h http://pastebin.com/TYFYCTY7
matrix.cpp http://pastebin.com/wYADLJ8Y
main.cpp http://pastebin.com/48BSqGJr
g++ main.cpp matrix.cpp -o matrix -O3
.
MODIFIER
Voici quelques résultats. La comparaison entre l'algorithme standard (std), échangé ordre de j et k de la boucle (swap) et bloqué algortihm avec une taille de bloc 13 (bloc).
- Avez-vous l'intention d'écrire une matrice de multiplier qui ne fonctionne que sur les matrices carrées? Multipliez est défini en tant que les dimensions intérieures sont égaux.
- Vous êtes de passage a et b par référence, non? Vous n'êtes pas la copie de deux matrices juste d'appeler cette fonction?
- Vous pouvez également utiliser Propre, qui est particulièrement bien adaptée. (Ne laissez pas la licence LGPL vous faire peur - c'est un en-tête de la seule bibliothèque, et le "virale" termes de la licence LGPL ne pas tenir. Voir FAQ.)
- les copies sont gommés par le compilateur, le passage par valeur est aussi rapide, voire plus rapide que par référence.
- Qui n'est pas universellement vrai. Avez-vous vu le constructeur de copie de code pour
class matrix
? Si non, vous êtes juste de faire une sauvage deviner. - Je ne veux pas inventer la whell un deuxième temps. C'est un projet pour tester un algorithme de multiplication de matrice. Je commence la mise en œuvre en C, et a obtenu ces pertes de performances maintenant en C++. Je ne veux pas utiliser cet algorithme, je veux juste mesure de la performance. Je n'ai pas besoin d'une bibliothèque.
- Pouvez-vous passé le code en question. Les liens ne sont plus de travail pour moi.
- OK. J'ai une copie du code. C'est comme comparer des pommes à des oranges. 1) Mettre le code dans le même harnais de test. 2) effectuer les mêmes opérations (Dans la version C++ vous n'êtes pas simplement en multipliant vous êtes également l'allocation de mémoire).
- J'ai trouvé le problème principal. Votre code C a un énorme dépassement de la mémoire tampon. C'est de réinitialiser le dim variable globale à l'origine de votre multiplication de sortie précoce.
- York: Désolé, c'était une erreur, parce que des tests de différentes gammes.
- Vous avez des fuites de mémoire toute la place dans ce code, qui est une grande partie de la raison passe-par-valeur est plus rapide que de passer par-const-référence. Est
mult_strassen
votre mise en œuvre de la "bloquer l'accès de la tendance" je l'ai suggéré, ou n'avez-vous pas posté ce code?
Vous devez vous connecter pour publier un commentaire.
Passer des paramètres par référence const pour commencer:
Pour vous donner plus de détails, nous avons besoin de connaître les détails des autres méthodes utilisées.
Et pour répondre à pourquoi la méthode originale est 4 fois plus rapide que nous aurions besoin de voir la méthode d'origine.
Le problème est sans doute la vôtre, car ce problème a été résolu un million de fois avant.
Aussi quand vous posez ce type de question TOUJOURS fournir compilable source appropriée des intrants afin que nous puissions réellement construire et exécuter le code et de voir ce qui se passe.
Sans le code, nous sommes juste deviner.
Modifier
Après la fixation de la principale bug dans le code en C d'origine (un tampon plus-run)
J'ai mis à jour le code pour exécuter le test côte à côte dans une comparaison équitable:
Les résultats aujourd'hui:
À partir de cela, nous voyons que le code C est deux fois plus rapide que le code C++ lorsqu'il est entièrement optimisé. Je ne peux pas voir la raison dans le code.
En parlant de vitesse, votre fonction sera de plus de cache-friendly si vous modifiez l'ordre de la
k
etj
itérations de boucle:C'est parce que
k
index dans le plus intérieur de la boucle, va provoquer un cache miss dansb
à chaque itération. Avecj
comme à l'intérieur de la plupart de l'index, à la foisc
etb
sont accessibles de manière contiguë, tandis quea
reste en place.Vous dites que vous ne voulez pas modifier l'algorithme, mais ça signifie quoi exactement?
N'en déroulant le nombre de boucles que "la modification de l'algorithme"? Que penser de l'utilisation de l'ESS/VMX selon instructions SIMD sont disponibles sur votre CPU? Qu'en employant une forme de blocage d'améliorer la localité de cache?
Si vous ne voulez pas de restructurer votre code à tous les, je doute qu'il ya plus que vous pouvez faire que les modifications que vous avez déjà fait. Tout le reste devient un compromis de modifications mineures apportées à l'algorithme pour obtenir un gain de performance.
Bien sûr, vous devez toujours prendre un coup d'oeil à l'asm généré par le compilateur. Qui vais vous en dire beaucoup plus sur ce qui peut être fait pour accélérer le code.
Assurez-vous que les membres
dim()
etoperator()()
sont déclarées en ligne, et que l'optimisation du compilateur est allumé. Puis de jouer avec des options comme-funroll-loops
(sur gcc).Quelle est la taille de
a.dim()
de toute façon? Si une ligne de la matrice ne rentre pas dans juste un couple de lignes de cache, vous seriez mieux avec un bloc d'accès au lieu d'une ligne à la fois.matrix
en valeur l'utilisation const référence.dim()
à l'extérieur de votre boucles.Voici ma mise en œuvre rapide, simple algorithme de multiplication pour la place de flotteur de matrices (tableaux 2D). Il devrait être un peu plus rapide que chrisaycock code, car il permet de préserver une partie des incréments.
Je suis un sauvage suppose ici, mais si vous alloue dynamiquement les matrices de fait une énorme différence, peut-être le problème, c'est la fragmentation. Encore une fois, je n'ai aucune idée de comment la matrice sous-jacente est mis en œuvre.
Pourquoi ne pas allouer de la mémoire pour les matrices à la main, en s'assurant qu'il est contigu, et de construire le pointeur de la structure-vous?
Aussi, ne l'dim() méthode supplémentaire de la complexité? Je voudrais déclarer en ligne, aussi.