J'écris une petite bibliothèque pour des calculs matriciels clairsemés comme un moyen de m'apprendre à faire le meilleur usage de la programmation orientée objet. J'ai travaillé très dur pour avoir un joli modèle objet, où les parties (matrices clairsemées et les graphiques qui décrivent leur structure de connectivité) sont très peu couplées. À mon avis, le code est beaucoup plus extensible et maintenable pour lui.
Cependant, c'est aussi un peu plus lent que si j'avais utilisé une approche contondante. Afin de tester les compromis d'avoir ce modèle d'objet, j'ai écrit un nouveau type de matrice clairsemée qui a rompu l'encapsulation du graphique sous-jacent pour voir combien plus rapide cela fonctionnerait.
Au début, ça avait l'air plutôt sombre; le code dont j'étais fier était autrefois 60% plus lent qu'une version sans aucune conception logicielle élégante. Mais, j'ai pu faire quelques optimisations de bas niveau - en alignant une fonction et en changeant un peu une boucle - sans changer du tout l'API. Avec ces changements, c'est maintenant seulement 20% plus lent que la concurrence.
Ce qui m'amène à ma question: quelle perte de performances dois-je accepter si cela signifie que j'ai un joli modèle d'objet?
la source
Réponses:
Très peu de développeurs de logiciels scientifiques comprennent les bons principes de conception, je m'excuse donc si cette réponse est un peu longue. Du point de vue de l'ingénierie logicielle, l'objectif du développeur de logiciels scientifiques est de concevoir une solution répondant à un ensemble de contraintes souvent conflictuelles .
Voici quelques exemples typiques de ces contraintes, qui pourraient être appliqués à la conception de votre bibliothèque matricielle clairsemée:
Les scientifiques accordent progressivement plus d'attention à certaines autres exigences courantes de l'ingénierie logicielle:
Vous devrez peut-être plus ou moins l'une de ces exigences. Si vous essayez de gagner un prix Gordon Bell pour la performance, même des fractions de pour cent sont pertinentes, et peu de juges évalueront la qualité de votre code (tant que vous pourrez les convaincre que c'est vrai). Si vous essayez de justifier l'exécution de ce code sur une ressource partagée telle qu'un cluster ou un supercalculateur, vous devez souvent défendre des affirmations sur les performances de votre code, mais celles-ci sont rarement très strictes. Si vous essayez de publier un article dans un journal décrivant les gains de performance de votre approche, vous devez légitimement être plus rapide que vos concurrents, et 20% de performances sont un compromis que je ferais avec plaisir pour une meilleure maintenabilité et réutilisation.
Pour en revenir à votre question, un «bon design», avec suffisamment de temps de développement, ne doit jamais sacrifier les performances. Si l'objectif est de rendre le code qui s'exécute aussi vite que possible, alors le code doit être conçu autour de ces contraintes. Vous pouvez utiliser des techniques telles que la génération de code, l'assemblage en ligne ou profiter de bibliothèques hautement optimisées pour vous aider à résoudre votre problème.
Mais que faire si vous n'avez pas assez de temps de développement? Qu'est-ce qui est assez bon? Eh bien, cela dépend, et personne ne pourra vous donner une bonne réponse à cette question sans plus de contexte.
FWIW: Si vous êtes vraiment intéressé à écrire des noyaux à matrice clairsemée hautes performances, vous devriez comparer avec une installation PETSc optimisée et travailler avec leur équipe si vous les battez, ils seraient heureux d'incorporer des noyaux accordés à la bibliothèque.
la source
C'est une question sur quoi vous passez votre temps. Pour la plupart d'entre nous, nous passons 3/4 du temps à programmer et 1/4 du temps à attendre les résultats. (Vos chiffres peuvent varier, mais je pense que le nombre n'est pas complètement sans mérite.) Donc, si vous avez un design qui vous permet de programmer deux fois plus vite (3/4 d'une unité de temps au lieu de 1,5 unité de temps), alors vous peut prendre un coup de 300% dans les performances (de 1/4 à 1 unité de temps) et vous êtes toujours en tête en termes de temps réel consacré à la résolution du problème.
D'un autre côté, si vous effectuez des calculs lourds, vos calculs peuvent sembler différents et vous voudrez peut-être passer plus de temps à optimiser votre code.
Pour moi, 20% semble être un assez bon compromis si vous finissez par être plus productif.
la source
À mon humble avis, une pénalité pouvant aller jusqu'à 50% (quelle qu'en soit la raison) n'est pas si mauvaise.
En fait, j'ai vu une différence de performances de 0 à 30% uniquement en fonction du type de compilateur. C'est pour la routine MatMult clairsemée de PETSc sur des matrices résultant de discrétisations FE d'ordre faible.
la source
La conception du logiciel ne s'améliorera pas automatiquement au fil du temps. La performance sera. Vous récupérerez les 20% avec votre prochain CPU. En outre, une bonne conception logicielle facilitera l'extension ou l'amélioration de la bibliothèque à l'avenir.
la source
Un principe général consiste à opter d'abord pour une bonne conception, puis à optimiser les performances uniquement si nécessaire . Les cas d'utilisation où un gain de performances de 20% est vraiment nécessaire sont susceptibles d'être plutôt rares, s'ils surviennent.
la source