Contenu | Rechercher | Menus

Annonce

DVD, clés USB et t-shirts Ubuntu-fr disponibles sur la boutique En Vente Libre

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 28/03/2020, à 23:22

kamaris

Alerte en cas de RAM disponible insuffisante

Si, comme moi, vous utilisez un petit ordi, avec assez peu de RAM, et que vous souhaitez malgré tout pouvoir faire tourner quelques logiciels assez gourmands (typiquement une machine virtuelle en parallèle de firefox), il est important de garder un œil sur la quantité de RAM disponible, si on ne veut pas se retrouver avec un système gelé.

Comme la méthode manuelle, consistant à garder ouvert un terminal exécutant top, m'a trop de fois conduit à des problèmes (j'oublie d'ouvrir le terminal, ou je finis par le virer, ou je l'oublie en arrière plan, etc.), j'ai fini par me décider à bricoler une petite commande, qui devait :

  • être lancée à l'ouverture de session, pour tourner ensuite en arrière plan ;

  • surveiller la quantité de RAM disponible, et lancer le terminal exécutant top si besoin ;

  • relancer le terminal s'il a été fermé, et qu'on est à nouveau en dépassement de seuil ;

  • consommer aussi peu de ressources que possible.

L'idée est qu'en pratique, lorsqu'il y a dépassement du seuil de RAM, le terminal exécutant top s'affiche au premier plan, jouant à la fois le rôle de pop-up et d'outil de monitoring.
À partir de là, soit on considère que ça va en gardant juste un œil sur le terminal qu'on garde ouvert, soit on intervient pour libérer de la RAM, et on peut fermer le terminal.
Dans tous les cas, la commande continue à tourner en arrière plan et fait ce que doit.

Commande principale

Voici donc cette commande :

free -s1 | awk -v'tpgrep=60' -v'treshold=0.1' -v'cmd=xfce4-terminal --disable-server -T top -x top -oRES' '/^Mem:/{if ($7/$2<treshold){if (! delay++ && system("pgrep -u \"$USER\" -xf \""cmd"\" &>/dev/null")==1) system(cmd" &"); else delay>=tpgrep?delay=0:""}else delay?delay=0:""}'

ou, sous forme développée :

free -s1 | awk -v'tpgrep=60' -v'treshold=0.1' -v'cmd=xfce4-terminal --disable-server -T top -x top -oRES' '
/^Mem:/{
  if ($7/$2<treshold){
    if (! delay++ && system("pgrep -u \"$USER\" -xf \""cmd"\" &>/dev/null")==1) system(cmd" &")
    else delay>=tpgrep?delay=0:""
  }
  else delay?delay=0:""
}'

Les variables passées à awk sont :

  • tpgrep : le nombre de secondes qu'on laisse s'écouler entre chaque pgrep, pour voir si un terminal exécutant top (lancé par la commande) est ouvert, lorsque l'on est en dépassement de seuil (60 secondes me semble raisonnable) ;

  • treshold : la proportion (0 < treshold < 1) de RAM disponible en dessous de laquelle on ouvre le terminal (perso j'ai mis 0.1, soit 10 % de RAM disponible, car je pousse trop souvent ma machine entre 80 % et 90 % de RAM utilisée pour mettre un seuil plus élevé).

  • cmd : la commande à lancer en cas de dépassement de seuil. Comme je suis sous XFCE, j'utilise xfce4-terminal, mais il peut évidemment être remplacé par n'importe quel émulateur, à condition toutefois d'adapter correctement les options utilisées (voir en troisième partie de ce post pour gnome-terminal).

On peut également changer la fréquence à laquelle free envoie les données à awk : une fois par seconde me semble raisonnable (un dépassement de RAM est vite arrivé, et free ne consomme rien).

Je n'ai pas constaté qu'on devait forcer la fenêtre du terminal à s'afficher au premier plan par quelque option : en général, je pense que ça doit le faire par défaut.
Mais si vous utilisez un logiciel qui force les nouvelles fenêtres à s'ouvrir en arrière plan, ou minimisées, alors évidemment, il faudra adapter.

Lancement à l'ouverture de la session graphique

Lorsqu'on lance la commande à l'ouverture de session, il faut la faire précéder d'un test pour savoir si une autre commande du même type ne tournerait pas déjà en arrière plan (lancée lors d'une précédente ouverture de session, sans redémarrage entre deux) : pgrep -u "$USER" -f '^awk -vtpgrep=' >/dev/null || …
Ensuite, soit vous utilisez comme moi un script d'ouverture, auquel cas vous pouvez rajouter cette commande quelque part, suivie de « & », en ayant pris soin d'activer le monitor mode :

set -m
pgrep -u "$USER" -f '^awk -vtpgrep=' >/dev/null || free -s1 | awk -v'tpgrep=60' -v'treshold=0.1' -v'cmd=xfce4-terminal --disable-server -T top -x top -oRES' '/^Mem:/{if ($7/$2<treshold){if (! delay++ && system("pgrep -u \"$USER\" -xf \""cmd"\" &>/dev/null")==1) system(cmd" &"); else delay>=tpgrep?delay=0:""}else delay?delay=0:""}' &

Soit vous la rajoutez dans les commandes à lancer à l'ouverture de session (avec votre outil de config graphique préféré, ou bien je crois que l'emplacement universel pour les lanceurs est ~/.config/autostart), mais il faut alors l'inclure dans un mini-script, en faisant attention aux guillemets :

sh -c 'pgrep -u "$USER" -f "^awk -vtpgrep=" >/dev/null || free -s1 | awk -v"tpgrep=60" -v"treshold=0.1" -v"cmd=xfce4-terminal --disable-server -T top -x top -oRES" '\''/^Mem:/{if ($7/$2<treshold){if (! delay++ && system("pgrep -u \"$USER\" -xf \""cmd"\" &>/dev/null")==1) system(cmd" &"); else delay>=tpgrep?delay=0:""}else delay?delay=0:""}'\'

Voilà, je crois que j'ai tout dit.
Il doit y avoir déjà plein de petites commandes de ce type qui trainent ici ou là sur le net, mais bon…
En espérant que ça serve un jour à quelqu'un smile.

------------------------

Quelques variantes à la commande donnée ci-dessus

Tout d'abord, en restant sur l'idée d'appeler des commandes externes depuis awk, on peut remplacer system("cmd") par "cmd" | getline pour l'appel de pgrep.
C'est peut-être plus robuste, car le code retour de getline risque moins d'être parasité par des évènements inattendus que le code retour de system() (voir https://www.gnu.org/software/gawk/manua … 002dvalues pour plus de détails) :

free -s1 | awk -v'tpgrep=60' -v'treshold=0.1' -v'cmd=xfce4-terminal --disable-server -T top -x top -oRES' '/^Mem:/{if ($7/$2<treshold){if (! delay++){if (! ("pgrep -u \"$USER\" -xf \""cmd"\"" | getline)) system(cmd" &"); close("pgrep -u \"$USER\" -xf \""cmd"\"")}else delay>=tpgrep?delay=0:""}else delay?delay=0:""}'

ou, sous forme développée :

free -s1 | awk -v'tpgrep=60' -v'treshold=0.1' -v'cmd=xfce4-terminal --disable-server -T top -x top -oRES' '
/^Mem:/{
  if ($7/$2<treshold){
    if (! delay++){
      if (! ("pgrep -u \"$USER\" -xf \""cmd"\"" | getline)) system(cmd" &")
      close("pgrep -u \"$USER\" -xf \""cmd"\"")
    }
    else delay>=tpgrep?delay=0:""
  }
  else delay?delay=0:""
}'

Ensuite, on peut changer plus radicalement de méthode, en utilisant plutôt bash que awk, avec une structure du type while read var; do …; done < <(cmd).
Voilà ce que ça peut donner dans ce cas :

tpgrep=60; treshold=0.1; cmd='xfce4-terminal --disable-server -T top -x top -oRES'; while read exceeded; do if ((exceeded)); then if ! ((delay++)) && ! pgrep -u "$USER" -xf "$cmd" >/dev/null; then $cmd & else ((delay>=$tpgrep)) && delay=0; fi else ((delay)) && delay=0; fi done < <(free -s1 | awk -v"treshold=$treshold" '/^Mem:/{print $7/$2<treshold; fflush()}')

ou, sous forme développée :

tpgrep=60; treshold=0.1; cmd='xfce4-terminal --disable-server -T top -x top -oRES'
while read exceeded; do
  if ((exceeded)); then
    if ! ((delay++)) && ! pgrep -u "$USER" -xf "$cmd" >/dev/null; then $cmd &
    else ((delay>=$tpgrep)) && delay=0; fi
  else ((delay)) && delay=0; fi
done < <(free -s1 | awk -v"treshold=$treshold" '/^Mem:/{print $7/$2<treshold; fflush()}')

Attention, c'est du bash, donc pour lancer cette commande au démarrage de la session dans un lanceur, il ne faut pas la mettre dans un sh -c '…' comme plus haut, mais dans un bash -c '…' :

bash -c 'pgrep -u "$USER" -f "^awk -vtpgrep=" >/dev/null || { tpgrep=60; treshold=0.1; cmd="xfce4-terminal --disable-server -T top -x top -oRES"; while read exceeded; do if ((exceeded)); then if ! ((delay++)) && ! pgrep -u "$USER" -xf "$cmd" >/dev/null; then $cmd & else ((delay>=$tpgrep)) && delay=0; fi else ((delay)) && delay=0; fi done < <(free -s1 | awk -v"treshold=$treshold" "/^Mem:/{print \$7/\$2<treshold; fflush()}"); }'

------------------------

Utilisation de gnome-terminal

gnome-terminal ne dispose plus nativement d'une option pour lancer une nouvelle instance, donc il faut ruser un peu, en passant par l'exécutable gnome-terminal-server, dont l'emplacement peut dépendre du système installé.
Par suite, la commande que pgrep doit chercher pour savoir s'il faut ou non relancer un terminal, ne correspond qu'à une partie de la commande effectivement lancée, ce qui implique quelques modifications du programme awk.
Je détaille ci-dessous seulement pour la version awk - getline, mais les version awk - system() et awk - bash (voir seconde partie du post) peuvent être adaptées de la même manière :

free -s1 | awk -v'tpgrep=60' -v'treshold=0.1' -v"cmd=$(whereis -b gnome-terminal-server | cut -d' ' -f2) --app-id top.terminal.instance & sleep 1; gnome-terminal --app-id top.terminal.instance -t top -e 'top -oRES'" '/^Mem:/{if ($7/$2<treshold){if (! delay++){cmd_pattern=cmd; sub(" *&.*","",cmd_pattern); if (! ("pgrep -u \"$USER\" -xf \""cmd_pattern"\"" | getline)) system(cmd); close("pgrep -u \"$USER\" -xf \""cmd_pattern"\"")}else delay>=tpgrep?delay=0:""}else delay?delay=0:""}'

ou, sous forme développée :

free -s1 | awk -v'tpgrep=60' -v'treshold=0.1' -v"cmd=$(whereis -b gnome-terminal-server | cut -d' ' -f2) --app-id top.terminal.instance & sleep 1; gnome-terminal --app-id top.terminal.instance -t top -e 'top -oRES'" '
/^Mem:/{
  if ($7/$2<treshold){
    if (! delay++){
      cmd_pattern=cmd
      sub(" *&.*","",cmd_pattern)
      if (! ("pgrep -u \"$USER\" -xf \""cmd_pattern"\"" | getline)) system(cmd)
      close("pgrep -u \"$USER\" -xf \""cmd_pattern"\"")
    }
    else delay>=tpgrep?delay=0:""
  }
  else delay?delay=0:""
}'

De même que plus haut, si on veut mettre cette commande dans un script de démarrage, il faut la faire précéder d'un test de préexistence, ajouter « & » à la fin pour la faire s'exécuter en arrière plan, et activer le monitor mode :

set -m
pgrep -u "$USER" -f '^awk -vtpgrep=' >/dev/null || free -s1 | awk -v'tpgrep=60' -v'treshold=0.1' -v"cmd=$(whereis -b gnome-terminal-server | cut -d' ' -f2) --app-id top.terminal.instance & sleep 1; gnome-terminal --app-id top.terminal.instance -t top -e 'top -oRES'" '/^Mem:/{if ($7/$2<treshold){if (! delay++){cmd_pattern=cmd; sub(" *&.*","",cmd_pattern); if (! ("pgrep -u \"$USER\" -xf \""cmd_pattern"\"" | getline)) system(cmd); close("pgrep -u \"$USER\" -xf \""cmd_pattern"\"")}else delay>=tpgrep?delay=0:""}else delay?delay=0:""}' &

Et si on veut l'ajouter dans les applications au démarrage, il faut l'inclure dans un mini-script, en adaptant les guillemets :

sh -c 'pgrep -u "$USER" -f "^awk -vtpgrep=" >/dev/null || free -s1 | awk -v"tpgrep=60" -v"treshold=0.1" -v"cmd=$(whereis -b gnome-terminal-server | cut -d" " -f2) --app-id top.terminal.instance & sleep 1; gnome-terminal --app-id top.terminal.instance -t top -e \"top -oRES\"" '\''/^Mem:/{if ($7/$2<treshold){if (! delay++){cmd_pattern=cmd; sub(" *&.*","",cmd_pattern); if (! ("pgrep -u \"$USER\" -xf \""cmd_pattern"\"" | getline)) system(cmd); close("pgrep -u \"$USER\" -xf \""cmd_pattern"\"")}else delay>=tpgrep?delay=0:""}else delay?delay=0:""}'\'

Dernière modification par kamaris (Le 14/04/2020, à 20:10)

Hors ligne

#2 Le 29/03/2020, à 10:51

Compte supprimé

Re : Alerte en cas de RAM disponible insuffisante

Bonjour kamaris.

Je te conseille d'ajouter [Tutoriel] au début de ton titre.

Juste une question, utilise tu la SWAP dans ton système qui n'est pas censé geler s'il est bien installé ?
Cordialement.

#3 Le 29/03/2020, à 15:07

kamaris

Re : Alerte en cas de RAM disponible insuffisante

J'avais d'abord pensé mettre [Tutoriel] dans le titre, effectivement.
Mais en fait, il ne s'agit pas à proprement parler d'un tutoriel, mais plutôt du partage d'une commande.
Par ailleurs, nous sommes dans la section « Trucs, astuces et scripts utiles » du forum, je pense donc que ce titre se suffit à lui-même.

Concernant la swap, il se trouve effectivement que j'ai fait le choix radical de ne pas en utiliser du tout, d'où le fait qu'une surveillance de la RAM est particulièrement cruciale.
Mais même si on utilise une partition ou un fichier de swap (et que le système est « bien installé » et configuré), il n'est pas du tout exclu que le système gèle, ou quasiment, ce qui en pratique revient à peu près au même.
Cela est particulièrement vrai si on a un disque dur mécanique, comme c'est mon cas, et c'est d'ailleurs la raison pour laquelle j'ai choisi d'éliminer complètement la swap : même bien réglée (je connais assez bien les diverses procédures, paramètres, etc.), il est très difficile de contrôler réellement l'utilisation qu'en fait le noyau, et dès qu'il commence à l'utiliser, les ralentissements que cela induit peuvent vite devenir considérables.
Je préfère donc gérer les choses manuellement, pour tirer vraiment le meilleur des faibles ressources dont je dispose.

Dernière modification par kamaris (Le 29/03/2020, à 15:08)

Hors ligne

#4 Le 29/03/2020, à 15:35

Compte supprimé

Re : Alerte en cas de RAM disponible insuffisante

Ok.
Tu t'interdis la mise en veille et l'hibernation du coup sans SWAP.
Et si tu mettais [TRUC] dans ton titre qui deviendrait plus visible ?
Cordialement.

#5 Le 29/03/2020, à 15:53

kamaris

Re : Alerte en cas de RAM disponible insuffisante

L_d_v_c@ a écrit :

Tu t'interdis la mise en veille et l'hibernation du coup sans SWAP.

Oui. Je ne me suis à peu près jamais servi de ces choses-là : mes ordis sont allumés ou éteints.

L_d_v_c@ a écrit :

Et si tu mettais [TRUC] dans ton titre qui deviendrait plus visible ?

Non, je ne vois pas de bonne raison de rajouter un préfixe au titre, qui serait redondant avec le nom de la section « Trucs, astuces et scripts utiles ».

Hors ligne

#6 Le 29/03/2020, à 16:14

Compte supprimé

Re : Alerte en cas de RAM disponible insuffisante

Ok pour le titre. Je ne pensais pas qu'il n'y avait pas de demande d'aide dans la partie « Trucs, astuces et scripts utiles ».
Peut-être que j'aurais dû y poster mes différents tutoriels précédents mais j'ai préféré poster dans « Autres types de matériel » et « Terminal, scripts et ligne de commande ».

Personnellement je n'éteins mon ordinateur qu'avec l'hibernation et rarement la mise en veille puisque l'hibernation ne craint pas les coupures de courant, contrairement à la mise en veille.

À chacun ses habitudes wink

#7 Le 29/03/2020, à 16:26

kamaris

Re : Alerte en cas de RAM disponible insuffisante

L_d_v_c@ a écrit :

Ok pour le titre. Je ne pensais pas qu'il n'y avait pas de demande d'aide dans la partie « Trucs, astuces et scripts utiles ».
Peut-être que j'aurais dû y poster mes différents tutoriels précédents mais j'ai préféré poster dans « Autres types de matériel » et « Terminal, scripts et ligne de commande ».

Eh bien, le titre de la section est assez explicite, et son résumé introductif est :
« Cette section est réservée à la proposition de trucs, astuces et scripts utiles. Pour les demandes d'aide merci d'utiliser les catégories adaptées (notamment terminal, scripts et ligne de commande, ou développement et programmation) »
Mais pour ta défense, tu n'es pas le seul à faire cette erreur…

L_d_v_c@ a écrit :

Personnellement je n'éteins mon ordinateur qu'avec l'hibernation et rarement la mise en veille puisque l'hibernation ne craint pas les coupures de courant, contrairement à la mise en veille.

À chacun ses habitudes wink

Tout à fait, pas de problème là-dessus wink

Hors ligne