2 votes

Comment collecter des noyaux binaires pour distribuer du code propriétaire ?

J'ai un code qui contient un savoir-faire que je ne voudrais pas distribuer en code source. Une des solutions est de fournir un tas de noyaux pré-compilés et de choisir le binaire correct en fonction du matériel de l'utilisateur.

Comment couvrir la plupart des utilisateurs (AMD et Intel, car Nvidia peut utiliser le code CUDA) avec un minimum de binaires et un minimum de machines sur lesquelles je dois faire tourner mon compilateur hors ligne ? Y a-t-il des familles de GPU qui peuvent utiliser les mêmes binaires ? Le compilateur CUDA peut compiler pour différentes architectures, qu'en est-il d'OpenCL ? Les données de compatibilité binaire ne semblent pas bien documentées, mais quelqu'un a peut-être collecté ces données pour lui-même.

Je sais qu'il y a le SPIR mais les anciens matériels ne le supportent pas.

Voici les détails de ma mise en œuvre si quelqu'un a trouvé cette question et fait moins que moi. J'ai fait un outil qui compile le noyau au fichier et ensuite j'ai rassemblé tous ces binaires dans un tableau C à inclure dans l'application principale :

const char* binaries[] = { //kernels/HD Graphics 4000 "\x62\x70\x6c\x69\x73\x74\x30\x30\xd4\x01\x02\x03" "\x04\x05\x06\x07\x08\x5f\x10\x0f\x63\x6c\x42\x69" "\x6e\x61\x72\x79\x56\x65\x72\x73\x69\x6f\x6e\x5c" ... "\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x47\xe0" , //here more kernels }; size_t binaries_sizes[] = { 204998, 205907, ... };

Et ensuite j'utilise le code suivant qui itère tous les noyaux (je n'ai rien inventé de plus intelligent que l'essai et l'erreur, en choisissant le premier noyau qui se construit avec succès, il y a probablement une meilleure solution) :

int e3 = -1; int i = 0; while (e3 != CL_SUCCESS) { if (i == lenof(binaries)) { throw Error(); } program = clCreateProgramWithBinary(context, 1, &deviceIds[devIdx], &binaries_sizes[i], (const unsigned char**)&binaries[i], nullptr, &e3); if (e3 != CL_SUCCESS) { ++i; continue; } int e4 = clBuildProgram(program, 1, &deviceIds[devIdx], "", nullptr, nullptr); e3 = e4; ++i; }

2voto

Ruyk Points 561

Malheureusement, il n'existe pas de solution standard pour votre problème. OpenCL est indépendant de la plate-forme, et il n'existe pas de méthode standard (à part SPIR) pour traiter ce problème. Chaque fournisseur décide d'une chaîne d'outils de compilation différente en interne, et même celle-ci peut changer entre plusieurs versions du même pilote, ou pour différents périphériques.

Vous pourriez ajouter des méta-données au noyau pour identifier la plate-forme pour laquelle vous l'avez compilé, ce qui vous épargnerait la partie essais et erreurs (c'est-à-dire qu'au lieu de simplement stocker binaries et binaries_size, vous pouvez également stocker binary_platform et binary_device et ensuite itérer à travers ces tableaux pour voir quel binaire vous devez charger).

La meilleure solution pour vous serait SPIR (ou le nouveau SPIRV), qui sont des représentations intermédiaires qui peuvent ensuite être "recompilées" par le pilote OpenCL vers le jeu d'instructions de l'architecture réelle. Si vous stockez vos binaires en SPIRV et que vous avez accès à la magie d'un compilateur ou que vous la connaissez, vous pouvez utiliser un outil de traduction pour récupérer le LLVM-IR et ensuite le compiler vers d'autres plateformes, comme AMD ou PTX, en utilisant l'infrastructure LLVM (cf. https://github.com/KhronosGroup/SPIRV-LLVM )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X