Profilazione programma Python con Yappi

Il profile Yappi deve essere integrato all'interno del programma Python, non può essere eseguito come wrapper esterno allo script, ma ha il vantaggio di poter profilare anche thread separati creati dal modulo daemon.DaemonContext, threading.Timer oppure threading.Thread.

In Debian 11 Bullseye esiste la versione 1.0 di Yappi:

apt install python3-yappi

Peccato che gli esempi forniti in documentazione non funzioninio:

Function stats for (Timer) (3)
Traceback (most recent call last):
  File "/usr/local/sbin/protherm", line 1258, in <module>
    program_main()
  File "/usr/local/sbin/protherm", line 1200, in program_main
    yappi.get_func_stats(ctx_id=thread.id).print_all()
TypeError: get_func_stats() got an unexpected keyword argument 'ctx_id'

Si installa pertanto la versione corrente 1.3.3 dal repository tramite pip:

pip3 install yappi

Ecco uno pseudo esempio di come implementare il profiler all'uscita di un programma che utilizza un timer (per eseguire azioni periodiche), un thread (per gestire un socket TCP) e daemon (per fare il fork in background):

import daemon
import socketserver
import threading
import yappi
 
def timer_callback():
    ...
 
class socket_tcp_handler(socketserver.StreamRequestHandler):
    ...
 
def main_loop():
    tcp_server = socketserver.TCPServer((BIND_ADDR, TCP_PORT), socket_tcp_handler)
    timer1_thread = threading.Timer(interval, timer_callback)
    th = threading.Thread(target=tcp_server.serve_forever)
    yappi.start()
    while not exit_program:
        ...
    # Retrieve thread stats by their thread id (given by yappi)
    yappi.stop()
    threads = yappi.get_thread_stats()
    for thread in threads:
        print("\n===== Function stats for (%s) (%d)" % (thread.name, thread.id))
        yappi.get_func_stats(ctx_id=thread.id).print_all()
 
context = daemon.DaemonContext(...)
with context:
    main_loop()