Forum Linux.général [résolu] visualiser charge CPU et mémoire | mesurer l'efficience

2
14
fév.
2022

Pour une expérience, il me faut collecter les informations de charge CPU et mémoire d'un ordinateur pendant qu'un·e utilisatrice réalise des tâches dessus. En gros: ressortir les histogrammes des moniteurs systèmes.
C'est le même objectif que dans ce post askubuntu.

Les outils et implémentations disponibles

  1. un script avec top et gnuplot

C'est la solution qui me paraît la meilleure, car la plus simple. Elle vient de là.

#!/bin/sh
# Source: https://dzone.com/articles/monitoring-process-memorycpu-usage-with-top-and-pl
# Date: 2013
# Usage: ./monitor-usage.sh <PID of the process>
# Output: top.dat with lines such as `1539689171 305m 2.0`, i.e. unix time - memory with m/g suffix - CPU load in %
# To plot the output, see https://gist.github.com/jakubholynet/931a3441982c833f5f8fcdcf54d05c91
export PID=$1
rm top.dat
while true
do
 top -bp $PID -bn 1 | egrep '^[0-9]+' | awk -v now=$(date +%s) '{print now,$6,$9}' >> top.dat
done

Je fais pourtant face à deux difficultés:
* Le fichier output.dat reste vide :-/
* Le script permet de suivre un PID précis, mais pas l'ensemble des processus.

  1. atop

Me semble déjà "overkill" avec sa longue page de manuel.
La commande

atop -M 5 15 > atop.mem

me sort un fichier déjà bien conséquent avec beaucoup trop d'informations.

  1. mpstat du paquet sysstat La commande
(mpstat -P ALL; echo; free) > sysinfo.txt

me sort un fichier plus lisible, mais je ne sais pas comment automatiser la commande chaque 5 seconde.

Je suis convaincu qu'un petit script activant les outils basiques de GNU/Linux fera l'affaire, mais possède des connaissances limitées de ces outils et de bash. Les solutions comme Glances, Collectl ou nmon sont trop développées pour mon besoin.

Une bonne âme peut-elle m'orienter?

  • # Toutes les 5 secondes

    Posté par  . Évalué à 6.

    Si tu veux exécuter la commande toutes les cinq secondes, tu peux la lancer dans une boucle et y ajouter un sleep:

    while true;
    do
    (mpstat -P ALL; echo; free) >> sysinfo.txt
    sleep 5
    done
    • [^] # Re: Toutes les 5 secondes

      Posté par  (site web personnel, Mastodon) . Évalué à 1.

      Merci!

      J'ai modifié la commande comme suit:

      #!/bin/sh
      rm sysinfo.txt
      while true;
      do
      (mpstat -u ; echo; free) >> sysinfo.txt
      sleep 3
      done

      et obtiens ce résultat:

      [...]
      18:37:42     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
      18:37:42     all   16.32    0.08    6.65    1.11    0.00    0.17    0.00    0.00    0.00   75.66
      
                     total       utilisé      libre     partagé tamp/cache   disponible
      Mem:         8090588     5361624      131492      445312     2597472     1970556
      Partition d'échange:    9764860      478744     9286116
      

      …qui m'offre les données nécessaires. Pour le CPU je compte prendre le %idle et l'inverser (sur 100) pour déterminer la charge. Pour la mémoire je veux prendre la colonne "utilisé".

      Comment sélectionner ces données choisies pour les visualiser grâce à gnuplot, c'est la prochaine étape.

  • # sar ou atop

    Posté par  . Évalué à 6.

    Les commandes sar (dans sysstat) et atop font la collecte de plein de métriques.

    atop et sar peuvent tourner en démon et permettent de rejouer les fichiers. sadf permet de convertir les données collectées par sar en graphes, entre autres.

    • [^] # Re: sar ou atop

      Posté par  (site web personnel, Mastodon) . Évalué à 1.

      Merci!

      sar et sadf au lieu de top et gnuplot. Ok, je lis la doc.

      • [^] # Re: sar ou atop

        Posté par  (site web personnel) . Évalué à 3. Dernière modification le 15 février 2022 à 19:13.

        sar ou atop

        Voire atopsar :)

        Adhérer à l'April, ça vous tente ?

    • [^] # Re: sar ou atop

      Posté par  (site web personnel, Mastodon) . Évalué à 2.

      Tout à fait ; il m'a fait penser à sar en lisant. Par contre, je ne connaissais pas ce côté de atop (jamais pris le temps de l'utiliser à fond) donc merci pour la découverte.

      “It is seldom that liberty of any kind is lost all at once.” ― David Hume

  • # Perso…

    Posté par  . Évalué à 6. Dernière modification le 14 février 2022 à 18:56.

    … j’utiliserai l’outil standard.

    Un simple ps devrait déjà faire le taf.

    $ ps -p $PID -o %cpu,%mem --no-headers
    $ man ps # pour avoir la liste complète de l’option -o

    Attention le %cpu n’est pas un “instantané” (au besoin il faudra faire un peu d’arithmétique autour).

    PS : tu peux sélectionner tous les process de la machine (-e), les trier, et tout et tout.

    Mort aux cons !

    • [^] # Re: Perso…

      Posté par  (site web personnel, Mastodon) . Évalué à 1.

      Merci!

      Elle va droit au but ta commande ps! :-)
      avec

      #!/bin/sh
      rm sysinfo_ps.txt
      while true;
      do
      (date; ps -e -o %cpu,%mem; echo "*****************") >> sysinfo_ps.txt
      sleep 2
      done

      j'obtiens:

      mar 15 fév 2022 19:17:39 CET
      %CPU  %MEM
       0.3  1.4
       0.8  2.3
       0.0  0.0
       0.0  0.0
       0.3  0.0
       0.0  0.8
       0.1  0.8
       0.1  0.8
      [...]
       0.0  0.0
      *****************
      

      Après lecture du manuel, il n'est pas possible avec ps d'obtenir un résultat global pour l'ensemble des processus. Une piste pour faire un total de chacune des deux colonnes?

      • [^] # Re: Perso…

        Posté par  (site web personnel, Mastodon) . Évalué à 2. Dernière modification le 16 février 2022 à 00:37.

        Je ne sais pas quel sens tu veux donner aux sommes, mais bon

        ps -e -o %cpu= -o %mem= |
        awk '{CPUs+=$1; RAMs+=$2} END {print CPUs,RAMs}'

        Au fait… Pourquoi un sous-processus ? Et pourquoi cet écho ?

        “It is seldom that liberty of any kind is lost all at once.” ― David Hume

        • [^] # Re: Perso…

          Posté par  (site web personnel, Mastodon) . Évalué à 1.

          yes!
          Par somme j'entends la somme des charges de tous les PID. Je comprends pas ta question sur le sous-processus. L'echo me sert à vérifier le résultat. Mon objectif est de collecter des données simples de charge CPU et mémoire pendant l'usage du système par un utilisateur, puis de les visualiser dans un graphique.
          D'ailleurs j'suis pas certain d'obtenir ça avec les keywords %cpu et %mem…

          • [^] # Re: Perso…

            Posté par  (site web personnel, Mastodon) . Évalué à 2. Dernière modification le 11 mars 2022 à 18:13.

            Le/la code/commande que je donne fait les sommes deux colonnes %cpu et %mem ; mais je ne sais si tu comprends bien toutes les implications… (En terme de mémoire, y a pas que la RAM par exemple, y a aussi l'usage de la swap et toutes sortes de mémoires disponibles. De même pour la CPU va prendre en compte le nombre de processeurs de la machine et leur nombre de cœurs, etc.)
            Pour voir la charge, ou load average, tu as trois valeurs qui te sont retournées par la commande uptime et répondent exactement à cela.
            Pour voir la mémoire utilisée et libre, il faut se tourner vers la commande mem qui répond simplement à ce point.

            Tu crées un sous-processus avec la parenthèse : ça veut dire que ton interpréteur (bash par exemple mais ça marche pour les autres shell aussi) va lancer une autre instance de lui-même qui va exécuter la(s) commande(s) de façon séparée. C'est presque comme si tu faisais bash -c "commande" dans le cas présent.
            Pour grouper des commandes (i.e. faire l'équivalent d'un bloc de commandes, afin de rediriger le contenu de toutes dans un fichier dans le cas présent), ce sont les accolades et non les parenthèses. Mais avec une petite subtilité dans son usage…

            “It is seldom that liberty of any kind is lost all at once.” ― David Hume

      • [^] # Re: Perso…

        Posté par  . Évalué à 2.

        Pour des agrégats, si tu tiens à scripter toi-même et, mettre les mains dans le cambouis, tu peux directement taper dans les stat. exposées par le noyau : /proc/meminfo, /proc/loadavg, /proc/stat, classiquement données fournies via les outils plus user-friendly et plus portables free, uptime, top, ps, etc.

        https://www.kernel.org/doc/html/latest/filesystems/proc.html

        Mort aux cons !

  • # reinventer la roue ?

    Posté par  . Évalué à 8.

    ton output.dat reste vide car tu remplis top.dat ;)

    sinon plutot que de reinventer la roue (mais c'est peut-etre pour un exercice)
    tu as SNMP :

    • un daemon snmpd qui tourne sur la machine
    • un client snmpget/snmpwalk qui va lire (depuis la machine, voire depuis le reseau) un OID spécifique pour connaitre l'usage CPU, ou la RAM

    c'est d'ailleurs comme cela qu'on collecte les métriques dans beaucoup de solution de monitoring

    • [^] # Re: reinventer la roue ?

      Posté par  (site web personnel, Mastodon) . Évalué à 1.

      Merci!

      Tu m'orientes vers les bonnes pratiques de monitoring. Pour moi (mon objectif et mes connaissances) c'est cependant trop complexe: un protocole nouveau, un démon à mettre en place, un client, …

      Bien vu entre output.dat et top.dat! J'ai corrigé et le fichier .dat reste cependant vide.

      • [^] # Re: reinventer la roue ?

        Posté par  . Évalué à 4.

        parce que top est un programme interactif, il ne rendra la main que quand tu le quitte
        donc ton '|' (pipe) ne fonctionnera qu'a la fin de ce dernier.

        il faut donc utiliser des programmes non interactifs ou des options à top pour qu'il ne tourne qu'une seule fois

        • [^] # Re: reinventer la roue ?

          Posté par  (site web personnel, Mastodon) . Évalué à 2.

          u des options à top pour qu'il ne tourne qu'une seule fois

          top -stats cpu,mem -l 4

          par exemple

          “It is seldom that liberty of any kind is lost all at once.” ― David Hume

        • [^] # Re: reinventer la roue ?

          Posté par  (Mastodon) . Évalué à 3.

          parce que top est un programme interactif

          sauf si tu lui demandes poliment : top -b | head

          -b c'est le batch mode, mais il n'a l'air de marcher que si tu | derrière.

          Quelques exemples ici

          En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

      • [^] # Re: reinventer la roue ?

        Posté par  . Évalué à 3.

        c'est cependant trop complexe: un protocole nouveau, un démon à mettre en place, un client, …

        mais plus haut, tu n'es pas contre installé/utilisé SAR (qui contient un daemon, un client…) ???

        note que SNMP est certes un protocole, mais tu n'as besoin que de connaitre les OIDs de ce que tu recherches, et pour apprendre tu affiches l'arbre complet, et tu regardes les OIDs.

        en plus, contrairement à SAR qui ne sera surement dispo que sous linux et bsd, SNMP est utilisé par plein d'appareil (windows, linux, BSD, routeur, imprimante, switch, AP wifi, box opérateur, parefeu, NAS)

        donc ce que tu veux faire en TOP/SAR sur ton linux, tu pourrais faire la meme chose en SNMP sur tous les appareils de ton reseau par exemple

    • [^] # Re: reinventer la roue ?

      Posté par  (site web personnel, Mastodon) . Évalué à 4.

      Tu seras surpris par le nombre de projets qui réinventent la roue… collectd a le vent en poupe pour faire sa métrologie avec influxdb et graphana

      “It is seldom that liberty of any kind is lost all at once.” ― David Hume

  • # Netdata

    Posté par  . Évalué à 4.

    Hello,
    C'est peut être une solution surdimensionnée par rapport à ton besoin, mais elle peut y répondre. Netdata est un logiciel open source qui permet de collecter et visualiser de très nombreux indicateurs système. C'est une solution simple à installer en particulier si on se contente des paramétrages par défaut.

    C'est par ici: https://github.com/netdata/netdata

  • # ça avance :-)

    Posté par  (site web personnel, Mastodon) . Évalué à 1.

    Voici où j'en suis, grâce à vos contributions :

    #!/bin/sh
    rm systemusage.csv
    while true;
    do
        (date; 
        echo -e $'\t' ;
        free -t | grep Mem | awk '{print $7}' ;
        echo -e $'\t' ;
        uptime | awk '{print $10}';
        echo -e $'\t' ;) >> systemusage.csv
    sleep 1
    done

    Mémoire

    J'ai suivi le conseil de Gil Cot d'utiliser mem, mais c'est pas vraiment une commande alors free fait l'affaire.
    Je prends la variable Disponible/Available. Selon le manuel, elle correspond à mon besoin d'information. Cependant le swap est laissé de côté.

    Estimation of how much memory is available for starting
    new applications, without swapping. Unlike the data
    provided by the cache or free fields, this field takes
    into account page cache and also that not all reclaimable
    memory slabs will be reclaimed due to items being in use
    (MemAvailable in /proc/meminfo, available on kernels 3.14,
    emulated on kernels 2.6.27+, otherwise the same as free)

    CPU

    Ici uptime donne une valeur utilisable de la charge CPU. Comme elle n'est pas générique à tous les systèmes, je dois faire attention au multi-coeur et multi-thread: une valeur de 1.00 sur un quadcore équivaut à une valeur de 0.25 sur singlecore.

    Visualisation

    Avec ces données je vais pouvoir faire un bel histogramme avec la mem et le cpu en y, et le temps en x.
    Par contre j'ai des difficultés à importer cela dans LibreOffice Calc. Il semble reconnaître le caractère de tabulation (/t), mais ne le prend pas en compte pour place les données dans de nouvelles colonnes.
    import-calc
    Alors que je veux une structure de csv comme ça:
    date | mem | cpu
    date2 | mem | cpu

    daten | mem | cpu

    Comment créer un fichier csv qui ordonne les données par ligne?

    • [^] # Re: ça avance :-)

      Posté par  (site web personnel, Mastodon) . Évalué à 2.

      Oui, pardon, me suis un peu mélange avec la fatigue puis ne suis pas revenu quand je me suis rendu compte une bonne heure après que j'avais écrit mem au lieu de free ! Comme tu cherches la quantité libre, prendre en compte la swap n'a pas de sens …parce-que idéalement il ne faut pas en avoir besoin et ne pas se dire que c'est de la mémoire qui est disponible normalement pour les programmes : quand ça swape c'est pas bon. Par ailleurs, tu peux régler le système pour ne pas utiliser la mémoire swap ou contrôler à quel seuil de saturation de la RAM il faut commencer à basculer. Mais en mode rapport, tu ne comptes pas sa présence sinon tu risques de croire que t'as assez de mémoire vive dispo au lieu de voir que ça sature, et sinon tu auras aussi du mal à expliquer aux hiérarchies qui sont de moins en moins technique quand on monte.

      Oui, pour le processeur il faut tenir compte du nombre de cœur, et même parfois si tu fais de l'hyperthreading ! Lire par exemple les échanges sur https://unix.stackexchange.com/questions/218074/how-to-know-number-of-cores-of-a-system-in-linux
      Je te propose ceci, à faire avant d'entrer dans la boucle :

      outputfile="systemusage.csv"
      # le jour où tu modifies, tu le fais en un seul endroit.
      rm -vf "$outputfile"
      # -v pour afficher ce qui se passe (à utiliser si tu es en mode interactif)
      # -f au cas où tu aurais un alias avec -i
      # ou si tu lances en tant qu'un autre compte (mais ne marchera que pour root)
      command -v nproc && NbrCrs=$(nproc --all) || NbrCrs=1
      # si la commande existe on l'utilise sinon on ne tient pas compte du nbr de çœurs

      Si tu regardes ton fichier dans un éditeur de texte, tu verras que la faute n'est pas du côté de LibreOffice (ou n'importe quel autre tableur.) En effet, chaque commande se termine par un saut de ligne…
      Dans la boucle, j'utiliserai plutôt quelque chose comme :

      echo -e "$(date)\t$(free -t | awk '/Mem:/{print $7}')\t$(uptime | awk -v N=$NbrCrs '{print $10/N}')\t" >>"$outputfile"

      J'ai un petit doute sur la 7ème colonne (compressed) : tu devrais utiliser la 3ème (used) ou la 4ème (free) non ?
      Sinon, j'ai supprimé le grep pour l'intégrer directement dans le awk
      De l'autre côté, j'ai passé la valeur du nombre total de cœurs pour adapter le résultat comme tu le souhaitais. Mais j'ai un petit doute sur le dixième champ :

      $ uptime
      23:37  up 10 days, 39 mins, 12 users, load averages: 1.70 1.59 1.57

      J'en profite pour reparler de top ; faut que t'essaye, juste pour la/le curiosité/fun…

      top -l 1 -s 0 | awk '/PhysMem:/ {print}'

      Maintenant, il parait que je n'est pas la manière propre/canonique d'écrire les scripts : j'ai trop de vieux réflexes. Voici la correction pour que ce soit plus lisible et facile à maintenir :

      TheMem=$(awk -v N=$brCrs '/Mem:/ {print $7/N}')
      TheLoad=$(uptime | awk '{print $10}')
      TheTime=$(date +"%Y-%M-%dT%H%M%S")
      echo -e "$TheTime\t$TheMem\t$TheLoad\t" >>"$outputfile"

      Maintenant, j'ai une réserve sur echo -e : ce n'est pas portable (ton programme ne marchera pas comme espéré si tu utilises un autre interpréteur que bash ou peut-être sur une autre distribution dont l'implémentation de la commande ne supporte pas cette option…) Voici la bonne façon de faire :

      # en reprenant les variables de la forme précédente…
      printf '%s\t%s\t%s\t\n' "$TheTime" "$TheMem" "$TheLoad"

      J'espère n'avoir rien oublié et te laisse recoller les morceaux. :-)

      “It is seldom that liberty of any kind is lost all at once.” ― David Hume

      • [^] # Re: ça avance :-)

        Posté par  (site web personnel, Mastodon) . Évalué à 1.

        trop beau! Merci! Et ne t'excuse pas: j'ai appris plein de choses en lisant et relisant tes commentaires et bouts de code!

        Dans mon système la 7ème colonne de la ligne Mem: résultant de la commande free correspond à la mémoire disponible, pas à la la mémoire compressed.

        Tout me semble bien, si ce n'est que les données ne sont pas enregistrées 🥲 J'ai essayé plein de bidouilles mais n'y parvient pas:

        #!/bin/sh
        # avec l'aide de la communauté linuxfr
        # https://linuxfr.org/forums/linux-general/posts/visualiser-charge-cpu-et-memoire-mesurer-l-efficience
        
        # Création du fichier de sortie
        outputfile="0000.csv"
        rm -vf "$outputfile"
        # -v    pour afficher ce qui se passe (à utiliser si tu es en mode interactif)
        # -f    au cas où tu aurais un alias avec -i
        #       ou si tu lances en tant qu'un autre compte (mais ne marchera que pour root)
        
        # Définition du nombre de thread et/ou processeurs pour normaliser le load average
        command -v nproc && NbrCrs=$(nproc --all) || NbrCrs=1
        
        # double pipe "||": si la commande existe on l'utilise sinon on ne tient pas compte du nbr de cœurs
        
        printf 'test hors bouuuucle\t'>> $outputfile # ✅
        
        # Définition des variables
        TheMem=$(awk -v N=$NbrCrs '/Mem:/ {print $7/N}') # mémoire disponible
        TheLoad=$(uptime | awk '{print $10}') # load average de la dernière minute
        TheTime=$(date +"%Y-%M-%dT%H%M%S")
        printf '%s\t' "$TheMem" >> $outputfile # 🚫
        
        # Enregistrement des données dans le fichier de sortie
        while true;
        do
        printf '%s\t%s\t%s\t\n' "$TheTime" "$TheMem" "$TheLoad" >> $outputfile #🚫
        printf 'test dans boucle\t' >> $outputfile #🚫
        sleep 2
        done
        • [^] # Re: ça avance :-)

          Posté par  (site web personnel, Mastodon) . Évalué à 2. Dernière modification le 17 mars 2022 à 15:01.

          Essaye en ligne de commande directement pour voir si ça affiche quelque chose ; peut-être qu'une erreur de syntaxe fait que la commande ne va pas au bout ?

          # avec ton shell
          $ printf '%s\t.\n' "foo"
          foo .
          # avec /bin/sh
          $ /bin/sh -c "printf '%s\t.\n' 'foo'"
          foo .

          Comme ça semble se gâter au second, peut-être qu'il y a un truc juste avant qu'il n'aime pas ; essaye ceci :

          set -x
          TheMem=$(awk -v N=$NbrCrs '/Mem:/ {print $7/N}') # mémoire disponible
          TheLoad=$(uptime | awk '{print $10}') # load average de la dernière minute
          TheTime=$(date +"%Y-%M-%dT%H%M%S")
          printf '%s\t' "$TheMem" >> $outputfile #
          set +x
          echo "1. $TheMem"
          echo "2. $TheLoad"
          echo "3. $TheTime"
          cat "$outputfile"
          exit

          Pendant que j'écris cette réponse je me rend compte qu'il y a une petite erreur que j'avais pas vu en lisant : ton premier appel à AWK n'a pas de fichier sur lequel travailler …et n'est pas branché sur l'entrée standard par le pipe sur une autre commande. (c'est probablement à partir de là que ça part en vrille…)

          edit : je viens de relire, et j'avais laissé une erreur dans ma réponse. la comparaison avec la version echo donne la réponse :

          echo -e "$(date)\t$(free -t | awk '/Mem:/{print $7}')\t$(uptime | awk -v N=$NbrCrs '{print $10/N}')\t" >>"$outputfile"

          “It is seldom that liberty of any kind is lost all at once.” ― David Hume

        • [^] # Re: ça avance :-)

          Posté par  (site web personnel, Mastodon) . Évalué à 2.

          Arf, quand je disais que j'ai une écriture cryptique de dinosaure du shell

          Maintenant, il parait que je n'est pas la manière propre/canonique d'écrire les scripts : j'ai trop de vieux réflexes.

          Faut vraiment que je fasse gaffe quand je réponds sur les fora, pour ne pas embrouiller inutilement comme ici.

          # double pipe "||": si la commande existe on l'utilise sinon on ne tient pas compte du nbr de cœurs

          Ce n'est pas exactement ça, enfin ce n'est pas le sens du double pipe… Je m'explique par des exemple

          # enchainer sans condition
          ls -d ~/                   ;  echo "$? on y est"
          ls ~/notfound              ;  echo "$? suite"
          # echainer en cas de succès
          cd "$HOME"     2>/dev/null && echo "$? = maison"
          # echainer en cas d'échec
          cd /inexistant 2>/dev/null || echo "$? = perdu"
          # pseudo alternative
          cd ~/ && echo "ok" || echo "ko"
          cd /404 && echo "ok" || echo "ko"
          

          Ma syntaxe n'est pas conseillée en général parce-que si on ne la comprend pas on aura des effets de bord… Pour la partie en question, la syntaxe claire (pas besoin d'être gourou du shell pour comprendre) et sans effet de bord est

          if command -v nproc >/dev/null
          then
            NbrCrs=$(nproc --all)
          else
            NbrCrs=1
          fi

          Quand la commande existe, son chemin dans le PATH est renvoyé sur la sortie standard, raison pour laquelle je rajoute la redirection vers /dev/null pour ne pas polluer la version finale. En phase d'élaboration c'est utile pour s'assurer qu'on passe bien par là.


          Pendant que j'écris cette réponse je me rend compte qu'il y a une petite erreur que j'avais pas vu en lisant : ton premier appel à AWK n'a pas de fichier sur lequel travailler …et n'est pas branché sur l'entrée standard par le pipe sur une autre commande. (c'est probablement à partir de là que ça part en vrille…)

          edit : je viens de relire, et j'avais laissé une erreur dans ma réponse.

          En relisant, je vois que j'avais pris soin de faire la transition

          echo -e "$TheTime\t$TheMem\t$TheLoad\t" >>"$outputfile"

          C'est juste les définition de variables juste avant qui ne collaient plus. Voici la correction que tu aurais du faire :

          TheMem=$(free -t | awk '/Mem:/{print $7}')
          TheLoad=$(uptime | awk -v N=$NbrCrs '{print $10/N}')
          TheTime=$(date +"%Y-%M-%dT%H%M%S")

          Mais bon, ça t'aurais permis de voir une des façon de déboguer du script shell : set -x va afficher tout ce qu'il fait avant de le faire, sorte de mode trace… Et aussi, souvent, pendant la phase de conception, on met des echo de vérification. Pour la version finale, quand c'est critique, on peut utiliser set -e qui fait planter (arrêter le script) quand une ligne est en erreur, au lieu de poursuivre en propageant des trucs incorrects. Tu peux aussi l'utiliser pour déboguer, par exemple dans le cas ci :

          set -e
          TheLoad=$(uptime | awk '{print $10}') # load average de la dernière minute
          echo "2. $TheLoad"
          TheMem=$(awk -v N=$NbrCrs '/Mem:/ {print $7/N}') # mémoire disponible
          echo "1. $TheMem"
          TheTime=$(date +"%Y-%M-%dT%H%M%S")
          echo "3. $TheTime"
          printf '%s\t' "$TheMem" >> $outputfile #
          cat "$outputfile"
          set +e
          exit

          (me semble que les affectations ne sont malheureusement pas en erreur, et puis les échos permettent aussi de savoir où on plante …sauf si on a cumulé avec set -xe par exemple. c'est à toi de voir et d'adapter au cas par cas.)


          printf 'test hors bouuuucle\t'>> $outputfile # ✅

          Attention que echo termine par un retour à la ligne, et qu'il faut explicitement rajouter celui-ci pour printf qui te laisse gérer ton affichage.
          Mais c'est une bonne idée d'avoir les (noms des) champs sur la première ligne, histoire de savoir rapidement quoi est où sans devoir aller voir dans le code. Accessoirement, on note cette ligne comme un commentaire shell car beaucoup d'outils reconnaissent cela et sauteront la ligne (c'est le cas avec gnuplot) sinon on peut utiliser aussi des chaînes entrecôte (si le fichier est destiné uniquement aux tableurs)

          printf '#Timestamp\tFreeMemory\tAverageLoad' >> "$outputfile"

          Comme c'est la première action sur le fichier, tu peux utiliser > au lieu de >> et te passer du rm avant. (ou le remplacer par touch si tu tiens à changer la date de création.) :-)

          “It is seldom that liberty of any kind is lost all at once.” ― David Hume

          • [^] # Re: ça avance :-)

            Posté par  (site web personnel, Mastodon) . Évalué à 1.

            Merci merci pour le temps, les conseils et snippets. J'ai la joie: grâce à tes conseils (et les autres aussi!) je suis parvenu à une version de script bash satisfaisante. Il y aurait plein de trucs à ajouter et optimiser, comme l'ajout du nom de la personne testeuse, le formatage du fichier de sortie selon la date et ce nom et même la création d'un histogramme directement avec gnuplot. Mais bon j'ai d'autres choses à préparer pour cette expérience; il faut savoir s'arrêter, même si je commence à ressentir pas mal de plaisir à bidouiller ce script.
            Parce que j'ai appris plein de choses, des commandes de base de linux certes, mais ausi des méthodes et une certaine logique. Le set -x est magique pour comprendre la logique du programme notamment!

            #!/bin/sh
            # avec l'aide de la communauté linuxfr
            # https://linuxfr.org/forums/linux-general/posts/visualiser-charge-cpu-et-memoire-mesurer-l-efficience
            
            #set -x
            # Création du fichier de sortie
            outputfile="0000.csv"
            rm -vf "$outputfile"
            # -v    pour afficher ce qui se passe (à utiliser si tu es en mode interactif)
            # -f    au cas où tu aurais un alias avec -i
            #       ou si tu lances en tant qu'un autre compte (mais ne marchera que pour root)
            
            # Définition du nombre de thread et/ou processeurs pour normaliser le load average
            command -v nproc && NbrCrs=$(nproc --all) || NbrCrs=1 # double pipe "||": si la commande existe on l'utilise sinon on ne tient pas compte du nbr de cœurs
            
            TheTime=$(date +"%T")
            Time=$(date)
            Sysinfo=$(lsb_release -a)
            
            #Informations système
            printf '%s\t%s\t\n%s\t%s\t\n%s\t\n' "Date:" "$Time" "Mémoire totale:" "$TotMem" "$Sysinfo" >> $outputfile
            # Inscription des entêtes du fichier de sortie
            printf '%s\t%s\t%s\t%s\t%s\t\n' "Timestamp" "Mémoire disponible" "Charge CPU" >> $outputfile
            
            # Enregistrement des données dans le fichier de sortie
            while true;
            do
            # Définition des variables
            AvMem=$(free -t | awk '/Mem:/ {print $7}') # mémoire disponible
            TotMem=$(free -t | awk '/Mem:/ {print $2}') # mémoire totale
            TheLoad=$(uptime | awk -v N=$NbrCrs '{print $10/N}') # load average de la dernière
            printf '%s\t%s\t%s\t%s\t\n' "$TheTime" "$AvMem"  "$TheLoad" >> $outputfile
            sleep 2
            done
            • [^] # Re: ça avance :-)

              Posté par  (site web personnel, Mastodon) . Évalué à 2.

              Attention aux lignes mal placées :-)

              • dans ta boucle tu définis TotMem qui n'est pas utilisé…
              • il est par contre utilisé plus tôt (Informations système) sans être défini…
              • dans ta boucle, TheTime qui est défini en dehors ne changera pas…

              Il est bien de précéder les lignes de début (Informations système & Inscription des entêtes du fichier de sortie) par dièse : gnuplot les reconnaîtra, par défaut comme des commentaires et tu n'auras pas à te prendre la tête quand tu lui donneras le fichier directement.

              gnuplot> set xlabel 'Memory'
              gnuplot> set ylabel 'Load'
              gnuplot> set title "My First Plot"
              gnuplot> plot '0000.csv' u 2:3 w linespoints

              À noter que le set -x tu le retrouveras sous cette forme vu que tu l'appelles d'entrée de jeu :

              #!/bin/sh -x

              En effet, le set active (-) ou désactive (+) des options du shell, comme on peut le faire aussi directement au moment de lancer l'interpréteur de commande.

              “It is seldom that liberty of any kind is lost all at once.” ― David Hume

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.