IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Problèmes étranges avec le dual core


Sujet :

Langage Delphi

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 11
    Points : 7
    Points
    7
    Par défaut Problèmes étranges avec le dual core
    Bonjour je me permets vous solliciter car je suis confronté a un problème étrange que je n'arrive pas à résoudre.

    Je développe une application musicale.
    Je passe les détails mais en gros j'ai deux threads:
    - un audio, highest, time critical qui gère le flux audio
    - un autre Idle qui gère l'affichage

    J'ai un option dans le setup de l'appli qui me permet d'activer le dual core, càd soit je me sert d'un seul core pour les deux threads soit chaque thread est executé par un core different.

    voici le problème.

    En mode nono core, l'application se comporte très bien, c'est à dire que le thread audio (time critical) est très stable et l'affichage est plus ou moins rapide en fonction de la charge cpu. Bref tout est normal, c'est à dire que les priorités des theads sont respectés. En cas de charge cpu important l'écran se fige mais l'audio reste stable.

    En mode dual core contre toute attente se comporte beaucoup moins bien puisque à partir d'une certaine charge du cpu audio le thread Idle semble interférer avec le thread audio (time critical) et bloque ce dernier.

    Je précise, après analyses qu'il semble que se soit au moment du BitBlit de windows que j'utilise pour copier les canvas ou DC.
    Comme si le thread IDLE provoquait un lock du thread audio...(?)

    Avez vous déjà été confrontés à un problème similaire, et avez vous des pistes pour le résoudre?

    merci+++++

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    On peux supposer que le Thread Audio envoie des informations vers le Thread Idle par exemple pour l'Equalizer (c'est le nom je crois ?) ...

    Si oui, tu as donc une section critique, est-il possible qu'elle soit trop étendue en traitement et donc provoque un Lock trop long ?

    Si non, le dual core, est-ce vraiement du bi-proc ? et ensuite le Thread GDI de Windows est sur quel processeur ? n'y aurait-il un grand échange d'info à ce moment ? Sur un mono-core, le Thread Audio est proritaire, et le Thread Idle travaille quand il peut ... sur un dual-core, les deux Thread sont indépendants et si le Thread Idle réclame du Temps Système qui tourne sur le processeur du Thread Audio, ce dernier se voit naturellement bloqué ...

    Au fait, tu as 2 ou 3 Thread ?
    Audio, Idle (générant des BMP) et le Thread VCL (Application.Run) ???
    Si oui, pourquoi ne pas généré l'image à afficher dans Bitmap temporaire (faire un switch, entre deux objets, un en cours de remplissage, l'autre en cours de lecture "DoubleBuffered", la section critique ne protégeant pas l'accès à la bitmap mais l'autorisation de switcher, le mieux étant de le faire avec une rotation sur trois bitmap, ainsi il y a toujours la possibilité de switcher sur un binome, le troisième pouvant être en cours d'utilisation ...)
    Et mettre justement, le BitBlt dans la TPaintBox (ou autre composant visuel) dans l'évènement OnIdle de l'application (là où normalement, la charge est la plus faible ...)

    Pour ce qui est des priorités, cela change-t-il vraiement grand chose ?
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 11
    Points : 7
    Points
    7
    Par défaut
    merci de t'intéresser à mon pb.
    C'est vrai qu'on commence à entrer dans un domaine que je ne maitrise pas vraiment, il faut le dire...

    On peux supposer que le Thread Audio envoie des informations vers le
    Thread Idle par exemple pour l'Equalizer (c'est le nom je crois ?) ...
    A priori non, quand j'ai besoin d'afficher qqchose, depuis ce thread, j'utilise un système de messages interne, ces messages étant gérés par le thread Idle.

    Si oui, tu as donc une section critique, est-il possible qu'elle soit trop étendue en traitement et donc provoque un Lock trop long ?
    J'utilise des lock.aquire ... lock.release pour protéger la mémoire mais seulement dans certains cap précis qui ne sont pas appliqués dans le cas présent. De toutes façons ça ne change rien quand je les enlèves.

    Si non, le dual core, est-ce vraiement du bi-proc ?
    oui un core 2 duo 7200

    et ensuite le Thread GDI de Windows est sur quel processeur ? n'y aurait-il un grand échange d'info à ce moment ? Sur un mono-core, le Thread Audio est proritaire, et le Thread Idle travaille quand il peut ... sur un dual-core, les deux Thread sont indépendants et si le Thread Idle réclame du Temps Système qui tourne sur le processeur du Thread Audio, ce dernier se voit naturellement bloqué ...
    Au fait, tu as 2 ou 3 Thread ?
    Là tu touches un point très sombre pour moi.
    Dans mon code je n'ai crée que 1 thread time critical audio et un simple TTimer. Mais quand je fais la liste de threads de l'appli j'en ai 8 au total.
    D'ou viennent-ils?
    Visiblement je n'ai aucun moyen de changer leur priorité ou leur AffinityMask et je ne sais pas d'où ils sortent...

    Audio, Idle (générant des BMP) et le Thread VCL (Application.Run) ???
    Si oui, pourquoi ne pas généré l'image à afficher dans Bitmap temporaire (faire un switch, entre deux objets, un en cours de remplissage, l'autre en cours de lecture "DoubleBuffered", la section critique ne protégeant pas l'accès à la bitmap mais l'autorisation de switcher, le mieux étant de le faire avec une rotation sur trois bitmap, ainsi il y a toujours la possibilité de switcher sur un binome, le troisième pouvant être en cours d'utilisation ...)
    Je ne suis pas sûr de tout bien comprendre, et je m'excuse de paraitre un peu blaireau sur ce coup...mais je crois qu'il va me falloir un petit exemple...

    Je te donne un exemple de code que j'utilise pour le paint d'un composant genre TPanel descendant de TCustomControl.
    J'utilise le librairie GR32 avec un PBTemp : TBitmap32; Je pense qu'on est dans le standard?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    procedure Tpatch.Paint;
    .....
      PBTemp.FillRectS(0,0,width,Height,color32(clPatchBack));
      larg := PBTemp.TextWidth(St);
      haut := PBTemp.TextHeight(St);
      PBTemp.TextOut(GLOB_MARGIN,GLOB_MARGINx2+DEFAULT_HEIGHT,St);
    ....    
    BitBlt(Canvas.Handle,0,0,width,height,PBTemp.canvas.Handle,0,0,SRCCOPY);
    end;
    En gros ça ressemble à ça avec en plus un TTimer genre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    procedure TTimer.onTimer;
    ...
      patch.paint;
    ...
    assez simple donc.

    Et mettre justement, le BitBlt dans la TPaintBox (ou autre composant visuel) dans l'évènement OnIdle de l'application (là où normalement, la charge est la plus faible ...)
    Concrètement ça veux dire quoi?
    Il faudrait vraiment que l'affichage soit fait en tache de fond quoi qu'il arrive.

    Pour ce qui est des priorités, cela change-t-il vraiement grand chose ?
    non rien du tout.

    Merci pour ton aide!

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Ok, donc tu as le Thread Audio, et le Thread VCL (le Timer utilise un message qui est géré dans la boucle Run, ...)

    Les autres Threads peuvent venir des composants que tu utilises, ... difficile de tous les trouver ...

    Pour ton système de message, c'est le Timer qui fait une demande, il attend la demande, le Thread Audio la gérant quand il en a le temps ... ça ne devrait pas géner ...

    La lib GR32, est effectivement bcp utilisée ...

    Je n'ai pas d'exemple pour l'histoire des buffers BMP (je t'en ponds un à partir d'un essai que j'avais commencé pour le jeu snake mais que je n'ai jamais eu le temps de finir n'ayant plus d'ordi à la maison), et dans ton cas, ce n'est pas nécessaire, ... le Thread VCL s'occupe de tout ce qui est Affichage ... mais je peux te l'expliquer :

    Donc, tu as le Thread VCL ce qui correspond à Application.Run, on utilise soit un Timer soit l'évènement OnIdle pour appeler TDisplayEngine.DrawTo, le code est un peu gourmand, bcp de création libération de BitMap, avec trois buffer et autant de sections critiques (utilisées différent et bloquant vraiement autour de la fonction Draw et non pas juste l'inversion des variables) cela permet d'avoir un sytème plus léger (toujours 3 objet en mémoire mais moins de mouvement en mémoire), et si je retrouve le code que j'avais fait, je le mets ici

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    type
      TDisplayEngine = class(TObject)
      private
        FActive: Boolean;
        function SwitchBitmap(NewBitmap: TBitmap): TBitmap;
        function GetDrawBitmap: TBitmap;
      public
        class procedure DrawTo(ACanvas: TCanvas);
     
        property Active: Boolean read FActive;
        property DrawBitmap: TBitmap read GetDrawBitmap;
    end;
     
    var
      _DisplayEngine: TDisplayEngine = nil; // Créer dans TDisplayEngine.Start, c'est une sorte de singleton car on ne peut pas instancier TDisplayEngine directement, on n'utilise que les méthodes de classes
     
    class procedure TDisplayEngine.DrawTo(ACanvas: TCanvas);
    begin
      if Assigned(_DisplayEngine) and _DisplayEngine.Active then
      begin
        ACanvas.Draw(0, 0, _DisplayEngine.DrawBitmap);
        _DisplayEngine.DrawBitmap.Free(); // On Libère l'image utilisée 
      end;
    end;
     
    function TDisplayEngine.SwitchBitmap(NewBitmap: TBitmap): TBitmap;
    begin
      FDrawBitmapLock.Acquire();
      try
        Result := FDrawBitmap;
        FDrawBitmap := NewBitmap;
      finally
        FDrawBitmapLock.Release();
      end;
    end;
     
    function TDisplayEngine.GetDrawBitmap: TBitmap;
    begin
      FDrawBitmapLock.Acquire();
      try
        Result := FDrawBitmap;
        FDrawBitmap := nil;
      finally
        FDrawBitmapLock.Release();
      end;
    end;
     
    procedure TDisplayEngine.TreatActionDraw;
    var
      DrawingBitmap: TBitmap;
      iCol, iRow: Integer;
    begin
      DrawingBitmap := TBitmap.Create();
      DrawingBitmap.Height := _DisplayEngine.FHeight;
      DrawingBitmap.Width := _DisplayEngine.FWidth;
      DrawingBitmap.BlaBlaBla ... DrawLine, Rect, FillRect, CopyRect, ... 
     
      _DisplayEngine.SwitchBitmap(DrawingBitmap).Free(); // Cela libère l'ancienne image, une nouvelle prend a pris sa place, si elle n'a pas été utilisé entre temps ...
    end;
     
    procedure TDisplayEngine.Execute;
    var
      Action: TDisplayAction;
    begin
      while not Terminated do
      begin
        Action := PopAction();
        case Action.ActionType of
          tatNone : TreatActionNone();
          tatDraw: TreatActionDraw();
          ...
        end;
        Sleep(1);
      end;
    end;
    J'ai effectivement l'impression, que Windows effectue l'affichage dans le compo BitMap32 sur le Proc du Thread Audio, c'est très con, ce n'est pas un traitement asynchrone (du moins je ne crois pas), il devrait rester sur le processeur en cours ... c'est la seule explication que je vois ... vérifie sinon, si le composant BitMap32 n'aurait pas une gestion de Double Buffer lui aussi, et qu'il n'aurait lui aussi un Thread caché (vu ce que j'ai vu sur la doc ICI)
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 11
    Points : 7
    Points
    7
    Par défaut
    Merci encore pour le coup de pouce!

    J'ai viré tous les mécanismes de lock sur la TBitmap32 mai rien n'y fait. Sur certaine fonctions c'est dément, on dirait que l'accès à la mémoire du DC est locké automatiquement. C'est possible ça?
    Je m'explique, par exemple une des fonction TBitmap32.FillRect ne fait que du byte-copy sur un pointer du DC, sans aucun lock et pourtant il y a conflit de thread...
    J'en perds mon latin comme dirait mon prof de 3ème.

    Je vais jeter un oeil sur ton code pour comprendre d'autres techniques et voir quel sont les influences. Mais l'avantage de la lib GR32 est qu'elle est très rapide.
    Quand j'utilise les fonctions standard de Tcanvas, il y moins de pb de lock mais je perds beaucoup en performances globales.

    Sinon, tu sais comment forcer l'affinyMask d'un thread. Quand je fais SetThreadAffinityMask, rien ne se passe... ni avec SetIdealProc. Ca marche pour le process global mais pas pour les threads.

    PS:c'est vraiment la merde le dual-core.

    merci+++

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Je n'ai jamais réussi à changer non plus les threads de place ...

    Sinon, je pense que c'est justement le TBitmap32 qui contient lui-même un thread qui bloque ...
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 11
    Points : 7
    Points
    7
    Par défaut
    je vais regarder ça d'un peu plus près encore!
    merci pour les tuyaux...

  8. #8
    Membre éclairé
    Profil pro
    Développeur Java
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 681
    Points
    681
    Par défaut
    Bonjour,

    j'ai lu avec intérêt le post (bon j'ai pas tout compris). Mais, j'ai trouvé quelque chose qui peut peut-être vous intéresser, quelqu'un à déjà eu ce problème :
    http://www.delphipages.com/threads/t...62246&G=162229

    Par contre, j'ai deux question :
    - ce que j'ai compris c'est que SetThreadAffinityMask indique sur quel processeur on doit faire fonctionner le thread non ?
    si ça ne fonctionne pas, dans la doc MSDN, ils indiquent qu'il faut que le thread est les droits THREAD_SET_INFORMATION et THREAD_QUERY_INFORMATION,
    - il y a SetProcessAffinityMask, c'est la même chose mais pour un processus ?

    En espérant être utile.

    PS : comment savoir si on tourne sur un processeur multi-core ou si on a plusieurs processeur ? Pour intel j'ai trouvé ça http://www.developpez.net/forums/sho...d.php?t=372167
    PS2 : je ne trouve pas les valeurs pour dwThreadAffinityMask dans la doc MSDN

Discussions similaires

  1. Problème étrange avec DBM::Deep
    Par scaleo dans le forum Modules
    Réponses: 3
    Dernier message: 23/03/2007, 10h51
  2. Problème étrange avec un integer
    Par Pedro dans le forum Delphi
    Réponses: 6
    Dernier message: 05/12/2006, 21h08
  3. Problème étrange avec DecimalSeparator ?
    Par MaTHieU_ dans le forum Delphi
    Réponses: 2
    Dernier message: 13/07/2006, 09h14
  4. problème étrange avec excel
    Par lanfeust42 dans le forum Modules
    Réponses: 1
    Dernier message: 15/06/2006, 10h57
  5. [FLASH MX2004 PRO] Problème étrange avec LoadClip...
    Par josemoroide dans le forum Flash
    Réponses: 6
    Dernier message: 04/08/2004, 15h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo