OpenCL : de vrais défis - page 7

 

1) Les pragmatiques sont une exigence pour le support au moment de la compilation, et non l'activation du support lui-même (comme vous semblez le penser). Donc cl_khr_fp64 est déjà impliqué si votre vises le supporte.

2) Et si la taille du tableau change au moment de l'exécution ? Bien sûr, cela peut être fait dans ce code particulier, mais cela n'améliorera pas la situation.

Laissez-moi vous dire tout de suite que je faisais du profilage dans AMD CodeXL:

3) Si nous ne prenons que le temps de calcul du noyau lui-même, toute tâche parallélisée sur le GPU gagnera en avantage lorsque le nombre de cœurs de CPU utilisés sera dépassé. Ainsi, même 8 tâches suffisent à accélérer les choses.

4) J'ai moi-même beaucoup de questions sur la formule de calcul des sections locales. Le gain le plus important a eu lieu lorsqu'à work_dim=1 je répartissais les tâches sur tous les cœurs du widget et ceci est UNITS.

Et pourquoi diviser la taille du tampon en général, alors que vous devriez diviser le nombre de ses éléments ? - ce que j'ai fait en fait.

Mathemat: En bref : que doit faire votre code ?

Montrer que l'étape de préparation aux calculs n'est pas instantanée et que le transfert de la mémoire tampon prend beaucoup de temps ; cela remet en question la praticabilité de l'utilisation d'OpenCL même pour les tâches alimentées.

Cela montre également que l'unité centrale n'est pas sélectionnée dans le testeur.

 
Roffild:

Montrant que l'étape de préparation des calculs n'est pas instantanée et que le transfert de la mémoire tampon prend beaucoup de temps, ce qui remet en question la praticabilité de l'utilisation d'OpenCL même pour des tâches hypertrophiées.

C'est-à-dire qu'il est tout à fait idiot de hurler à ce sujet ; en revanche, il est tout à fait différent de le mesurer ; cela peut être utile sur le plan pratique.

Il montre également que le CPU n'est pas sélectionné dans le testeur.

Peut-être que c'est justifié, mais peut-être que c'est une sur-assurance. Quoi qu'il en soit, je suis sûr que cela a été fait consciemment pour assurer l'efficacité du processus de test lui-même. Plus précisément, l'optimisation (puisqu'il est multi-fil). Ici, les chances d'inclusion peuvent apparaître si la notion de test et d'optimisation sont clairement et complètement séparées (au niveau de la politique du parti), c'est-à-dire si nous les définissons comme différents types logiques d'utilisation du testeur. Avec le support logiciel correspondant (officiellement différent). (Ce serait une bonne chose à bien des égards, et je suis un partisan de longue date d'une telle séparation/distinction, jusqu'à des boutons différents pour commencer l'optimisation et les tests).

Théoriquement, la sélection du CPU pourrait alors être autorisée pendant les tests et interdite pendant l'optimisation (ce qui est correct).

 
Roffild: 1) Les pragmatiques sont une exigence du support au moment de la compilation, et non une activation du support lui-même (comme vous semblez le penser). C'est-à-dire que cl_khr_fp64 est déjà impliqué si les viscères le supportent.

Oui, j'en ai fait trop avec le pragma. Si vous continuez à travailler sur votre widget et ne transmettez pas le code à quelqu'un d'autre, aucun problème. Mais si quelqu'un veut le lire sur une carte Barts (disons, 6870), il y aura des problèmes. Le code du noyau essaiera de s'exécuter sans montrer d'erreurs.

4) Je me pose moi-même beaucoup de questions sur la formule de calcul de la section locale. Le gain le plus important a été obtenu lorsque work_dim=1 répartit les tâches sur tous les cœurs du widget, ce qui est UNITS.

Pas nécessairement. Il est souvent beaucoup plus utile d'augmenter le travail dans le noyau lui-même. Il s'agit d'équilibrer les frais généraux associés au transfert de données.

Et votre UNITS est juste un nombre de moteurs SIMD. Selon la documentation,

local_work_size[] définit un sous-ensemble de tâches à exécuter par le noyau de programme OpenCL spécifié. Sa dimension est égale à work_items[]et permet de découper le sous-ensemble total des tâches en sous-ensembles plus petits sans résidu de division . En fait, la taille du tableaulocal_work_size[] doit être choisie de manière à ce que l'ensemble global de tâches work_items[] soit découpé en sous-ensembles plus petits. Dans cet exemple ,local_work_size[3]={10, 10, 10} fera l'affaire , puisquework_items[40, 100, 320] peut être assemblé à partir du tableau local_items[10, 10, 10] sans aucun résidu .

Le nombre de moteurs SIMD est une constante strictement matérielle qui ne doit pas du tout diviser la tâche globale.

Mais vous devez d'abord évaluer correctement le problème global lui-même.

A propos du CPU dans le testeur - je vois, je suis convaincu.

 
MetaDriver:

Ce n'est absolument pas nouveau. Je veux dire, c'est idiot de le crier, mais le mesurer est une autre affaire ; cela peut être utile dans la pratique.

Sauf que pour une raison quelconque, j'ai dû prendre ces mesures... Lorsque vous lisez "il y a un délai de transmission", vous n'avez aucune idée de son importance.

Mathemat: Et votre UNITS est juste un nombre de moteurs SIMD. Selon la documentation,

Le nombre de moteurs SIMD est une constante strictement matérielle, qui ne doit pas du tout diviser la tâche globale.

Utilisons plutôt la documentation officielle:

CL_DEVICE_MAX_COMPUTE_UNITS cl_uint Le nombre d'unités de calcul parallèles sur le dispositif OpenCL. Un groupe de travail s'exécute sur une seule unité de calcul. La valeur minimale est de 1.
taille_travail_local.
Pointe vers un tableau de valeurs non signées work_dim qui décrivent le nombre d'unités de travail qui composent un groupe de travail (également appelé la taille du groupe de travail) qui exécutera le noyau spécifié par le noyau.
Mes conclusions sont donc correctes et confirmées par le test AMD CodeXL.
 

Le point est différent. Appelez vos barils d'unités, mais le fait est que les unités dans votre code ne divisent pas la tâche globale en entier (le mien ne le fait certainement pas : 240/28 n'est pas un entier ; le vôtre aussi, puisque vous avez unités=18). Il s'agit d'un bug.

Et deuxièmement, ici et maintenant, vous travaillez avec OpenCL pour MQL5 (enfin, ce n'est pas exact, mais vous m'avez compris) ; après tout, il s'agit d'un OpenCL différent de celui de Khronos.

P.S. Je n'ai pas créé l'hyperlien, je l'ai juste obtenu par moi-même :)

Roffild:
CL_DEVICE_MAX_COMPUTE_UNITS cl_uint Le nombre d'unités de calcul parallèles sur le dispositif OpenCL. Un groupe de travail s'exécute sur une seule unité de calcul. La valeur minimale est de 1.

Voir d'autres sources pour la définition des "unités de calcul".

Au fait, voici un tableau tiré de mon deuxième article. Il serait bon que vous compreniez toutes ces unités de calcul (18), ces cœurs de flux (288), ces éléments de traitement (1440), ces fronts d'onde maximums/GPU (496) et ces éléments de travail/GPU (31744). Je ne l'ai pas encore compris.


 
Mathemat:

Le point est différent. Appelez vos barils d'unités, mais le fait est que les unités dans votre code ne divisent pas la tâche globale en entier (le mien ne le fait certainement pas : 240/28 n'est pas un entier ; le vôtre aussi, puisque vous avez unités=18). C'est un problème.

Alors pourquoi avez-vous basé le nombre d'octets sur 240 ? Vous pouvez peut-être le faire, mais la carte graphique ne le peut pas. Donc 240/8 = 30 doubles.

240 octets est la taille de la totalité du tampon de 30 doubles.

Et "choisir un diviseur entier" n' est qu'une recommandation de la documentation officielle. Et cette recommandation ne fonctionne pas parfaitement.

Et ce qui concerne les UNITS n'est pas de mon ressort ; ce sont juste des conseils tirés des forums OpenCL. Je l'ai testé et j'ai obtenu la vitesse maximale...

Mathemat:

Et la deuxième chose : ici et maintenant vous travaillez avec OpenCL pour MQL5 (enfin, ce n'est pas exact, mais vous m'avez eu) où il s'agit, après tout, d'un OpenCL différent de celui de Khronos.

Et quel est "l'autre" ?

Vous confondez les implémentations propriétaires et les simples wrappers. OpenCL MQL est juste une enveloppe sur l'API OpenCL de Khronos. A propos de la différence entre OpenCL MQL et Khronos.

 
Mathemat: Au fait, voici le tableau de mon deuxième article. Il serait bon que vous compreniez toutes ces unités de calcul (18), ces cœurs de flux (288), ces éléments de traitement (1440), ces fronts d'onde maximums/GPU (496) et ces éléments de travail/GPU (31744). Je ne l'ai pas encore compris.

unités de calcul est le nombre de tâches simultanées en cours d'exécution.

max wavefronts/GPU (496) et work-items/GPU (31744) sont la queue à exécuter.

AMD CodeXL a déjà une réponse à toutes ces questions.

 
Roffild:

unités de calcul est le nombre de tâches simultanées en cours d'exécution.

max wavefronts/GPU (496) et work-items/GPU (31744) sont en attente d'exécution.

AMD CodeXL peut enfin vous aider - il répond à toutes ces questions.

Peut-être que je ne comprends pas quelque chose, désolé. Mais connaissez-vous Alexey personnellement ? Mais de côté, ça n'a pas l'air..... vous parlez trop effrontément, plus intelligemment que les autres ? être intelligent n'est pas un péché, s'en vanter entre frères en esprit est honteux par contre...

 

Je suis un mec simple et je réponds à la question.

Si vous voulez vraiment comprendre OpenCL et pas seulement le supposer, vous devrez mettre AMD CodeXL et créer votre propre wrapper C/C++.

Je peux poster mon wrapper, mais il comporte quelques lignes illogiques dues à mon manque de pratique en C/C++.

 
Roffild: Alors pourquoi avoir pris 240 octets comme chiffre de base ? Vous pouvez peut-être le faire, mais la carte vidéo ne le peut pas. Donc 240/8 = 30 doubles.

240 octets correspondent à la taille de l'ensemble du tampon de 30 doubles.

Regardez votre propre code :

uint units = (uint)CLGetInfoInteger(hcontext, CL_DEVICE_MAX_COMPUTE_UNITS);
uint global_work_offset[] = {0};
uint global_work_size[1];
uint local_work_size[1];
global_work_size[0] = ArraySize(price);
Print( "Глобальная задача = ", global_work_size[0] );  /// Это я добавил, вышло 240. Но это и так легко подсчитать: 30*double = 240
local_work_size[0] = global_work_size[0] / units;

De plus, dans la dernière ligne, vous divisez vous-même 240 par 18 (ce sont les unités de votre carte).

Et "ramasser tout le diviseur" n' est qu'une recommandation de la documentation officielle. Et cette recommandation ne fonctionne pas parfaitement.

Nous travaillons avec MQL5 OpenCL. Je me réfère à la documentation sur notre site web. Bien sûr, je regarde aussi Khronos.

Quant aux UNITS, ce ne sont pas mes propres mots, mais des conseils tirés des forums OpenCL. Je l'ai testé et j'ai obtenu la vitesse maximale...

J'ai obtenu la vitesse maximale avec différents paramètres. Et alors ?

Je vais vous donner une idée approximative. 18 tâches exécutées simultanément sur des mouches GPU est le maximum qui peut être fait sur 4-5 chaînes de CPU. Et un CPU sur émulation x86 peut organiser beaucoup plus de threads. Du moins si c'est Intel. Mon ancien Pentium G840 (2 cœurs) a donné une accélération d'environ 70x - sur deux unités ! Sans parler de ce que mon actuel... i7, pour ainsi dire.

Une tâche bien parallélisée (voir les scripts MetaDriver de la première branche d'ocl) permet d'atteindre une vitesse de 1000 ou plus sur GPU (en comparaison avec 1 thread sur CPU dans MQL5). Si vous ne le trouvez pas, je peux le télécharger pour que vous l'essayiez sur votre carte.

Si vous voulez vraiment comprendre OpenCL et pas seulement le deviner, vous devrez mettre AMD CodeXL et créer votre propre wrapper C/C++.

OK, je vais y jeter un œil, merci.