C# : System.Drawing et performances... - C#/.NET managed - Programmation
Marsh Posté le 12-04-2006 à 07:52:31
Bon ben euh ils font pareil...
http://www.codeproject.com/cs/medi [...] rawing.asp
Marsh Posté le 12-04-2006 à 09:41:18
ReplyMarsh Posté le 12-04-2006 à 10:42:37
Ouais, mais c'est quoi au juste ?
J'ai VS 2005 Team Suite Tester / (ou Developer) chais pas au juste
-> Et j'ai tout un tas d'assistants qui me permettent d'auditer mon code pour voir s'il est rapide, bien écrit et tout ça. C'est la même chose ou ça n'a rien à voir ? En fait, je bute sur le mot "profiling"
Marsh Posté le 12-04-2006 à 13:14:46
Genre tu lances nProf, t'ouvres ton .exe, t'exécute normalement ton machin, puis tu quitte. Là il t'affichera tout le déroulement de ton prog, avec le temps pris par chaque fonction. Comme ça tu pourra voir laquelle est celle qui prend le plus de temps
Marsh Posté le 12-04-2006 à 14:27:25
ben c'est tout vu, c'est le "drawimage" qui recopie le bitmap du double buffer dans le graphics de ma form. mes tests confirment ce point à 100%, aucun doute possible.
mais c'est justement là le problème : comment réduire ce temps au minimum possible ?
je peux modifier en tentant de jouer avec la zone à redessiner, mais rapidement les éléments qui bougent vont prendre toute la fenêtre, donc à la base ça va plus alourdir les traîtements qu'autrechose, pour un gain vraiment faible...
Marsh Posté le 12-04-2006 à 15:08:54
ReplyMarsh Posté le 12-04-2006 à 16:35:52
chagarou a écrit : DirectX? |
DirectDraw n'existe plus, et c'est remplacé par GDI+
Et je vais pas me repalucher un moteur 3D pour faire de la 2D
Marsh Posté le 12-04-2006 à 16:37:28
FlorentG a écrit : Sinon ch'ais pas, en utilisant l'évènement OnPaint plutôt |
Tu ferais ça comment ? Parceque là, moi j'ai pas d'idée, à la base il se lance au moment du render, mais pas si je fais pas un invalidate() manuel (si je vais pas le render)
Et le invalidate() ça fait encore pire : non seulement ça ramme, mais ça fait du flickering même avec le double buffer
Marsh Posté le 12-04-2006 à 20:46:53
Pour en revenir au problème de performances, j'ai donc pas pris "nProf", puisque VS 2005 a déjà tout ce qu'il faut.
Voici le résultat (grosse n'image) :
http://www.manga-torii.com/images/performance.PNG
Donc, comme je disais, en "exclusive", l'EXE principal bouffe seulement... 0% de l'occupation CPU globale, et le moteur 2D 1,768%.
Par contre, en "inclusive", on voit bien en effet que le moteur 2D bouffe 83,929%.
Quand je rentre dans le détail, et que je regarde les fonctions appelée/appelantes, c'est bien le "DrawImage" qui est directement dans "Engine.Render()" qui bouffe 66,667% alors que les multiples appels dans "EngineItem.Render()" ne bouffent en tout que 9% environ...
J'ai donc bien une couille dans le potage avec cette histoire de double buffer : autant la génération de l'image "shadow" est rapide et ne pose pas de problème de performances, autant la simple recopie de cette image dans le Graphics de ma forme fait tout s'effondrer.
A noter que j'ai fait le test en mode fenêtré, avec une petite fenêtre. En plein écran ça doit être largement pire/flagrant étant donné que ça arrive à ralentir toute l'application.
Marsh Posté le 12-04-2006 à 21:31:31
P'tain si j'avais le temps, j'aurais donné un essai Peut-être demain soir ou vendredi j'peux essayer d'essayer...
Marsh Posté le 12-04-2006 à 23:33:53
C'est pas un problème. Merci si tu peux me filer un coup de main, mais sinon c'est pas grave
Là je viens de tout essayer, pas moyen de trouver ce qui cloche.
Une âme charitable m'a filé les sources d'un moteur 2D basé sur D3D. D'expérience, parceque j'avais déjà bidouillé un peu avec D3D, ça va solutionner mon problème. Mais j'aurais bien voulu trouver ce qui déconnait avec GDI, c'est pas normal que ça ramme comme ça.
Je crois que j'ai tout tenté là, pas moyen de trouver ce qui cloche. J'ai clippé tout ce que je pouvais, boundé comme un malade, jusqu'à ce que plus rien ne marche... Mais que pouic, ça n'a rien changé.
J'ai suivi à la lettre les warning d'audit du code de VS... Au point d'avoir une application ne voulant plus démarrer faute de permissions... J'ai quasiment plus aucun "new" de goret inutile (genre un new d'un Region -type extrêment gourmand en mémoire- dans un while). Bref, tout mon code est à priori optimisé au maximum de ce que je pouvais faire, mais j'ai pas vu un pouillème de différence
(bon, je vous rassure j'ai pas passé toute la soirée dessus... 2 heures max, c'est déjà trop vu le résultat )
Marsh Posté le 12-04-2006 à 23:40:25
Si tu veux partir de ce que j'ai fais pour trouver ce qui cloche...
http://www.manga-torii.com/images/ant.zip (1,1 Mo - projet complet, programme + moteur 2D. J'ai pas fait de nettoyage)
-- Je viens de voir que j'aurais pu virer mon "Visual Studio Performance Report" avant de zipper... Il fait 10 Mo
T'étonne pas du truc, à la base c'est pour faire un "simulateur de fourmis", genre 1000 trucs qui se balladent à l'écran et cherchent quelquechose puis retournent d'où ils viennent avec, afin de me familiariser avec différentes techniques de findingpath et de gestion des collisions.
Eh oui, le but du jeu c'était pas de me prendre la tête avec GDI... Mais si ça ramme avant même de faire le moindre bout d'algo de FindingPath, c'est même pas la peine
Marsh Posté le 04-05-2006 à 00:10:00
tu le compiles en mode debug ?
Parce que j'ai déja remarqué d'énorme différence si on utilise le mode debug ( c'est beaucoup beaucoup plus lent )
Marsh Posté le 04-05-2006 à 12:03:39
Ben mes tests étaient avec VS Express. Et j'ai pas trouvé comment compiler en release avec cette version.
Ce soir, j'aurai enfin les DVD MSDN qu'on attend depuis 3 mois, verrai ce que ça donne avec.
Marsh Posté le 22-02-2008 à 16:41:39
Bonjour,
j'ai le même problème et je me suis rendu compte que la technique du double buffering était inutile dans mon cas également.
Après de nombreux tests et avoir logger les temps d'éxécution des méthodes, j'ai l'impression qu'il y a un temps d'attente incomprésible lors du premier appel à des fonctions tels que DrawImage (probableùment du à l'initialisation de composant ou chargement de DLL).
J'appele plusieurs fois la méthode Drawimage avec la même image (toujours sur le même fond) et à la même position : premier appel de 0,1 à 0,2 s tous les suivants (une centaine) moins de : 0,0001 s.
Ce que je ne comprend pas c'est que si je fais une boucle par dessus ces appels, je me tape pour chaque boucle cet appel 0,1 à 0,2 s suivi d'une centaine de 0,0001 s !
Marsh Posté le 11-04-2006 à 21:24:58
Salut, j'ai un "léger" souci de performances avec System.Drawing
Bon, ok, je cherche le diable à bosser en plein écran sur mon 24" mais bon...
Le but du jeu, c'est d'avoir à l'écran un truc fluide à l'écran, et sans clignotements.
J'ai suivi cet article (cet section "Double Buffering Technique The .NET Way" ) afin de virer les clignottements. Ca marche bien, et autant c'est rapide et sans consommation CPU dans une fenêtre de la taille par défaut, autant quand je passe en plein écran... 100% CPU sur un AMD 3500+ et ça oublie de dessiner toutes les 10ms... C'est plutôt toutes les 20/30ms...
(ok, je laisserai peut-être pas un ticker de 10ms, ça sert pas à grand chose maintenant que les gens sont pour la plupart en CRT à 60 ou 75Hz max)
Après tests (viré tous mes éléments à l'affichage sauf 1, et shooté tous mes traîtements pour remplacer par un déplacement d'une image de 10x10 de façon rectiligne), ça ramme toujours à donf.
Il semble donc que ce soit le coup du "DrawImage" de mon image tampon qui fout tout à plat. D'après l'article, c'est censé être performant, et malgré certaines optimisations que j'ai tenté d'apporter, ça ramme toujours autant.
D'après l'auteur, passer par la lib Win32 est plus lent, et surtout c'est plus gore, donc j'ai pas testé (et aucune envie de le faire).
Y'a un bout que j'ai mal recopié ? Ou des méga-conneries dans mon code et j'en suis pas conscient ?
L'article date de 2002... Je suppose que depuis, ça a dû évoluer... Il doit se baser sur la version 1.0 du FrameWork, et on en est à la 2.0... Y'a une meilleure solution qui a vu le jour depuis ?
Voici les bouts de mon code qui sont concernés :
En bref, plutôt que de recréer un Graphics new à chaque ittération du "Render", je lui efface les zones des anciens sprites dans le "PreRender" via des Clip, puis je redessine les sprites une fois qu'ils ont bougé.
Ceci dit, ça ne change rien
A priori, c'est bien la recopie du gros Bitmap temporaire qui plombe tout.
Message édité par Arjuna le 11-04-2006 à 21:30:12