J'ai du code Python que je veux déboguer avec perf. Pour cela, je souhaite utiliser un sous-processus. La commande suivante renvoie des informations relatives aux instructions d'un processus jusqu'à ce que la commande soit quittée via Ctrl ^ C.

perf stat -p <my_pid>

Maintenant, je veux l'exécuter dans un code Python en arrière-plan, jusqu'à un moment où je veux être en mesure de terminer son opération et d'imprimer la sortie des commandes. Pour montrer ce que je veux dire:

x = subprocess.call(["perf","stat","-p",str(GetMyProcessID())])

.. CODE TO DEBUG ..

print x   # I want to terminate subprocess here and output 'x'

Maintenant, je veux déterminer ce qu'il faut faire à la ligne de 'print x' pour terminer le processus et vérifier la sortie. Toute idée / aide est appréciée.

Santé et merci d'avance,

6
mozcelikors 14 janv. 2017 à 23:10

2 réponses

Meilleure réponse

Premièrement: je déconseille d'appeler perf à partir de votre processus python (comme vous le voyez dans la complexité de la tâche ci-dessous), mais à la place, utilisez la ligne de commande:

sudo perf stat -- python test.py

Si vous vraiment souhaitez appeler perf depuis python, vous rencontrerez des problèmes délicats:

  1. pour terminer perf et lui faire afficher les statistiques de performances rassemblées, vous devez lui envoyer le signal SIGINT (essayez-le avec sudo perf stat -p mypid: ctrl-\ n'imprimera rien alors que {{X4 }} volonté)
  2. vous devez capturer stderr car perf envoie sa sortie à stderr (au moins dans ma version)
  3. vous devez utiliser fork() avec un processus qui envoie SIGINT et l'autre lecture est sortie pendant que le processus meurt. Sans fourches, cela ne fonctionnera pas car après avoir SIGINT édité le processus perf, vous ne pouvez plus lire depuis stdin car le processus est déjà terminé, et lorsque vous lisez depuis stdin pour la première fois, vous avez gagné n'obtient aucune sortie tant que perf n'est pas correctement terminé.

Cela signifie que vous vous retrouverez avec ce programme python:

import subprocess
import os
import signal
import time

perf = subprocess.Popen(['perf', 'stat',  '-p', str(os.getpid())], stderr=subprocess.PIPE)

# <-- your code goes here

if os.fork() == 0:
    # child
    time.sleep(1)  # wait until parent runs `stderr.read()`
    perf.send_signal(signal.SIGINT)
    exit(0)

# parent
print("got perf stats>>{}<<".format(perf.stderr.read().decode("utf-8")))

Le bit time.sleep(1) est moche, ce qu'il fait c'est qu'il le fera mais j'imagine qu'il fera l'affaire dans 99% des cas. Il n'a pratiquement aucune influence sur les données de performance, la seule influence qu'il a sur le "temps d'exécution total" (*xx seconds time elapsed)

3
hansaplast 16 janv. 2017 à 15:55