Je vais essayer de résumer mes expériences acquises au cours du développement de ViennaCL, où nous avons des moteurs CUDA et OpenCL avec principalement des traductions 1: 1 de nombreux noyaux de calcul. De votre question, je suppose également que nous abordons principalement les GPU ici.
Portabilité des performances.Tout d’abord, il n’existe pas de noyaux portables performants en ce sens que vous écrivez un noyau une fois et il fonctionnera efficacement sur tous les matériels. Pas dans OpenCL, où cela est plus apparent en raison de la gamme plus étendue de matériel pris en charge, mais également pas dans CUDA. CUDA est moins évident en raison de la gamme moins étendue de matériel pris en charge, mais même dans ce cas, nous devons déjà distinguer au moins trois architectures matérielles (pré-Fermi, Fermi, Kepler). Ces fluctuations de performances peuvent facilement entraîner une variation de performances de 20%, en fonction de la manière dont vous orchestrez les threads et de la taille du groupe de travail que vous choisissez, même si le noyau est aussi simple qu'une copie tampon. Il convient également de mentionner que sur les GPU pré-Fermi et Fermi, il était possible d’écrire des noyaux de multiplication matrice-matrice rapides directement dans CUDA, alors que pour les derniers GPU Kepler, il semble qu'il faille passer au langage de pseudo-assemblage PTX pour se rapprocher des performances de CUBLAS. Ainsi, même un langage contrôlé par le fournisseur, tel que CUDA, semble rencontrer des problèmes pour suivre le rythme des développements matériels. De plus, tout le code CUDA est compilé de manière statique lorsque vous exécutez nvcc, ce qui nécessite un peu d'équilibrage via l'indicateur -arch, tandis que les noyaux OpenCL sont compilés à l'exécution à partir du compilateur juste-à-temps. Vous pouvez donc en principe personnaliser les noyaux jusqu'aux spécificités d'un périphérique de calcul particulier. Ce dernier est toutefois très impliqué et ne devient généralement une option très attrayante que lorsque votre code mûrit et que votre expérience s'accumule. Le prix à payer est le temps O (1) requis pour la compilation juste à temps, ce qui peut poser problème dans certaines situations. OpenCL 2.
Débogage et profilage. Les outils de débogage et de profilage CUDA sont les meilleurs disponibles pour GPGPU. Les outils d'AMD ne sont pas mauvais non plus, mais ils n'incluent pas de gemmes comme cuda-gdb ou cuda-memcheck. De plus, toujours aujourd'hui, NVIDIA fournit les pilotes et les kits de développement les plus robustes pour GPGPU, le système se bloque à cause de noyaux erronés qui constituent réellement une exception et non la règle, à la fois avec OpenCL et CUDA. Pour des raisons que je n'ai probablement pas besoin d'expliquer ici, NVIDIA ne propose plus de débogage et de profilage pour OpenCL avec CUDA 5.0 et versions ultérieures.
Accessibilité et commodité. Il est beaucoup plus facile de mettre en place les premiers codes CUDA, d’autant plus que le code CUDA s’intègre plutôt bien avec le code hôte. (Je discuterai du prix à payer plus tard.) Il existe de nombreux didacticiels sur le Web, ainsi que des guides d'optimisation et des bibliothèques. Avec OpenCL, vous devez passer par un peu de code d’initialisation et écrire vos noyaux sous forme de chaînes afin que vous ne trouviez que des erreurs de compilation lors de l’exécution lors de l’alimentation des sources dans le compilateur jit. Il faut donc plus de temps pour parcourir un cycle de code / compilation / débogage avec OpenCL. Votre productivité est donc généralement inférieure au cours de cette phase de développement initiale.
Aspects de la bibliothèque de logiciels. Alors que les éléments précédents étaient en faveur de CUDA, l'intégration dans d'autres logiciels est un avantage considérable pour OpenCL. Vous pouvez utiliser OpenCL simplement en vous connectant à la bibliothèque OpenCL partagée et c'est tout, alors qu'avec CUDA, vous devez disposer de l'ensemble de la chaîne d'outils CUDA. Pire encore, vous devez utiliser les compilateurs hôtes appropriés pour que nvcc fonctionne. Si vous avez déjà essayé d'utiliser, par exemple, CUDA 4.2 avec GCC 4.6 ou une version plus récente, vous aurez du mal à faire fonctionner les choses. En général, si vous utilisez un compilateur plus récent que le SDK CUDA, des problèmes peuvent survenir. L’intégration dans des systèmes de compilation tels que CMake est une autre source de maux de tête (vous pouvez également trouver de nombreuses preuves, par exemple, du PETSclistes de diffusion). Ce n'est peut-être pas un problème sur votre propre machine sur laquelle vous avez le contrôle total, mais dès que vous distribuez votre code, vous rencontrez des situations dans lesquelles les utilisateurs sont quelque peu restreints dans leur pile logicielle. En d'autres termes, avec CUDA, vous n'êtes plus libre de choisir votre compilateur hôte préféré, mais NVIDIA dicte les compilateurs que vous êtes autorisé à utiliser.
Autres aspects. CUDA est un peu plus proche du matériel (par exemple, des chaînes), mais mon expérience en algèbre linéaire montre que vous en tirez rarement des avantages significatifs. Il y a quelques bibliothèques de logiciels supplémentaires pour CUDA, mais de plus en plus de bibliothèques utilisent plusieurs systèmes de traitement. ViennaCL , VexCL ou Paralution prennent tous en charge les backends OpenCL et CUDA, une tendance similaire peut être observée avec les bibliothèques d'autres zones.
GPGPU n'est pas une balle d'argent. Il a été démontré que GPGPU offrait de bonnes performances pour les opérations structurées et les tâches à calcul limité. Cependant, pour les algorithmes avec une part non négligeable de traitement séquentiel, GPGPU ne peut pas surmonter magiquement la loi d'Amdahl . Dans de telles situations, il vaut mieux utiliser une bonne implémentation de processeur du meilleur algorithme disponible plutôt que d'essayer de lancer un algorithme parallèle, mais moins approprié, à votre problème. De plus, PCI-Express est un grave goulet d'étranglement. Vous devez donc vérifier à l'avance si les économies réalisées sur les GPU peuvent compenser les frais généraux liés au transfert de données en continu.
Ma recommandation. Veuillez considérer CUDA et OpenCL plutôt que CUDA ouOpenCL. Il n'est pas nécessaire de vous limiter inutilement à une plate-forme, mais de tirer le meilleur parti des deux mondes. Ce qui me convient, c’est de configurer une implémentation initiale dans CUDA, de la déboguer, de la profiler, puis de la transférer à OpenCL par simple substitution de chaînes. en fonction du matériel cible.) Cet effort de portage prend généralement moins de 10% de votre temps, mais vous offre également la possibilité d’exécuter sur d’autres matériels. Vous serez peut-être surpris de la capacité du matériel non-NVIDIA à fonctionner dans certaines situations. Surtout, envisagez la réutilisation des fonctionnalités dans les bibliothèques dans la mesure du possible. Alors qu'un rapide & La réimplémentation incorrecte de certaines fonctionnalités fonctionne souvent de manière acceptable pour une exécution mono-thread sur un CPU, elle vous donnera souvent de mauvaises performances sur du matériel massivement parallèle. Idéalement, vous pouvez même tout décharger dans les bibliothèques sans vous soucier de savoir si elles utilisent CUDA, OpenCL ou les deux en interne. Personnellement, je n'oserais jamais écrire du code verrouillé par le vendeur pour quelque chose sur lequel je veux pouvoir compter dans quelques années, mais cet aspect idéologique doit faire l'objet d'une discussion séparée.