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.
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.
Il y a quatre améliorations principales.
subprocess
par ʻopen ()`print
avec formatLe 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.
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
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 doubler
CPU> 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'utilisation
get_data ()`.
Après cela, je voudrais en parler dans l'explication.
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.
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.
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à.
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.
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.
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.
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