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

Lazarus Pascal Discussion :

[Raspberry Pi] Compteur et précision


Sujet :

Lazarus Pascal

  1. #1
    Membre confirmé

    Inscrit en
    Novembre 2002
    Messages
    789
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 789
    Points : 505
    Points
    505
    Par défaut [Raspberry Pi] Compteur et précision
    Bonjour,

    CPU : Raspberry PI 4 B
    OS : RASPBIAN
    Langage : LAZARUS 2.0.0 + dfsg - 2
    Compilateur : FPC 3.0.4

    Je cherche à faire un genre de "chrono" pour mesurer des temps d'exécution de routine, donc avec une précision à la µs.

    Mes recherches m'ont amenées à trouver l'exemple ci dessous, mais que je n'arrive pas à faire fonctionner.

    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
    unit UCompteurNano;
     
    {$mode objfpc}{$H+}
     
    interface
     
    uses
      Classes, baseUnix, SysUtils, cthreads, Ctypes;
     
    Procedure DebCompteur;
    function  FinCompteur:string;
     
    Const
      CLOCK_MONOTONIC = 1;
     
    Type
      timespec = record
        tv_sec   : time_t;
        tv_nsec : clong;
      end;
    var startTime : timespec;
         EndTime   : timespec;
     
        Procedure clock_gettime(clk_id : cint; tp:ptimespec); cdecl; external 'C' name 'clock_gettime';
     
    implementation
     
    Procedure DebCompteur;
    begin
        clock_gettime(CLOCK_MONOTONIC, @startTime);
    end;
     
    function FinCompteur:string;
    Var duree:Int64;
    begin
       clock_gettime(CLOCK_MONOTONIC, @EndTime);
       duree:=(EndTime.tv_sec - StartTime.tv_sec)*1000000000;
       duree:=duree + (EndTime.     tv_nsec - StartTime.tv_nsec);
       result:=IntToStr(duree) + 'ns';
    end;
     
    end.
    D'après ce que j'en ai compris, j'utilise une librairie en "C" dans Lazarus, je pense que cette utilisation me pose des problèmes.
    De plus je ne sais pas si cette librairie est installée sur mon Raspberry.

    Lorsque je met les deux unités suivantes "cthreads, Ctypes", le code se compile, mais le programme ne se lance plus.
    Si j'ajoute l'appel à la " DLL => clock_gettime ", le code ne se compile plus.

    Si quelqu'un a des idées, je suis bien sur preneur !

    bonne soirée.
    Bye et bon code...

    Ce n'est pas tant l'aide de nos amis qui nous aide , mais notre confiance dans cette aide .

  2. #2
    Expert confirmé

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 497
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 497
    Points : 4 756
    Points
    4 756
    Par défaut
    Bonjour,

    Je ne pourrais pas aider sur cet environnement mais la mesure de temps est très difficile sur les systèmes multitâches. Un peu comme vouloir connaître la durée d'un film malgré les encarts publicitaires.

    Faire de la mesure intrinsèque (hors interruption du fil de traitement) revient à rechercher le minimum du temps sur un grand nombre d'exécutions. Dans le cas des routines courtes, le temps de boucle et la durée de mesure du temps ne sont plus négligeables.

    La mesure intégrée donne un temps réaliste d'utilisation (avec les éventuelles interruptions) . Dans ce cas, on ne mesure pas le temps de chaque exécution mais celui d'un grand nombre.

    Quand on répète l'exécution d'une routine, il convient d'en utiliser (même de façon idiote) le résultat. Sinon le compilateur peut se rendre compte que les itérations ne servent à rien et carrément sauter toute la boucle de test ce qui donne des résultats fantastiques... ...mais faux.

    Par ailleurs, les résultats ne sont pas exportables. Les résultats seront différents sur une machine plus ou moins puissante, mieux ou moins bien ventilée, avec un autre compilateur, selon le niveau de priorité du programme, cohabitant avec d'autres applications, etc.

    Je me sers seulement de la comparaisons de temps entre deux versions d'une même routine afin de choisir la meilleure. Et même là, il faut faire attention. La première routine testée essuie les plâtres (l'IDE de développement lance des sauvegardes après la compilations qui se déroulent en partie durant les premiers tests et peuvent les alourdir).

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  3. #3
    Expert éminent
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 116
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 116
    Points : 9 626
    Points
    9 626
    Par défaut
    Hello,
    il y a le composant TEpikTimer présent dans le Online Package manager qui permet de faire des mesures précises de temps :
    EpikTimer est un chronomètre de programmeur capable de mesurer des événements très courts avec une précision traçable sur de longues périodes.
    Il existe en composant GUI mais on peut aussi l'utiliser en mode console (dans les paquets requis ajouter etpackage). Voici un exemple d'utilisation en mode console :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    program project1;
    uses classes, etpackage; 
    var
      ET: TEpikTimer;
    begin
      ET := TEpikTimer.Create(nil);
      ET.Clear;
      ET.Start;
      ET.SystemSleep(2000); // Tempo 2000 millisecondes
      Writeln(ET.Elapsed);
      readln;
    end.
    Ami calmant, J.P
    Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

  4. #4
    Membre confirmé

    Inscrit en
    Novembre 2002
    Messages
    789
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 789
    Points : 505
    Points
    505
    Par défaut
    bonjour à vous ,

    @ Guesset, je suis d'accord avec toi, je cherchais juste à avoir un chrono juste pour faire des tests comparatifs. Quitte à mettre les bouts de routine dans une bouche pour multiplier leur temps d'exécution, et en déduire une durée.

    @Jurrasic pork, ce chrono est en effet facilement mis en œuvre. Si sa base de temps est de l'ordre de 1µs (que j'ai pas pu confirmer), sa précision est de la milliseconde. Nous pouvons jouer sur la précision " ET.StringPrecision" mais seulement pour l'affichage du résultat.
    je suis allez voir le "GetSystemTicks":
    La fonction GetSystemTicks renvoie le nombre de cycles système fournis par le système d'exploitation. La précision de cette fonction dépend de la résolution du minuteur système, qui est généralement de l'ordre de la milliseconde
    je crois que je vais devoir attendre d'avoir un oscilloscope sous la main !

    merci a vous deux .
    Bye et bon code...

    Ce n'est pas tant l'aide de nos amis qui nous aide , mais notre confiance dans cette aide .

  5. #5
    Rédacteur
    Avatar de Chrispi
    Homme Profil pro
    Chargé de missions
    Inscrit en
    Juin 2020
    Messages
    230
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations professionnelles :
    Activité : Chargé de missions
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2020
    Messages : 230
    Points : 1 174
    Points
    1 174
    Par défaut
    Bonjour petitcoucou31,

    Je ne bosse pas sur ce type d'environnement mais le sujet a piqué ma curiosité.
    J'ai trouvé le code qui suit. Tu peux peut-être l'essayer et éventuellement le corriger et/ou l'adapter.

    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
    76
    77
    78
    79
    80
    81
    82
    83
    unit UnitChronometer;
     
    {$mode objfpc}{$H+}
     
    interface
     
    uses
      Classes, SysUtils, Forms, StdCtrls, Unix;
     
    type
      TForm1 = class(TForm)
        StartButton: TButton;
        StopButton: TButton;
        ResetButton: TButton;
        Label1: TLabel;
        procedure StartButtonClick(Sender: TObject);
        procedure StopButtonClick(Sender: TObject);
        procedure ResetButtonClick(Sender: TObject);
      private
        FStartTime: TTimeVal;
        FStopTime: TTimeVal;
        FRunning: Boolean;
        function GetElapsedTime: Double;
      public
        property ElapsedTime: Double read GetElapsedTime; // Temps en microsecondes
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.lfm}
     
    { TForm1 }
     
    procedure TForm1.StartButtonClick(Sender: TObject);
    begin
      if not FRunning then
      begin
        fpgettimeofday(@FStartTime, nil); // Démarrer le chronomètre
        FRunning := True;
      end;
    end;
     
    procedure TForm1.StopButtonClick(Sender: TObject);
    begin
      if FRunning then
      begin
        fpgettimeofday(@FStopTime, nil); // Arrêter le chronomètre
        FRunning := False;
        Label1.Caption := Format('Temps écoulé : %.3f μs', [ElapsedTime]);
      end;
    end;
     
    procedure TForm1.ResetButtonClick(Sender: TObject);
    begin
      FStartTime.tv_sec := 0;
      FStartTime.tv_usec := 0;
      FStopTime.tv_sec := 0;
      FStopTime.tv_usec := 0;
      FRunning := False;
      Label1.Caption := 'Temps écoulé : 0 μs';
    end;
     
    function TForm1.GetElapsedTime: Double;
    var
      StartMicros, StopMicros: Int64;
    begin
      if FRunning then
      begin
        // Si le chronomètre est toujours en cours, utiliser l'heure actuelle
        fpgettimeofday(@FStopTime, nil);
      end;
      // Convertir les valeurs en microsecondes
      StartMicros := (FStartTime.tv_sec * 1000000) + FStartTime.tv_usec;
      StopMicros := (FStopTime.tv_sec * 1000000) + FStopTime.tv_usec;
     
      // Calculer le temps écoulé
      Result := StopMicros - StartMicros;
    end;
     
    end.
    Quelques explications :

    fpgettimeofday :

    • Récupère l'heure actuelle avec une résolution à la microseconde.
    • Retourne un TTimeVal, contenant les secondes (tv_sec) et microsecondes (tv_usec).


    Calcul du temps écoulé :

    • Les deux champs tv_sec et tv_usec sont combinés pour obtenir une durée totale en microsecondes.


    Chronomètre :

    • Démarrage avec fpgettimeofday(@FStartTime, nil).
    • Arrêt avec fpgettimeofday(@FStopTime, nil).
    • Conversion en microsecondes : (tv_sec * 1000000) + tv_usec.


    Interface utilisateur :

    • Trois boutons : Démarrer, Arrêter, et Réinitialiser.
    • Une étiquette affiche le temps écoulé en microsecondes.


    Cordialement,

    Chrispi

  6. #6
    Expert confirmé

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 497
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 497
    Points : 4 756
    Points
    4 756
    Par défaut
    Bonjour,

    Les fonctions de temps retournent souvent un temps en us voir ns mais cela ne signifie pas que la précision soit du même ordre. Il y a souvent une fonction complémentaire qui donne la résolution.

    Les fonctions de temps prennent des tops qu'ils multiplient par la résolution temporelle (je n'utilise pas tick alors que ça démange car les fonctions de ce nom font souvent la même opération).

    Il est intéressant de voir que cette résolution évolue car les CPU modernes changent leur vitesse selon la charge et la chaleur. Ainsi, lancer une routine lourde (le ventillo s'affole au bout d'un instant) dans deux versions favorisera la première qui partira avec une fréquence plus élevée. D'où l'intérêt de faire deux ensembles de mesures inversés (fn1 puis fn2 et fn2 puis fn1) surtout si les résultats sont proches.

    Comme déjà évoqué l'exactitude sur une seule mesure est très aléatoire. Il est préférable de faire la mesure sur un grand nombre d'itérations : relative stabilité de la valeur moyenne et gain en précision (1000 mesures en us donnent un temps unitaire en ns).

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

Discussions similaires

  1. Projet compteur entrée/sortie Raspberry
    Par diablack dans le forum Programmation multimédia/Jeux
    Réponses: 1
    Dernier message: 25/04/2021, 17h46
  2. [XSL FO] Compteur a partir de 2
    Par Hugo001 dans le forum XSL/XSLT/XPATH
    Réponses: 7
    Dernier message: 30/06/2004, 12h39
  3. [PB CONCEPTUEL] avec compteur/trigger
    Par kase74 dans le forum SQL
    Réponses: 6
    Dernier message: 25/03/2004, 12h02
  4. Remise à 0 d'un compteur automatique
    Par missllyss dans le forum SQL
    Réponses: 4
    Dernier message: 15/12/2003, 17h46
  5. Migration Access > SQL Server (suite) : Compteur
    Par LadyArwen dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 06/03/2003, 15h08

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