Motivés pour un petit test? Alors un retour ne serait pas de refus...

Motivés pour un petit test? Alors un retour ne serait pas de refus... - C#/.NET managed - Programmation

Marsh Posté le 14-02-2010 à 15:28:31    

Ca fait à peu près 1 semaine que je cherche à améliorer un peu ma pratique en C#, pour ce faire j'ai ébauché une petite appli exécutant ce qui se rapproche d'un algo de RayTracing.
 
Parmi les "nouveautés", pour moi, il y a la gestion de threads, et c'est justement là-dessus que j'aurais besoin d'un petit feedback vu que je n'ai que du dual pour mes tests perso.
 
Mon appli lance un certain nombre de threads en fonction du bouton appuyé :
 
- 1 thread pour les boutons ST
- autant de threads que de nombre de cores pour les boutons SMP (CPU multi-cores comme machines multi-CPU)
- autant de threads que de processeurs logiques pour les boutons SMT (Core i7, Northwood/Prescott avec HT activé)
 
Au départ, je n'avais pas du tout fixé d'affinité, ça a été modifié mais ça n'est pas encore totalement au point (aucune distinction entre cores logiques et cores physiques donc le test SMP va probablement exécuter n*2 threads sur n cores si le HT est activé), mais c'est plutôt le comportement sur du test SMP qui m'intéresse pour le moment, puisque systématiquement j'ai un thread qui se termine sensiblement avant l'autre sur les 2 seuls que je peux lancer.
 
Bref, un petit retour sur le comportement avec un quad HT off me permettrait de voir si il est utile d'améliorer la gestion des threads.
 
 
Lien vers l'appli de test : http://pagesperso-orange.fr/grmpf/UglyRTBench.zip
 
Notes :  
 
- Nécessite Vista/7
- Cible le framework 2.0
- La mise à jour de la PictureBox est assez sommaire (invalidation de tout ce qui a déjà été modifié)
- Sur mon PC, les temps de calcul purs sont sensiblement plus courts que les temps totaux, et accessoirement la mise à jour de l'UI semble responsable des ralentissements en SMP/SMT


Message édité par Gigathlon le 14-02-2010 à 21:11:34
Reply

Marsh Posté le 14-02-2010 à 15:28:31   

Reply

Marsh Posté le 14-02-2010 à 21:48:59    

Complément d'informations sur l'appli :
 
- lecture des informations relatives aux processeurs (nombre de CPU, nombre de cores par CPU, nombre de processeurs logiques par CPU)
- lancement d'un nombre de threads (BackgroundWorkers) correspondant au choix (1, nombre de cores global, nombre de processeurs logiques global)
- les threads lancés forcent leur affinité sur un "CPU" (ceux visibles sous le task manager) et font chacun une part égale du rendu (4 threads lancés calculeront respectivement les lignes 0/1/2/3 puis 4/5/6/7 et ainsi de suite)
- à chaque fin de ligne, le thread envoie via son évènement ProgressChanged non seulement le % de lignes qu'il a rendu, mais aussi la ligne elle-même et sa position
- le gestionnaire d'évènement OnProgressChanged copie la ligne dans la bitmap sous-jascente à la PictureBox et affiche la progression thread par thread dans la barre de titre
 
Soucis déjà identifiés :
 
- l'invalidation de la PictureBox ligne par ligne ne fonctionne pas, je suis obligé d'invalider toute la partie déjà modifiée (donc à la première ligne elle seule, mais arrivé à la 1200e toutes les lignes)
- sur un CPU dual core, l'IHM pompe énormément de ressources, ce qui ralentit aléatoirement un des 2 threads de rendu (très visible dans la progression)
 
Soucis potentiels identifiés :
 
- prise en charge du SMT (HyperThreading), actuellement je ne sais pas si mon dispatch est fait sur les cores physiques ou non -> besoin d'un feedback là-dessus


Message édité par Gigathlon le 14-02-2010 à 21:52:12
Reply

Marsh Posté le 14-02-2010 à 22:42:19    

http://img99.imageshack.us/img99/213/image1gd.jpg
 
Alors J'ai remarqué que les deux test Single thread occupe deux cores @ 100%  :heink:
Les autres test multi-thread occupe bien les 4 cores dispo.
 
 
Sinon je me demandais si c'est possible de le coder en openCL pour l'éxcuter sur les CG.


Message édité par Gein le 14-02-2010 à 22:42:29
Reply

Marsh Posté le 14-02-2010 à 23:32:54    

Les 100% sur 2 cores sont plus ou moins normaux, c'est comme je le disais plus haut le rafraîchissement de la PictureBox (prévisualisation) qui pompe pas mal.
 
Sans ça les temps sont nettement moins importants et surtout les threads finissent tous en même temps à quelques pouillèmes près.
 
On voit bien d'après tes résultats que les 4 cores n'amènent pas un gain de 300% comme attendu, un des thread n'étant efficace qu'à 50% (perturbé par l'UI pendant son taf) ça explique déjà en partie ce résultat. En pratique ça ne sera pas une optimisation prioritaire avant un bon moment, les scènes de test étant abusivement simples ça amplifie l'impact qu'a l'affichage (3 et 8 sphères avec 2 point lights dans chaque cas et une profondeur de 6 avec pas mal de choses non réalisées).
 
Sinon, à titre informatif, l'image est rendue en 1920x1200 et non en 960x600 comme à l'affichage et la scène légère est une copie quasi conforme d'un des sites où j'ai pioché quelques infos sur le RT (ceci dit, le rendu orthogonal j'ai toujours pas compris en quoi c'était intéressant :o)
 
 
J'ai ajouté une version sans invalidation de la PictureBox dans l'archive si jamais ça peut servir. Pour un portage vers le GPU ça attendra, il faudra que je me remette au C++ pour créer une DLL ayant les mêmes fonctionnalités que ma classe actuelle pour finir par l'intégrer dans mon UI (SlimDX est trop mal documenté pour que je puisse apprendre sur le tas avec et, sauf erreur de ma part, Microsoft n'a pas fait évoluer son Managed DirectX depuis un bail).
 
 
Ah oui, j'oubliais... étant donné que c'est un développement perso, si il y a des intéressés pour causer code histoire que j'apprenne des bricoles (ou inversement, on ne peut pas toujours penser à tout :p), je suis parfaitement disposé à partager ce qui peut être important.


Message édité par Gigathlon le 15-02-2010 à 00:48:26
Reply

Marsh Posté le 15-02-2010 à 18:43:24    

Je viens de ressayer avec la version sans preview :
 
ST : 2,431
SMP : 0,956
SMT : 1,016
 
ST : 6,313
SMP : 2,495
MT : 3,281
 
C'est bon cette fois si le single thread fonction que sur un seul core. ;)
 
Les temps me semble correctes.

Reply

Marsh Posté le 15-02-2010 à 20:09:49    

Il y a encore pas mal de pertes en multi-thread, ça tombe bien vu que c'est ce que j'essaye d'améliorer pour me rapprocher des 100% d'efficacité.
 
Pour la différence SMP/SMT par contre c'est pas trop normal, ça ressemble à une variation d'un lancement sur l'autre (les 2 font strictement la même chose sur un CPU capable de gérer uniquement 1 thread par core).
 
Je vais essayer une variante légèrement optimisée dans l'allocation des ressources (là c'est assez goret, chaque thread génère 1200/n Bitmap dans sa boucle).

Reply

Marsh Posté le 15-02-2010 à 22:09:18    

Version sans preview
ST : 2.663
SMP: 0.904
SMT: 0.904
 
ST:6.505
SMP:2.324
SMT:2.355
 
Avec preview:
ST: 2.804
SMP: 1.413
SMT : 1.267
 
ST: 6.870
SMP: 3.376
SMT: 3.678

Reply

Marsh Posté le 16-02-2010 à 13:02:31    

Toujours pas de proco avec HT à l'horizon, mais c'est pas grave... :o
 
J'ai fait une découverte today concernant le fameux LineOutput = new Bitmap(width, height) répété dans la boucle de rendu, je vais essayer de voir si je trouve des avis dessus.
 
Avec

Code :
  1. LineOutput = new Bitmap(width, 1);


Les temps de rendu sont de 2.5/5.8s en ST et 1.4/3.3s en MT.
 
Avec

Code :
  1. LineOutput = new Bitmap(width, 1, PixelFormat.Format24bppRgb);


Les temps de rendu sont de 3.3/6.7s en ST et 1.9/3.7s en MT.
 
Autrement dit, l'instanciation de la bitmap "ligne" prend le double de temps quand on demande un format RGB24... alors qu'au final l'image est créée en RGB32 dans les 2 cas.
 
 
Peu de nouveautés à part ça pour le moment, je me suis contenté de ranger un peu le code (mise en évidence des structures utilitaires dans un fichier dédié, déportation de la gestion de l'affinité).
 
En parlant de ça, si jamais certains lecteurs cherchent comment gérer l'affinité des threads...

Code :
  1. [DllImport("kernel32" )]
  2. static extern int GetCurrentThreadId();
  3.  
  4. private void SetThreadAffinity(int ThreadNumber)
  5. {
  6.     int AffinityMask = 0x00000001;
  7.     try
  8.     {
  9.         foreach (ProcessThread pt in Process.GetCurrentProcess().Threads)
  10.         {
  11.             if (GetCurrentThreadId() == pt.Id) pt.ProcessorAffinity = (IntPtr)(AffinityMask << ThreadNumber);
  12.         }
  13.     }
  14.     catch { throw new Exception("SetThreadAffinity" ); }
  15. }


Je pense que ça se passe de commentaire, en dehors de l'effet sur un processeur avec HyperThreading que j'aimerais bien connaître.
 
ThreadNumber est le N° de thread interne au programme (0 à n-1 pour n threads), le reste est standard.


Message édité par Gigathlon le 16-02-2010 à 13:06:06
Reply

Marsh Posté le 16-02-2010 à 17:39:18    

Petite amélioration du côté du temps perdu en générant directement les données bitmap sans passer par un objet Bitmap. C'est pas encore totalement clean mais ça vient bon.
 
Avant -> 2.5/5.8s ST et 1.4/3.3s MT
Après -> 1/4.2s ST et 0.6/2.3s MT
 
Tout ça toujours sur mon petit C2D E8400 @3.6GHz sans prévisualisation.
 
Modification de l'interface pour un peu plus de fonctionnalités et ajout d'une 3e scène qui permet au passage de voir qu'il y a un problème dans mes paramètres "optiques" (probablement la direction du rayon primaire).
 
Toujours au même endroit, j'ai remplacé purement et simplement l'archive -> http://pagesperso-orange.fr/grmpf/UglyRTBench.zip


Message édité par Gigathlon le 16-02-2010 à 17:45:51
Reply

Marsh Posté le 16-02-2010 à 19:59:32    

Sur mon i7 :
 
Scène 1 :  
ST = 1"362
SMP = 0"632
SMT = 0"545
 
Scène 2:
ST = 6.203
SMP = 2"863
SMT = 1"811
 
Scène 3 :
ST = 17"855
SMP = 8"328
SMT = 5"247
 
 
J'ai pas testé avec preview

Reply

Marsh Posté le 16-02-2010 à 19:59:32   

Reply

Marsh Posté le 16-02-2010 à 20:31:01    

Réalisé avec la dernière version en date?  
 
Car là ça ressemblerait à un souci d'attribution des threads aux cores physiques.
 
Avec cette dernière version j'ai vu de meilleurs résultats sur un i5 en terme de scaling... D'ailleurs je vais mettre un affichage de l'efficacité du multithreading dans l'UI, ça sera plus simple à voir.


Message édité par Gigathlon le 16-02-2010 à 20:32:18
Reply

Marsh Posté le 16-02-2010 à 20:33:31    

Oui

Reply

Marsh Posté le 16-02-2010 à 20:47:02    

Le résultat est peut-être aussi influencé par la RAM (l'i5 de Damien est relativement violent avec sa DDR3 1600 7-8-7-24) et les changements de contexte (donc perte d'efficacité avec HyperThreading).
 
Bon, en tout cas je sais sur quoi plancher pour la prochaine évolution :
 
- % d'efficacité du multithreading (un peu de variables globales à ajouter à l'UI)
- 2 choix de distribution des threads pour le mode SMP (1-2-3-4 actuellement, possibilité de passer à 1-3-5-7, ces chiffres représentant l'ordre du bit mis à 1 dans le masque de sélection de l'affinité)

Reply

Marsh Posté le 16-02-2010 à 20:53:04    

J'ai pas testé avec rien de lancé hein, j'ai des choses lancées hein et qui tournent. J'ai lancé qq fois histoire de voir si les chiffres variaient un peu mais ça reste dans le même ordre de grandeur

Reply

Marsh Posté le 16-02-2010 à 21:22:25    

Je te rassure, tu n'es pas un cas isolé, il y a bien un problème avec l'HyperThreading ;)
 
Même si d'autres choses tournent, sauf si c'est un rendu sous Max ou autre tâche très consommatrice ça n'aura pas un impact extraordinaire, ça fait varier les temps mais là c'est reproduit 3 fois et par 2 personnes donc c'est bien un souci d'efficacité.
 
On verra avec l'ordre alternatif d'attribution des threads si le SMT dégrade effectivement les perfs ou non.
 
 
Après, ça reste du .NET donc faut pas non plus s'attendre à des miracles, mais ça sera intéressant de comparer avec le même code en C++ (sauf que pour ça faudra que je m'y remette, le C# est proche mais tellement plus intuitif/propre parfois... :o).


Message édité par Gigathlon le 16-02-2010 à 21:26:19
Reply

Marsh Posté le 16-02-2010 à 22:36:08    

Archive mise à jour, normalement les CPU avec HyperThreading devraient fonctionner correctement maintenant (version 0.3, l'autre a été laissée pour permettre de comparer les résultats).


Message édité par Gigathlon le 16-02-2010 à 22:36:52
Reply

Marsh Posté le 19-02-2010 à 22:52:13    

avec la nouvelle mise a jour sur la scene 3
sans preview
st 16.506
smp 5.982
smt  5.578

 


donc plus de gain en 4 coeurs et 8 coeurs

 


avec preview
st 18.044
smp 6.127
smt 6.297
ps : core i7 920


Message édité par ilo34 le 20-02-2010 à 09:39:45
Reply

Marsh Posté le 20-02-2010 à 01:30:38    

UglyRTBench 0.30, sans preview, sur un Q6600 :
 
Scène 1:
ST : 1.250
SMP : 0.500 (63%)
SMT : 0.515 (61%)
 
Scène 2:
ST : 4.843
SMP : 1.734 (70%)
SMT : 1.765 (69%)
 
Scène 3:
ST : 12.828
SMP : 4.281 (75%)
SMT : 4.328 (74%)
 
 

Reply

Marsh Posté le 20-02-2010 à 09:14:26    

pourquoi framework 2.0  
 
pourquoi pas le 3.0 ou le 3.5 ?
 
sinon j'essaierais ça cet après midi
 
i7 920


Message édité par Activation le 20-02-2010 à 09:16:28
Reply

Marsh Posté le 20-02-2010 à 10:41:17    

alors avec la version 0.30 i7 920 avec OC 3Ghz (eist actif donc en idle 1.7Ghz)
 
sans preview
 
scene 1
ST 1"114
SMP 0"400 effic 70%
SMT 0"448 effic 31%
 
scene 2
ST 5"270
SMP 1"661 effic 79%
SMT 1"642 effic 40%
 
scene 3
ST 15"551
SMP 4"709 effic 83%
SMT 4"715 effic 41%
 
avec preview
scene 1
ST 1"174
SMP 0"428 effic 69%
SMT 0"421 effic 35%
 
scene 2
ST 5"488
SMP 1"898 effic 72%
SMT 1"734 effic 40%
 
scene 3
ST 16"131  
SMP 5"472 effic 74%
SMT 5"417 effic 37%
 
------------------------------------------------
ST charge 3 cores
 
sinon de façon général tu ne peut t'appuyer que sur la valeur au dixième de seconde
 
dès le centième de seconde ça commence à trop fluctuer d'une exécution à une autre dans les même conditions
 
maintenant de toute façon y a un gros bug dans ton exécutable
 
tu lance les tests sans preview ok
tu coche preview ok
tu décoche preview (sans fermer le soft) et pourtant il continue à faire comme si preview était encore coché
 
SINON SANS PREVIEW (donc pas impacté par opti multicore des drivers ati me semble)
en smp les 4 cores monte plus en charge
en smt les 8 cores monte un peu moins en charge... mais c'est franchement pas significatif
 
en gros en smp chacun des 4 cores utilisé je sais pas tourne à 92%
en smt chacun des 8 cores est peut être chargé à 85% bref le code semble pas tiré au mieux de l'hyper treading
vu qu'il est question ici de raytracing doit y avoir moyen d'optimiser encore  
pour une même scène à calculer en 8 cores ça devrait plus tourner à 55% de charge par core ici pour coller avec le temps de calcul
 
hors pour un temps de calcul quasi similaire tout les cores sont encore bien trop sollicité.... sollicité en calcul inutile ? (mauvaise boucle ou version du framework qui occasionne contre performance ?)
 
NOTE: framework 3.0 est bien plus adapté à partir de vista.... framework 2.0 c'est plutôt pour un soft que tu pense faire tourner sur Win9x/2k/xp inférieur au SP2
 
enfin moi ce que j'en dit, vu que tu demande des retour avec vista et 7
 
me semble sinon que framework 3.0 apporte des amélioration pour si tenté est que tu veuille mettre le soft dans un environnement de virtualisation (avec 2.0 risque de fuite mémoire ... pas glop en virtualisation)
 
me semble hein.... je suis de très très loin le dev maintenant ça fait 10ans que j'ai pas fait de dev et framework existait même pas alors (juste du blabla sur ça mise en oeuvre au mieux)
 [:le-lapin-fou]


Message édité par Activation le 20-02-2010 à 10:58:19
Reply

Marsh Posté le 20-02-2010 à 11:00:58    

Gigathlon> Au fait, pourquoi cela nécessite Vista/7 ? J'ai pas fait gaffe à ça, mais je suis sous XP et à priori pas de soucis.
Concernant le SMT, tu devrais le griser pour ceux qui n'ont pas l'HT (car dans leur cas le test est strictement identique) et pour les autres, tu ne devrais pas indiquer l'efficacité mais le gain par rapport au SMP.

 

Activation> Le ST sans preview charge 3 cores ? Quel niveau de charge ? Moi j'ai bien 1 seul core utilisé à 100%.
Concernant tes résultats, il est effectivement étonnant que 8 thread à 88% ne donne pas meilleur résultat que 4 thread à 92%.
Ceci dit je pense que cela doit être dû à la façon dont est considéré le "% utilisé". Avoir 2 CPU logique utilisés à 100% sur le même core ne doit pas signifier que le core fait 2 fois plus de calcul (ce qui est impossible ou presque, surtout lorsqu'il s'agit du même type de calcul qui va utiliser les même unités de calcul). Il doit y avoir beaucoup "d'attente" et cet attente doit être inclus dans le % d'utilisation.


Message édité par Fouge le 20-02-2010 à 11:13:38
Reply

Marsh Posté le 20-02-2010 à 11:12:42    

je referais un test tout à l'heure
 
ça vient peut être du fait que quand après avoir fait un test avec preview et que tu décoche ça continue à faire des tests avec preview
 
je me souvient plus si c'est avant d'avoir réalisé l'existance de ce bug ou après que j'ai vu que 3 cores étaient chargé
 
je finis des mises à jour sur steam pour pas avoir de perturbation et je reteste
 
*************
sinon pour la charge étrangement lourde en 8cores logique, y avait pas des instructions qui ont été mise en place à partir des Q9xxx E0 et core i7 au niveau des registres SSE
pour accélérer le passage d'un thread à un autre


Message édité par Activation le 20-02-2010 à 11:23:41
Reply

Marsh Posté le 20-02-2010 à 11:16:11    

Au fait, c'est open source ? [:cupra]  
J'ai bien envie d'essayer tout ça en le ciblant sur le Framework 3.0 ou 3.5

Reply

Marsh Posté le 20-02-2010 à 11:39:20    

ok donc refais le test et ST sans preview c'est bien qu1 core de chargé
 
mes 3 cores ça venait du fait que 1 fois preview décoché après un test avec preview... bah ça continu de bencher en mode "avec preview" si tu ferme pas l'appli

Reply

Marsh Posté le 27-02-2010 à 15:33:53    

Pas vraiment de news pour l'instant, je cherche comment rendre les réfractions correctement et comme cette semaine a été assez chargée j'ai pas énormément avancé.
 
Ma première idée était visiblement pas tout à fait la bonne et il semblerait que pour rendre les "caustiques" et autres objets enfermés dans des objets transparents ça soit un peu le bazar en dehors de scènes abusivement simples.
 
Je pense que je vais laisser l'algo comme ça, corriger un peu les horreurs dans les classes "objets" et démarrer le portage.
 
Concernant la cible, je ne pense pas qu'un changement de framework aurait une incidence vu que je n'ai rien utilisé de particulier, donc sauf grosses améliorations sur les collections ou le compilateur faut pas s'attendre à grand chose.
 
 
 
Edit: j'ai profité du nettoyage pour ajouter un filtrage bilinéaire sur les textures vu qu'elles pouvaient donner un truc bien laid... par contre maintenant c'est cette partie du code qui est laide [:ddr555]
 
En corrigeant le problème qui apparaît quand on tombe pile sur un texel (poids de 0) je me suis dit que si je pouvais n'aller le chercher qu'une fois plutôt que 2 ça serait plus efficace, seulement maintenant ça grouille de redondance. En fait la redondance vient du wrapping des coordonnées hors de l'intervalle UV [0,1[ et de la coordonnée "texture" qui peut passer à -1 ou max+1 avec les texels à filtrer.


Message édité par Gigathlon le 28-02-2010 à 00:37:45
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed