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 :

Optimisation de code : etrange


Sujet :

Langage Delphi

  1. #1
    Futur Membre du Club
    Inscrit en
    Novembre 2005
    Messages
    12
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 12
    Points : 8
    Points
    8
    Par défaut Optimisation de code : etrange
    Bonjour à tous,

    Voilà, je travaille pour l'heure sur l'optimisation de morceaux de programme.
    Et j'obtiens des resultats assez surprenants, donc si un maitre du delphi peut me renseigner sur le pourquoi de la chose...

    Je vous expose la chose :

    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
    procedure TWeather.Load(var f_temp:text; pheno: TRPhenoInfos; tempfit: integer);
    var
      i, j : integer;
      doy1, year1, codestation : integer;
      temp1,temp2,temp3,lat1:double;
      nb_days:integer;
     
      wd : TRWeatherDay;
      y_idx : integer;
     
      a_arr : vectdays;
     
      t : TDateTime;
     
      vec : array[1..50] of ^TRWeatherDay;
     
    begin
     
      LogIt('START Reading...'); t := Now;
     
      reset(f_temp);
      readln(f_temp); //skip header
     
      Self.SetSize(pheno.nb_obs);
     
      for j:=1 to pheno.nb_obs do
      begin
        y_idx := j-1;
     
        repeat readln(f_temp, codestation, lat1, year1, doy1, temp1,temp2,temp3)
        until (((codestation = pheno.Tabpheno[j].station) and (year1 >= pheno.Tabpheno[j].year)) or (codestation = 0));
     
        if (codestation = 0) then
            raise Exception.create('Station not found or stations in wrong order!');
     
     
        Self.year[y_idx] := TWeatherYear.Create(year1, y_idx, Self.selfPtr);
     
        wd := CreateWeatherDay(codestation, lat1, year1, doy1, temp1, temp2, temp3);
     
        if (tempfit = 1) then wd._tmu := wd._tmp
        else if (tempfit = 2) then wd._tmu := wd._tmn
        else if (tempfit = 3) then wd._tmu := wd._tmx;
     
        Self.year[y_idx].SetDay(doy1, wd);
     
        nb_days := Self.year[y_idx].numDays; //GetNbDays(v._yea);
        for i:=2 to nb_days do
        begin
     
          readln(f_temp, codestation, lat1, year1, doy1, temp1, temp2, temp3);
          if (codestation = 0) then
            raise Exception.create('Unexpected EOF found > the year could not be read entirely !');
     
          wd := CreateWeatherDay(codestation, lat1, year1, doy1, temp1, temp2, temp3);
     
          if (tempfit = 1) then wd._tmu := wd._tmp
          else if (tempfit = 2) then wd._tmu := wd._tmn
          else if (tempfit = 3) then wd._tmu := wd._tmx;
     
          Self.year[y_idx].SetDay(doy1, wd);
     
     
        end;
     
      end;
     
      LogIt('END Reading...' + FormatDateTime('ss.zzz', Now - t));
      new (vec[1]);
     
    end;
    Dans ce code, la ligne "new (vec[1]);" est, théoriquement, parfaitement inutile hors temps d'execution de la fonction :
    * ~6 sec si je commente "new (vec[1]);"
    * ~1.5 sec, si je mets le taille du tableau "vec" à 5000
    * ~0.71 sce, avec le code soumis ci-dessus.

    Y a t'il une raison à cela (je suppose que oui), mais j'ai besoin de vos conseils.
    Merci pour votre aide.

    PS : Je suis aussi preneur si vous avez des idees, a-priori, d'amelioration de mon algo.

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 548
    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 548
    Points : 25 118
    Points
    25 118
    Par défaut
    C'est mieux en Français

    Quel Delphi ?
    V7 ? FastMM ?
    A partir de D2007, FastMM est inclu, mais cela impacte surtout les chaines et les allocations par New (le tas) mais pas les variables de la pile (comme ton array)
    Tu devrais activer "ReportMemoryLeaksOnShutdown", tu dois avoir des fuites un peu partout avec du code si Etrange !

    ce sujet RAM non utilisée va te passionner !
    Cela va te donner pas mal d'info sur la mémoire ! l'allocation et la libération !



    Vec n'est pas du tout utilisé !
    Retire le New ET la déclaration, dis nous le temps !

    Si tu laisse l'étrange New, cela alloue un pointeur non libéré, c'est vrai que c'est moche !
    Si retire juste l'étrange New, tu n'aurais pas un Avertissement "Variable non utilisée" donc en théorie, je crois qu'elle n'est pas alloué sur la pile !

    Tu devrais mesurer le temps à l'extérieur de la fonction et à l'intérieur (ton cas actuel)

    Car, à part la libération de Vec lors du dernier "end", la présence de l'étrange New ne devrait pas changer grand chose !

    Utilise QueryPerformance Counter\Frequency, c'est plus fiable que Now() !

    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
    procedure GetBeginTime(var Value: Int64);
    begin
       QueryPerformanceCounter(Value);
    end;
     
    function ElapsedTime(var BeginTime: Int64): Cardinal;
    var
       EndTime, TickPerSec: Int64;
    begin
       QueryPerformanceCounter(EndTime);
       QueryPerformanceFrequency(TickPerSec);
       Result := Round((EndTime - BeginTime) / TickPerSec * 1000);
    end;
     
    function FormatMS(MilliSecondes: Cardinal): string;
    var
      Hour, Min, Sec: Cardinal;
    begin
      Hour := MilliSecondes div 3600000;
      MilliSecondes := MilliSecondes mod 3600000;
      Min := MilliSecondes div 60000;
      MilliSecondes := MilliSecondes mod 60000;
      Sec := MilliSecondes div 1000;
      MilliSecondes := MilliSecondes mod 1000;
      Result := Format('%.2d:%.2d:%.2d:%.3d', [Hour, Min, Sec, MilliSecondes]);
    end;
    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
    Inscrit en
    Novembre 2005
    Messages
    12
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 12
    Points : 8
    Points
    8
    Par défaut
    Merci beaucoup pour toutes ces infos.

    Le temps en virant la ligne qui ne sert a rien est déja mentionné : 6sec.

    J'ai deja intégré FastMM avec stack trace et tout. Et en effet j'ai pas mal de fuites connues que je n'ai pas encore pris le temps de corriger.
    Tu penses que ca expliquerait les delires de perfs dans mon code ?

    Parce qu'en effet "l'etrange new" ne sert strictement à rien : comment on peut passer de quelques fuites memoires (ma ram n'est pas tant solicitée que ca), à des comportements aussi louches ?

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 548
    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 548
    Points : 25 118
    Points
    25 118
    Par défaut
    Citation Envoyé par golgauth Voir le message
    Le temps en virant la ligne qui ne sert a rien est déja mentionné : 6sec.
    en supprimant le New, oui tu l'as déjà donné, moi je te parle de retirer vec : array[1..50] of ^TRWeatherDay; qui ne sert strictement à rien puisque pas utiliser (sauf ce étrange new)
    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
    Inscrit en
    Novembre 2005
    Messages
    12
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 12
    Points : 8
    Points
    8
    Par défaut
    Oui, alors j'ai effectivement viré la declaration (array[0..50]...) et ca donne 6 secondes. Idem...

    Je jete un coup d'oeil a tes lien.

    Thanks a lot again
    Regards

    Edit : Desolé, j'ai oublié de répondre à tes questions :
    - Je suis sous delphi 2010

  6. #6
    Futur Membre du Club
    Inscrit en
    Novembre 2005
    Messages
    12
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 12
    Points : 8
    Points
    8
    Par défaut
    Apres reflexion, est-ce que la presence de cette ligne inutile ne serait-elle pas responsable d'une optimisation differente (meilleure) par le compilateur delphi. Je ne suis pas tres au fait de comment voir ca via le code asm generé.
    Je ragarde comment visualiser les codes asm avec et sans la ligne etrange...

  7. #7
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 173
    Points
    4 173
    Par défaut
    En travaillant avec des fichiers, il faut t'attendre à ce que les performances soient aléatoires.
    Tu dépends énormément de l'état de la machine : Etat des caches disques, ce que fais Windows en tâche de fond... De plus, à chaque fois que ton appli fait une E/S tu donnes une opportunité à Windows de prendre la main pour faire autre chose...

    Lorsque tu exécutes ton appli une première fois à froid, Windows doit lire le fichier depuis le disque. Mais si tu recommences juste derrière, le fichier est présent en cache et la lecture est beaucoup plus rapide.
    Pour mesurer tes temps, tu as bien lancé plusieur fois le même traitement dans les mêmes conditions pour identifier le temps le plus caractéristique ?

    Si le fichier n'est pas trop volumineux, tu ferais mieux de le charger intégralement en mémoire au début du traitement (par exemple avec un TStringList), puis analyser le contenu toi même.
    Les performances seront bien meilleures.

  8. #8
    Futur Membre du Club
    Inscrit en
    Novembre 2005
    Messages
    12
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 12
    Points : 8
    Points
    8
    Par défaut
    Salut et merci pour vos reponses,

    Pour mesurer tes temps, tu as bien lancé plusieur fois le même traitement dans les mêmes conditions pour identifier le temps le plus caractéristique ?
    Oui.

    Si le fichier n'est pas trop volumineux, tu ferais mieux de le charger intégralement en mémoire au début du traitement (par exemple avec un TStringList), puis analyser le contenu toi même.
    Le soucis est que je manipule, potentiellement plusieurs fichiers (en multi-thread) pouvant atteindre 400000 lignes. Je pense que c'est un peu violent pour des StringLists...

    De plus mes resultats ne sont pas du tout aléatoires : j'obtiens toujours la meme choses...

Discussions similaires

  1. optimiser le code d'une fonction
    Par yanis97 dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 15/07/2005, 08h41
  2. Optimiser mon code ASP/HTML
    Par ahage4x4 dans le forum ASP
    Réponses: 7
    Dernier message: 30/05/2005, 10h29
  3. optimiser le code
    Par bibi2607 dans le forum ASP
    Réponses: 3
    Dernier message: 03/02/2005, 14h30
  4. syntaxe et optimisation de codes
    Par elitol dans le forum Langage SQL
    Réponses: 18
    Dernier message: 12/08/2004, 11h54
  5. optimisation du code et var globales
    Par tigrou2405 dans le forum ASP
    Réponses: 2
    Dernier message: 23/01/2004, 10h59

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