[LINUX] [Version améliorée] Script pour surveiller le CPU avec Python

Quand j'exécute temp.py dans Mesurer la température du CPU de Raspeye avec Python j'ai écrit plus tôt, le nombre de CPU est compté à chaque fois qu'il se déclenche dans une boucle while. J'utilisais un pourcentage. Puisqu'il s'agit d'un script de monitoring, je voudrais l'améliorer car il doit être le plus léger possible.

À propos, après l'amélioration, la sortie ressemble à ceci. À partir de la gauche, température du processeur, fréquence, taux d'utilisation global et taux d'utilisation pour chaque cœur. 110255.png

Cause

Ce qui était lourd, c'était le module appelé subprocess utilisé pour exécuter les commandes du système d'exploitation Linux. À ce propos, Il est faux de chatter avec le sous-processus de python. , alors jetez un œil. En termes simples, il est lent car il lance un processus enfant juste pour obtenir le texte. Si vous utilisez la fonction intégrée pour l'opération de fichier appelée ʻopen () `, elle ne sera complétée qu'en Python, donc ce sera environ 50 fois plus rapide.

Points d'amélioration

Il y a quatre améliorations principales.

  1. Remplacez subprocess par ʻopen ()`
  2. La boucle de «while» est lente, alors remplacez-la par «for»
  3. Réécrivez l'opération de chaîne de caractères dans print avec format
  4. Suppression de l'affichage de la tension de fonctionnement et affichage du taux d'utilisation

Le premier est le point culminant de cette période. Auparavant, j'utilisais subprocess pour exécuter une commande créée par le système d'exploitation Raspberry Pi appelée vcgencmd. Cela ne peut être exécuté que sur le système d'exploitation Raspberry Pi, et vcgencmd est conçu pour fonctionner dans le shell, il ne convient donc pas à la saisie à partir de Python. La surveillance en Python est une bombe de sous-processus qui n'est qu'un nom, donc c'est une sous-fonctionnalité de cette fois pour obtenir des informations sur le processeur sans utiliser vcgencmd.

Le second est insignifiant, mais je l'ai réécrit dans une ambiance. Le troisième est principalement pour améliorer la lisibilité. Quatrièmement, je n'ai pas trouvé grand intérêt à vérifier la tension de fonctionnement et je n'ai pas pu trouver le fichier qui enregistrait la tension de fonctionnement. Modifié pour afficher l'utilisation du processeur à la place.

code

Voici le code amélioré.

temp.py


#!/usr/bin/python3.7

import time
import sys

#Fonction d'acquisition du temps d'utilisation du processeur
def get_data():
    with open('/proc/stat') as r: #Lire le fichier de statistiques du processeur
        stats = r.readlines() #Liste par ligne
        stat = [line.strip().split() for line in stats if 'cpu' in line] #Prenez la ligne contenant le processeur et supprimez le caractère de saut de ligne, double liste séparée par des blancs
    rs = [] #Déclarer une liste qui contient le temps d'utilisation
    for data in stat: #Extraire les données de l'ensemble du processeur et de chaque cœur logique à partir des statistiques
        busy = int(data[1]) + int(data[2]) + int(data[3]) #Trouver l'heure de l'état occupé
        all = busy + int(data[4]) #Demandez tout le temps
        rs.append([all, busy]) #Ajouter à la liste
    return rs #Renvoie une valeur

pre_data = get_data() #Obtenez le premier temps d'utilisation du processeur
ave = 0 #Déclaration de variable pour le calcul de la moyenne

time.sleep(1) #Attendez une seconde

try: #Ctrl avec ce qui suit sauf l'interruption du clavier+Pièce de fonctionnement normal pour attraper C
    for i in range(60): #Répéter 60 fois
        with open('/sys/class/thermal/thermal_zone0/temp') as t: #Lecture de la température du processeur
            temp = int(t.read()) / 1000 #Conversion de type et unités de correspondance
        with open('/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq') as f: #Lecture de la fréquence du processeur
            freq = int(f.read()) #Conversion de type

        now_data = get_data() #Obtenir le temps d'utilisation actuel du processeur
        rates = [] #Déclarer une liste contenant l'utilisation du processeur

        for j in range(5): #Processeur entier+Nombre de cœurs logiques(4)Répéter fois
            now = now_data[j] #Extraire les données CPU souhaitées de la durée d'utilisation actuelle
            pre = pre_data[j] #Extraire les données CPU souhaitées à partir de la durée d'utilisation d'il y a 1 seconde
            rate = (now[1] - pre[1]) / (now[0] - pre[0]) * 100 #(État occupé/L'ensemble) *Trouvez l'utilisation du processeur à 100
            rates.append(rate) #Ajouter l'utilisation du processeur à la liste

        #Formater et exporter à l'aide de la méthode de format
        print("Temp:{0:>6.2f}'C, Freq: {1:.2f}GHz, CPU:{2:>5.1f}% [{3:>3.0f},{4:>3.0f},{5:>3.0f},{6:>3.0f}]({7:>2})".format(temp, freq / 1000000, rates[0], rates[1], rates[2], rates[3], rates[4], i + 1))

        ave += temp #Ajouter la température actuelle pour la température moyenne
        pre_data = now_data #Enregistrer les données actuelles pour les données des secondes suivantes
        time.sleep(1) #Attendez une seconde
    print("Average: {:.2f}'C (60s)".format(ave / 60)) #Écrivez la moyenne après la fin de la boucle
except KeyboardInterrupt: #Ctrl+Catch C
    sec = i + 1 #Obtenez le temps écoulé à la fin
    print(" Aborted.\nAverage: {0:.2f}'C ({1}s)".format(ave / sec, sec)) #Écrivez la température moyenne
    sys.exit() #Réussite

l'utilisation du processeur

Avant l'explication, je voudrais décrire comment calculer séparément le taux d'utilisation du processeur. J'ai fait référence à ici.

Le taux d'utilisation du processeur est essentiellement le rapport entre le temps pendant lequel le processeur était occupé et le temps total, donc si vous obtenez le temps d'utilisation du processeur à partir des statistiques du processeur fournies par Ubuntu, vous pouvez l'obtenir par le principe suivant.

Temps de fonctionnement cumulé du processeur(s) ... 904 905 906 907 908 ...
Temps d'occupation cumulé(s) ... 302 302.5 302.6 303 303 ...
Temps de fonctionnement différentiel du processeur(s) ... 1 1 1 1 1 ...
Différence Heure de l'état occupé(s) ... - 0.5 0.1 0.4 0 ...
l'utilisation du processeur(%) ... - 50% 10% 40% 0% ...

Le flux général du code est "Acquisition de données (pré)" -> "Attendre 1 seconde" -> "Acquisition de données (maintenant et avant suivant)" -> "Calcul" -> "Acquisition de données (suivant maintenant)" -> (Répéter) ..

Les statistiques du processeur Ubuntu sont répertoriées dans / proc / stat, et ce qui suit est un extrait des informations nécessaires du manuel.

man


/proc/stat
    kernel/system statistics.  Varies with architecture.  Common entries include:
        cpu 10132153 290696 3084719 46828483 16683 0 25195 0 175628 0
        cpu0 1393280 32966 572056 13343292 6130 0 17875 0 23933 0
        #Formatez la chaîne ci-dessus pour qu'elle ressemble à celle de droite[[cpu, 10132153, 290696, 3084719, 46828483, 16683, 0, 25195, 0, 175628, 0], [cpu0, 1393280, 32966, 572056, 13343292, 6130, 0, 17875, 0, 23933, 0]]
            The amount of time, measured in units of USER_HZ (1/100ths of a second on most architectures, use sysconf(_SC_CLK_TCK) to obtain the right value), that the system ("cpu" line) or the specific CPU ("cpuN" line) spent in various states:
                user   (1) Time spent in user mode. #Occupé par l'utilisateur
                nice   (2) Time spent in user mode with low priority (nice). #Occupé en raison de processus de faible priorité par les utilisateurs
                system (3) Time spent in system mode. #Occupé par le système
                idle   (4) Time spent in the idle task.  This value should be USER_HZ times the second entry in the /proc/uptime pseudo-file. #Idole

Nous le formaterons afin que vous puissiez récupérer les données nécessaires en vous référant à cela. Si vous l'obtenez avec subprocess, il y en a un pratique appelé grep, mais vous ne pouvez pas l'utiliser cette fois. Utilisez donc le readlines () inclus dans ʻopen () . Reportez-vous à l'article [ici](https://note.nkmk.me/python-grep-like/), reproduisez le même comportement que grep, et traitez-le pour doublerCPU> item`. Fais une liste. (Voir les commentaires dans le manuel ci-dessus)

À partir de cette double liste, for prend les données pour l'ensemble du processeur et chaque cœur logique, calcule l'état d'occupation et le temps total écoulé, et les renvoie sous la forme d'une double liste deCPU et cœur logique> temps écoulé '. Ici, la somme des 2e, 3e et 4e éléments de la liste est la somme de l'état Occupé, et la somme de l'état Occupé et de l'état Inactif (le 5e élément) est le temps total écoulé. Ce qui précède est le traitement de la fonction d'acquisition du temps d'utilisationget_data ()`. Après cela, je voudrais en parler dans l'explication.

Commentaire

Je l'ai écrit dans les commentaires, mais je voudrais le traiter dans l'ordre du haut. Je suis moi-même un débutant, je vais donc l'expliquer en excès.

import Tout d'abord, «importez» les modules requis. Cette fois, j'ai chargé le module «time» pour la veille et le module «sys» pour la terminaison. En plus de cela, le code pré-amélioré contenait un "sous-processus", mais je l'ai supprimé.

def get_data() Nous avons déjà traité de l'utilisation du processeur dans une autre section, mais nous avons déclaré une fonction pour obtenir le temps d'utilisation cumulé avec def.

pre_data et ʻave, time.sleep (1) `

Avant d'entrer dans la boucle, récupérez les données pour le calcul initial et déclarez une variable pour calculer la température moyenne du processeur. Puis attendez une seconde. Si vous continuez sans attendre, now_data sera acquis plus tôt que l'intervalle de mise à jour de / proc / stat, donc la différence sera de zéro et vous serez en colère si vous ne divisez pas par 0.

try et ʻexcept`

En englobant la boucle entière dans try, l'entrée de Ctrl + C peut être interceptée comme une exception au lieu d'une erreur. Quand Ctrl + C est entré, il saute à ʻexcepté interruption de clavier`, calcule la température moyenne, puis se termine normalement.

for i in range(60) Il répète le processus en substituant des nombres de 0 à 59 pour i. Il semble que répéter 10000000 fois soit plus rapide que répéter avec «while» pendant environ 0,04 seconde. Cette fois, ce n'est pas dans la plage d'erreur, mais j'aime le fait que je n'ai pas à préparer de compteur car c'est intelligent.

with open() Une fonction intégrée qui ouvre le fichier introduit au nom de subprocess. Comme mentionné ci-dessus, veuillez consulter ici pour plus de détails. Le traitement étant terminé dans Python, cela contribue à la réduction de poids.

now_data et taux

Vous obtenez le temps d'utilisation cumulé actuel du processeur. Déclare une liste vide pour remplacer l'utilisation du processeur.

for j in range(5) Les données sont extraites et traitées pour l'ensemble du processeur et chaque cœur. Calcule l'utilisation du processeur en calculant la différence entre le temps d'utilisation cumulé actuel «now_data» et le temps d'utilisation cumulé «pre_data» il y a une seconde, et renvoie le résultat sous forme de liste. (Que dois-je nommer un index qui n'est pas ʻi`?)

print Il est écrit de manière à être facilement visible en utilisant la méthode format. C'est très pratique car vous pouvez effectuer des calculs simples tels que diviser la valeur moyenne à l'intérieur du format.

ʻAve et pre_data, time.sleep (1)`

La température actuelle est ajoutée à «sauver» pour obtenir la température moyenne. Remplacez les données actuelles obtenues précédemment par pre_data pour le prochain calcul d'utilisation du processeur. Après avoir attendu une seconde, le processus boucle.

Obtenez des informations sur le processeur sans utiliser vcgencmd

Comme je l'ai mentionné précédemment, obtenir des informations de Python avec vcgencmd est très inefficace. Puisque les données sont transformées en fichier par Ubuntu comme / proc / stat, j'ai essayé de les récupérer à partir de là.

Température du CPU

Je pense que c'est un endroit assez célèbre.

cat /sys/class/thermal/thermal_zone0/temp
#1000 fois la température est sortie

Avec vcgencmd, les unités et ainsi de suite sont attachées, mais comme il ne s'agit que d'un nombre, il semble préférable de l'obtenir d'ici pour l'intégrer dans le script. La division n'est pas une douleur si elle est dans le programme, et pour une raison quelconque, il est bon que les nombres valides soient plus grands.

Fréquence du processeur

J'ai eu du mal à trouver ça, mais en tout cas il y a de grands hommes. Je vous remercie.

Ubuntu CPUfreq Part 3-About the files in the cpufreq folder of the CPU

#/sys/devices/system/cpu/cpu*/cpu freq à cpu(coeur)Les informations sont collectées
#cpuinfo_cur_freq est la valeur obtenue à partir du matériel
#scaling_cur_freq est la valeur obtenue à partir du noyau Linux

cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
#Permission denied
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
#La fréquence CPU de cpu0 est affichée

C'est bien de trouver une place, mais j'ai rencontré deux problèmes. La première est que vous ne pouvez voir root que pour les nombres obtenus à partir du matériel, et l'autre est que les fichiers sont différents pour chaque cœur de processeur. Si possible, je voudrais me référer à la valeur numérique obtenue à partir du matériel, mais je veux l'exécuter sans root, et si la fréquence est différente pour chaque cœur de processeur, je veux prendre la moyenne, mais je veux l'éviter car le traitement sera quadruplé.

J'ai essayé de vérifier avec la force brute pour résoudre ces problèmes. Si les huit valeurs correspondent, il n'y a pas de problème même si une valeur est utilisée comme échantillon représentatif, alors obtenez et comparez 10000 fois cpuinfo_cur_freq et scaling_cur_freq des 4 cœurs. En conséquence, ils correspondaient tous à un taux d'environ 95%. Il semble qu'il y ait un décalage lors du changement de fréquence, et si vous mettez un sommeil entre les vérifications, il était d'environ 95%, et si vous ne faisiez rien et le répétiez, c'était 100% cohérent. De plus, il semble que l'écart se produise principalement entre le matériel et le noyau, et que la correspondance entre les cœurs était d'environ 99% au pire. Cela n'a pas besoin d'être aussi strict, et l'échantillonnage chaque seconde aura peu d'effet, donc cette fois j'ai décidé d'utiliser scaling_cur_freq of cpu0 comme valeur représentative.

Sous Linux (dans Raspberry Pi?), Vous ne contrôlez pas d'économiser de l'énergie en changeant la fréquence pour chaque cœur. Je vous serais reconnaissant de bien vouloir me faire savoir si quelqu'un connaît ce domaine.

Tension du processeur

Nous n'avons pas pu trouver l'emplacement du fichier. Vous pouvez le trouver si vous le cherchez sérieusement, mais comme c'était une valeur qui n'avait pas à être à l'origine, j'ai décidé de le couper à ce moment-là. Si quelqu'un sait, faites-le moi savoir.

Résumé

J'ai commencé à travailler sur la réduction du poids des scripts lourds, et depuis que j'ai surveillé le CPU avec Python, j'ai ajouté le but de le compléter uniquement avec Python, et à la fin j'ai réussi à réduire considérablement le poids. Je suis parfaitement conscient de mes études quotidiennes car je peux en apprendre davantage sur des fonctions super utiles que je ne connaissais pas. J'ai également pu l'affiner un peu en réécrivant le code lors de la rédaction de cet article. La révision est importante. Cela a été un long article, mais merci d'avoir lu jusqu'au bout. Si vous avez des suggestions, n'hésitez pas à nous contacter.

Recommended Posts

[Version améliorée] Script pour surveiller le CPU avec Python
Vérifier la version avec python
Script Python pour obtenir des informations de note avec REAPER
Comment ajouter de l'aide à HDA (avec bonus de script Python)
Connectez-vous à Wikipedia avec Python
Publiez sur Slack avec Python 3
Basculer python vers 2.7 avec des alternatives
Écrire en csv avec Python
Introduction à Python (version Python APG4b)
Comment changer la version de Python
Spécifiez la version python avec virtualenv
Je souhaite spécifier une autre version de Python avec pyvenv
Python: comment utiliser async avec
Lien pour commencer avec python
[Python] Ecrire dans un fichier csv avec Python
Ravi de vous rencontrer avec python
Essayez d'exploiter Facebook avec Python
Sortie vers un fichier csv avec Python
Surveillez les applications Web Python avec Prometheus
Surveillez les performances des applications Python avec Dynatrace ♪
Comment obtenir la version Python
Convertir la liste en DataFrame avec python
Conversion MP3 → WAV avec Python
[python] Script de copie pour générer un journal de copie
Pour faire une récursion avec Python2
Comment démarrer avec Python
Que faire avec la sortie de PYTHON?
Gérez chaque version de Python avec Homebrew
Comment calculer la date avec python
Publiez facilement sur Twitter avec Python 3
Je veux déboguer avec Python
Version Python pour obtenir les ports inutilisés
Ecrire un script batch avec Python3.5 ~
[AWS SAM] Présentation de la version Python
Comment installer automatiquement le pilote Chrome pour la version Chrome avec Python + Selenium + Chrome
Convertir un script Python écrit dans PyTorch en exe avec PyInstaller
ImportError lors de la tentative d'utilisation du package gcloud avec la version AWS Lambda Python
[Blender] Comment définir shape_key avec un script
Essayez de reproduire un film couleur avec Python
Essayez de vous connecter à qiita avec Python
Changer l'environnement Python 64 bits en environnement 32 bits avec Anaconda
Reconnaissance vocale en anglais avec python [speech to text]
Convertir un mémo à la fois avec Python 2to3
mail html avec image à envoyer avec python
[Yahoo! Weather Replacement Version] Comment obtenir des informations météo avec LINE Notify + Python
Mémo pour demander des KPI avec python
python à retenir uniquement avec bonjour, mondes
Exécuter le script Python avec TS-220 cron
Sortir les caractères de couleur en joli avec python
Épingler le répertoire actuel au répertoire de script en Python
Si vous souhaitez inclure awsebcli dans CircleCI, spécifiez la version de python
Exemple de script pour piéger les signaux en Python
Sortie du journal Python vers la console avec GAE
Convertir des données Excel en JSON avec python
Convertir Hiragana en Romaji avec Python (bêta)