Python-profiler

Källkod: Lib/profile.py och Lib/pstats.py


Introduktion till profileringsverktygen

cProfile och profile ger deterministisk profilering av Python-program. En profile är en uppsättning statistik som beskriver hur ofta och hur länge olika delar av programmet kördes. Denna statistik kan formateras till rapporter via modulen pstats.

Pythons standardbibliotek tillhandahåller två olika implementeringar av samma profileringsgränssnitt:

  1. cProfile rekommenderas för de flesta användare; det är ett C-tillägg med rimlig overhead som gör det lämpligt för profilering av långkörande program. Baserat på lsprof, med bidrag från Brett Rosen och Ted Czotter.

  2. profile, en ren Python-modul vars gränssnitt imiteras av cProfile, men som lägger till betydande overhead till profilerade program. Om du försöker utöka profileraren på något sätt kan uppgiften vara enklare med den här modulen. Ursprungligen designad och skriven av Jim Roskind.

Anteckning

Profilermodulerna är utformade för att ge en exekveringsprofil för ett visst program, inte för benchmarking (för det finns timeit för rimligt exakta resultat). Detta gäller särskilt för benchmarking av Python-kod mot C-kod: profilerarna introducerar overhead för Python-kod, men inte för funktioner på C-nivå, och därför skulle C-koden verka snabbare än någon Python-kod.

Användarmanual för Instant

Det här avsnittet är avsett för användare som ”inte vill läsa manualen” Det ger en mycket kort översikt och gör det möjligt för en användare att snabbt utföra profilering på en befintlig applikation.

För att profilera en funktion som tar ett enda argument kan du göra så här:

import cProfile
import re
cProfile.run('re.compile("foo|bar")')

(Använd profile i stället för cProfile om den senare inte finns tillgänglig i ditt system)

Ovanstående åtgärd skulle köra re.compile() och skriva ut profilresultat som följande:

      214 funktionsanrop (207 primitiva anrop)  0,002 sekunder

Ordnad efter: kumulativ tid

ncalls tottime percall cumtime percall filnamn:lineno(funktion)
     1 0,000 0,000 0,002 0,002 {inbyggd metod builtins.exec}
     1 0,000 0,000 0,001 0,001 <string>:1(<module>)
     1 0,000 0,000 0,001 0,001 __init__.py:250(kompilera)
     1 0,000 0,000 0,001 0,001 __init__.py:289(_kompilering)
     1 0,000 0,000 0,000 0,000 _compiler.py:759(kompilera)
     1 0,000 0,000 0,000 0,000 _parser.py:937(parse)
     1 0,000 0,000 0,000 0,000 _compiler.py:598(_code)
     1 0,000 0,000 0,000 0,000 0,000 _parser.py:435(_parse_sub)

Den första raden visar att 214 anrop övervakades. Av dessa anrop var 207 primitive, vilket betyder att anropet inte inducerades via rekursion. Nästa rad: Ordered by: cumulative time anger att utdata är sorterade efter cumtime-värdena. Kolumnrubrikerna inkluderar:

ncalls

för antalet samtal.

tottid

för den totala tid som tillbringats i den givna funktionen (och exklusive tid för anrop till underfunktioner)

per telefon

är kvoten av tottime dividerat med ncalls

cumtime

är den ackumulerade tid som använts i denna och alla underfunktioner (från anrop till avslut). Denna siffra är korrekt även för rekursiva funktioner.

per telefon

är kvoten av cumtime dividerat med primitiva anrop

filnamn:lineno(funktion)

tillhandahåller respektive data för varje funktion

När det finns två siffror i den första kolumnen (t.ex. 3/1) betyder det att funktionen recursade. Det andra värdet är antalet primitiva anrop och det första är det totala antalet anrop. Observera att när funktionen inte recurserar är dessa två värden desamma och endast den enda siffran skrivs ut.

I stället för att skriva ut resultatet i slutet av profilkörningen kan du spara resultatet i en fil genom att ange ett filnamn i funktionen run():

import cProfile
import re
cProfile.run('re.compile("foo|bar")', 'restats')

Klassen pstats.Stats läser in profilresultat från en fil och formaterar dem på olika sätt.

Filerna cProfile och profile kan också användas som ett skript för att profilera ett annat skript. Till exempel:

python -m cProfile [-o output_file] [-s sort_order] (-m modul | myscript.py)
-o <output_file>

Skriver profilresultaten till en fil i stället för till stdout.

-s <sort_order>

Anger ett av sorteringsvärdena i sort_stats() för att sortera utdata efter. Detta gäller endast när -o inte anges.

-m <module>

Anger att det är en modul som profileras i stället för ett skript.

Tillagd i version 3.7: Alternativet -m lades till i cProfile.

Tillagd i version 3.8: Alternativet -m lades till i profile.

Modulen pstats klass Stats har en mängd olika metoder för att manipulera och skriva ut data som sparats i en profilresultatfil:

import pstats
from pstats import SortKey
p = pstats.Stats('restats')
p.strip_dirs().sort_stats(-1).print_stats()

Metoden strip_dirs() tog bort den främmande sökvägen från alla modulnamn. Metoden sort_stats() sorterade alla poster enligt den standardsträng för modul/rad/namn som skrivs ut. Metoden print_stats() skrev ut all statistik. Du kan prova följande sorteringsanrop:

p.sort_stats(SortKey.NAME)
p.print_stats()

Det första anropet sorterar faktiskt listan efter funktionsnamn och det andra anropet skriver ut statistiken. Följande är några intressanta anrop att experimentera med:

p.sort_stats(SortKey.CUMULATIVE).print_stats(10)

Detta sorterar profilen efter kumulativ tid i en funktion och skriver sedan bara ut de tio mest betydelsefulla raderna. Om du vill förstå vilka algoritmer som tar tid är det raden ovan som du ska använda.

Om du ville se vilka funktioner som loopade mycket och tog mycket tid, skulle du göra:

p.sort_stats(SortKey.TIME).print_stats(10)

för att sortera efter tidsåtgång inom varje funktion och sedan skriva ut statistiken för de tio bästa funktionerna.

Du kan också prova:

p.sort_stats(SortKey.FILENAME).print_stats('__init__')

Detta sorterar all statistik efter filnamn och skriver sedan ut statistik för endast klassens init-metoder (eftersom de stavas med __init__ i sig). Som ett sista exempel kan du prova:

p.sort_stats(SortKey.TIME, SortKey.CUMULATIVE).print_stats(.5, 'init')

Denna rad sorterar statistik med en primär nyckel för tid och en sekundär nyckel för kumulativ tid, och skriver sedan ut en del av statistiken. För att vara specifik, gallras listan först ner till 50% (re: .5) av sin ursprungliga storlek, sedan behålls endast rader som innehåller init, och den under-sub-listan skrivs ut.

Om du undrade vilka funktioner som kallade ovanstående funktioner, kan du nu (p är fortfarande sorterad enligt det sista kriteriet) göra:

p.print_callers(.5, 'init')

och du får en lista över personer som ringer för var och en av de listade funktionerna.

Om du vill ha fler funktioner måste du läsa manualen eller gissa vad följande funktioner gör:

p.print_callees()
p.add('restats')

Modulen pstats anropas som ett skript och är en statistikbläddrare för läsning och granskning av profildumpar. Den har ett enkelt linjeorienterat gränssnitt (implementerat med hjälp av cmd) och interaktiv hjälp.

profile och cProfile Modulreferens

Både modulerna profile och cProfile innehåller följande funktioner:

profile.run(command, filename=None, sort=-1)

Denna funktion tar ett enda argument som kan skickas till exec()-funktionen, och ett valfritt filnamn. I samtliga fall exekveras denna rutin:

exec(kommando, __main__.__dict__, __main__.__dict__)

och samlar in profileringsstatistik från körningen. Om det inte finns något filnamn skapar funktionen automatiskt en Stats-instans och skriver ut en enkel profileringsrapport. Om sorteringsvärdet anges skickas det till denna Stats-instans för att styra hur resultaten ska sorteras.

profile.runctx(command, globals, locals, filename=None, sort=-1)

Den här funktionen liknar run(), med extra argument för att ange mappningarna för globals och locals för command-strängen. Den här rutinen exekverar:

exec(kommando, globals, locals)

och samlar in profileringsstatistik som i funktionen run() ovan.

class profile.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)

Den här klassen används normalt bara om det behövs mer exakt kontroll över profileringen än vad funktionen cProfile.run() ger.

En egen timer kan tillhandahållas för att mäta hur lång tid det tar för koden att köras via argumentet timer. Detta måste vara en funktion som returnerar ett enda tal som representerar den aktuella tiden. Om talet är ett heltal anger timeunit en multiplikator som anger varaktigheten för varje tidsenhet. Om timern t.ex. returnerar tider som mäts i tusendelar av sekunder, är tidsenheten .001.

Genom att direkt använda klassen Profile kan du formatera profilresultat utan att skriva profildata till en fil:

import cProfile, pstats, io
från pstats import SortKey
pr = cProfile.profil()
pr.enable()
# ... gör något ...
pr.disable()
s = io.StringIO()
sortby = SortKey.CUMULATIVE
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print(s.getvalue())

Klassen Profile kan också användas som en kontexthanterare (stöds endast i modulen cProfile. se Typer av kontexthanterare):

import cProfile

med cProfile.Profile() som pr:
    # ... gör något ...

    pr.print_stats()

Ändrad i version 3.8: Stöd för kontexthanterare har lagts till.

enable()

Börja samla in profileringsdata. Endast i cProfile.

disable()

Sluta samla in profileringsdata. Endast i cProfile.

create_stats()

Sluta samla in profileringsdata och registrera resultaten internt som den aktuella profilen.

print_stats(sort=-1)

Skapa ett Stats-objekt baserat på den aktuella profilen och skriv ut resultaten till stdout.

Parametern sort anger sorteringsordningen för den statistik som visas. Den accepterar en enda nyckel eller en tupel av nycklar för att möjliggöra sortering på flera nivåer, som i Stats.sort_stats.

Tillagd i version 3.13: print_stats() accepterar nu en tupel av nycklar.

dump_stats(filename)

Skriv resultatet av den aktuella profilen till filnamn.

run(cmd)

Profilera cmd:n via exec().

runctx(cmd, globals, locals)

Profilera cmd via exec() med den angivna globala och lokala miljön.

runcall(func, /, *args, **kwargs)

Profil func(*args, **kwargs)

Observera att profileringen endast fungerar om det anropade kommandot/funktionen faktiskt returneras. Om tolken avslutas (t.ex. via ett sys.exit()-anrop under exekveringen av det anropade kommandot/funktionen) kommer inga profileringsresultat att skrivas ut.

Klassen Stats

Analys av profileringsdata görs med hjälp av klassen Stats.

class pstats.Stats(*filenames or profile, stream=sys.stdout)

Denna klasskonstruktor skapar en instans av ett ”statistikobjekt” från ett filnamn (eller en lista med filnamn) eller från en Profile-instans. Utdata kommer att skrivas ut till den ström som anges av stream.

Den fil som väljs av ovanstående konstruktör måste ha skapats av motsvarande version av profile eller cProfile. För att vara specifik, det finns ingen garanterad filkompatibilitet med framtida versioner av denna profilerare, och det finns ingen kompatibilitet med filer som producerats av andra profilerare, eller samma profilerare som körs på ett annat operativsystem. Om flera filer tillhandahålls kommer all statistik för identiska funktioner att sammanställas, så att en övergripande bild av flera processer kan beaktas i en enda rapport. Om ytterligare filer behöver kombineras med data i ett befintligt Stats-objekt, kan metoden add() användas.

I stället för att läsa profildata från en fil kan ett cProfile.Profile- eller profile.Profile-objekt användas som profildatakälla.

Stats-objekt har följande metoder:

strip_dirs()

Den här metoden för klassen Stats tar bort all inledande sökvägsinformation från filnamn. Det är mycket användbart för att minska storleken på utskriften så att den ryms inom (nära) 80 kolumner. Den här metoden ändrar objektet och den borttagna informationen går förlorad. Efter att ha utfört en strippning anses objektet ha sina poster i en ”slumpmässig” ordning, som den var precis efter initialisering och laddning av objektet. Om strip_dirs() gör att två funktionsnamn inte går att skilja åt (de står på samma rad i samma filnamn och har samma funktionsnamn), ackumuleras statistiken för dessa två poster till en enda post.

add(*filenames)

Denna metod i klassen Stats ackumulerar ytterligare profileringsinformation i det aktuella profileringsobjektet. Dess argument bör referera till filnamn som skapats av motsvarande version av profile.run() eller cProfile.run(). Statistik för identiskt namngivna (re: fil, rad, namn) funktioner ackumuleras automatiskt till statistik för en enda funktion.

dump_stats(filename)

Spara data som laddats i objektet Stats till en fil med namnet filnamn. Filen skapas om den inte finns, och skrivs över om den redan finns. Detta är likvärdigt med metoden med samma namn i klasserna profile.Profile och cProfile.Profile.

sort_stats(*keys)

Denna metod modifierar Stats-objektet genom att sortera det enligt de angivna kriterierna. Argumentet kan vara antingen en sträng eller ett SortKey-enum som identifierar grunden för en sortering (exempel: 'time', 'name', SortKey.TIME eller SortKey.NAME). Argumentet SortKey enums har en fördel jämfört med strängargumentet genom att det är mer robust och mindre felbenäget.

När mer än en nyckel anges används ytterligare nycklar som sekundära kriterier när det råder likhet mellan alla nycklar som valts före dem. Exempelvis sorterar sort_stats(SortKey.NAME, SortKey.FILE) alla poster efter deras funktionsnamn och löser alla oavgjorda frågor (identiska funktionsnamn) genom att sortera efter filnamn.

För strängargumentet kan förkortningar användas för alla nyckelnamn, så länge förkortningen är entydig.

Följande är giltiga strängar och SortKey:

Giltig sträng Arg

Giltig enum Arg

Betydelse

'calls'

SortKey.CALLS

antal samtal

'cumulative'

SortKey.KUMULATIV

kumulativ tid

'cumtime'

N/A

kumulativ tid

'file'

N/A

filnamn

'filename'

SortKey.FILENAME

filnamn

'module'

N/A

filnamn

'ncalls'

N/A

antal samtal

'pcalls'

Sorteringsnyckel.PCALLS

antal primitiva samtal

'line'

Sorteringsnyckel.LINJE

radnummer

'name'

Sorteringsnyckel.namn

funktionsnamn

'nfl'

Sorteringsnyckel.NFL

namn/fil/rad

'stdname'

SortKey.STDNAME

standardnamn

'time'

Sorteringsnyckel.TIME

intern tid

'tottime'

N/A

intern tid

Observera att alla sorteringar av statistik är i fallande ordning (de mest tidskrävande först), medan sökningar efter namn, filer och radnummer är i stigande ordning (alfabetisk). Den subtila skillnaden mellan SortKey.NFL och SortKey.STDNAME är att standardnamnet är en sortering av namnet som det skrivs ut, vilket innebär att de inbäddade radnumren jämförs på ett udda sätt. Till exempel skulle raderna 3, 20 och 40 (om filnamnen var desamma) visas i strängordningen 20, 3 och 40. Däremot gör SortKey.NFL en numerisk jämförelse av radnumren. I själva verket är Sort_stats(SortKey.NFL) samma sak som Sort_stats(SortKey.NAME, SortKey.FILENAME, SortKey.LINE).

Av bakåtkompatibilitetsskäl är de numeriska argumenten -1, 0, 1 och 2 tillåtna. De tolkas som 'stdname', 'calls', 'time' respektive 'cumulative'. Om detta gamla format (numeriskt) används, kommer endast en sorteringsnyckel (den numeriska nyckeln) att användas, och ytterligare argument kommer att ignoreras.

Tillagd i version 3.7: Enumret SortKey har lagts till.

reverse_order()

Denna metod för klassen Stats reverserar ordningen på grundlistan i objektet. Observera att som standard väljs stigande eller fallande ordning korrekt baserat på den valda sorteringsnyckeln.

print_stats(*restrictions)

Denna metod för klassen Stats skriver ut en rapport enligt beskrivningen i definitionen profile.run().

Ordningen på utskriften baseras på den senaste sort_stats()-operationen som gjordes på objektet (med förbehåll för förbehåll i add() och strip_dirs()).

De argument som anges (om några) kan användas för att begränsa listan till de viktiga posterna. Inledningsvis antas listan vara den fullständiga uppsättningen profilerade funktioner. Varje begränsning är antingen ett heltal (för att välja ett antal rader), en decimal mellan 0,0 och 1,0 (för att välja en procentandel av raderna) eller en sträng som tolkas som ett reguljärt uttryck (för att matcha det standardnamn som skrivs ut). Om flera begränsningar anges tillämpas de i tur och ordning. Exempel:

print_stats(.1, 'foo:')

skulle först begränsa utskriften till den första 10% of-listan och sedan bara skriva ut funktioner som ingick i filnamnet .*foo:. I motsats till detta skulle kommandot:

print_stats('foo:', .1)

skulle begränsa listan till alla funktioner som har filnamnen .*foo:, och sedan bara skriva ut de första 10% of dem.

print_callers(*restrictions)

Denna metod för klassen Stats skriver ut en lista över alla funktioner som anropade varje funktion i den profilerade databasen. Ordningen är identisk med den som tillhandahålls av print_stats(), och definitionen av det begränsande argumentet är också identisk. Varje uppringare rapporteras på en egen rad. Formatet skiljer sig något beroende på vilken profilerare som producerade statistiken:

  • Med profile visas ett tal inom parentes efter varje uppringare för att visa hur många gånger just detta uppringande gjordes. För enkelhetens skull upprepar en andra siffra utan parentes den sammanlagda tid som tillbringats i funktionen till höger.

  • Med cProfile föregås varje anrop av tre siffror: antalet gånger som det specifika anropet gjordes och den totala och kumulativa tid som spenderades i den aktuella funktionen när den anropades av den specifika anroparen.

print_callees(*restrictions)

Denna metod för klassen Stats skriver ut en lista över alla funktioner som anropades av den angivna funktionen. Bortsett från denna omkastning av anropens riktning (re: called vs was called by) är argumenten och ordningen identiska med metoden print_callers().

get_stats_profile()

Denna metod returnerar en instans av StatsProfile, som innehåller en mappning av funktionsnamn till instanser av FunctionProfile. Varje FunctionProfile-instans innehåller information som är relaterad till funktionens profil, t.ex. hur lång tid det tog för funktionen att köras, hur många gånger den anropades osv.

Tillagd i version 3.9: Lade till följande dataklasser: StatsProfile, FunctionProfile. Följande funktion lades till: get_stats_profile.

Vad är deterministisk profilering?

Deterministic profiling är tänkt att återspegla det faktum att alla händelser av typen funktionsanrop, funktionsretur och undantag övervakas och att exakta tidsangivelser görs för intervallen mellan dessa händelser (under vilken tid användarens kod exekveras). Vid statistical profiling (som inte görs av den här modulen) görs däremot slumpmässiga stickprov på den effektiva instruktionspekaren och man drar slutsatser om var tiden spenderas. Den senare tekniken innebär traditionellt mindre overhead (eftersom koden inte behöver instrumenteras), men ger bara relativa indikationer på var tiden spenderas.

I Python, eftersom det finns en tolk som är aktiv under exekveringen, krävs det inte att det finns instrumenterad kod för att göra en deterministisk profilering. Python tillhandahåller automatiskt en hook (valfri callback) för varje händelse. Dessutom tenderar Pythons tolkade natur att lägga till så mycket overhead till exekveringen att deterministisk profilering tenderar att bara lägga till liten bearbetningsoverhead i typiska applikationer. Resultatet är att deterministisk profilering inte är särskilt dyr, men ändå ger omfattande körtidsstatistik om körningen av ett Python-program.

Statistik över antal anrop kan användas för att identifiera buggar i koden (överraskande antal anrop) och för att identifiera möjliga punkter för inline-expansion (högt antal anrop). Intern tidsstatistik kan användas för att identifiera ”heta loopar” som bör optimeras noggrant. Kumulativ tidsstatistik bör användas för att identifiera högnivåfel i valet av algoritmer. Observera att den ovanliga hanteringen av kumulativa tider i den här profileraren gör att statistik för rekursiva implementeringar av algoritmer kan jämföras direkt med iterativa implementeringar.

Begränsningar

En begränsning har att göra med noggrannheten i tidsinformationen. Det finns ett grundläggande problem med deterministiska profilerare som rör noggrannhet. Den mest uppenbara begränsningen är att den underliggande ”klockan” bara tickar med en hastighet (typiskt) på cirka 0,001 sekunder. Därför kommer inga mätningar att vara mer exakta än den underliggande klockan. Om tillräckligt många mätningar görs tenderar ”felet” att jämna ut sig. Om man tar bort detta första fel uppstår tyvärr en andra felkälla.

Det andra problemet är att det ”tar ett tag” från det att en händelse skickas till dess att profilerarens anrop för att få tiden faktiskt får klockans tillstånd. På samma sätt finns det en viss fördröjning när man lämnar profileringshändelsehanteraren från det att klockans värde erhölls (och sedan gömdes undan) tills användarens kod återigen körs. Därför kommer funktioner som anropas många gånger, eller som anropar många funktioner, vanligtvis att ackumulera detta fel. Felet som ackumuleras på detta sätt är vanligtvis mindre än klockans noggrannhet (mindre än ett klockslag), men det kan ackumuleras och bli mycket betydande.

Problemet är större med profile än med den mindre avancerade cProfile. Av denna anledning tillhandahåller profile ett sätt att kalibrera sig själv för en given plattform så att detta fel kan tas bort på ett probabilistiskt sätt (i genomsnitt). När profileraren har kalibrerats kommer den att vara mer exakt (i minsta kvadrat-led), men den kommer ibland att producera negativa siffror (när antalet anrop är exceptionellt lågt och sannolikhetens gudar arbetar emot dig :-). ) Låt dig inte skrämmas av negativa siffror i profilen. De ska endast visas om du har kalibrerat din profilerare och resultaten faktiskt är bättre än utan kalibrering.

Kalibrering

Profileraren i modulen profile subtraherar en konstant från varje händelsehanteringstid för att kompensera för omkostnaderna för att anropa tidsfunktionen och lagra resultaten. Som standard är konstanten 0. Följande procedur kan användas för att få en bättre konstant för en viss plattform (se Begränsningar).

import profile
pr = profile.Profile()
for i in range(5):
    print(pr.calibrate(10000))

Metoden kör det antal Python-anrop som anges i argumentet, direkt och igen under profileraren, och mäter tiden för båda. Den beräknar sedan den dolda overhead per profileringshändelse och returnerar den som en float. Till exempel, på en 1,8 GHz Intel Core i5 som kör macOS och använder Pythons time.process_time() som timer, är det magiska talet cirka 4,04e-6.

Syftet med den här övningen är att få ett någorlunda konsekvent resultat. Om din dator är mycket snabb, eller om din timerfunktion har dålig upplösning, kan du behöva passera 100000, eller till och med 1000000, för att få konsekventa resultat.

När du har ett konsekvent svar kan du använda det på tre sätt:

importprofil

# 1. Tillämpa beräknad bias på alla profilinstanser som skapas hädanefter.
profile.Profile.bias = din_beräknade_bias

# 2. Tillämpa beräknad förspänning på en specifik profilinstans.
pr = profile.Profile()
pr.bias = din_beräknade_bias

# 3. Ange beräknad förspänning i instansens konstruktör.
pr = profile.Profile(bias=din_beräknade_bias)

Om du har ett val är det bättre att du väljer en mindre konstant, och då kommer dina resultat ”mindre ofta” att visa sig vara negativa i profilstatistiken.

Använda en anpassad timer

Om du vill ändra hur aktuell tid bestäms (t.ex. för att tvinga fram användning av väggklockans tid eller förfluten processtid), skickar du den tidsfunktion du vill ha till Profile-klassens konstruktör:

pr = profil.Profil(din_tid_func)

Den resulterande profileraren kommer sedan att anropa your_time_func. Beroende på om du använder profile.Profile eller cProfile.Profile, kommer your_time_func’s returvärde att tolkas på olika sätt:

profile.Profile

your_time_func bör returnera ett enda tal, eller en lista med tal vars summa är den aktuella tiden (som vad os.times() returnerar). Om funktionen returnerar ett enda tidsnummer, eller om listan med returnerade nummer har längden 2, får du en särskilt snabb version av sändningsrutinen.

Tänk på att du bör kalibrera profileringsklassen för den timerfunktion du väljer (se Kalibrering). För de flesta maskiner kommer en timer som returnerar ett ensamt heltalsvärde att ge de bästa resultaten när det gäller låg overhead under profileringen. (os.times() är ganska dålig, eftersom den returnerar en tupel av flyttalsvärden). Om du vill byta ut en bättre timer på det renaste sättet, härled en klass och hårdkoppla en ersättande dispatch-metod som bäst hanterar ditt timeranrop, tillsammans med lämplig kalibreringskonstant.

cProfile.Profile

your_time_func bör returnera ett enda tal. Om den returnerar heltal kan du också anropa klasskonstruktören med ett andra argument som anger den verkliga varaktigheten för en tidsenhet. Om till exempel your_integer_time_func returnerar tider som mäts i tusentals sekunder, skulle du konstruera Profile-instansen på följande sätt:

pr = cProfile.Profile(din_integer_tid_func, 0,001)

Eftersom klassen cProfile.Profile inte kan kalibreras, bör anpassade timerfunktioner användas med försiktighet och vara så snabba som möjligt. För bästa resultat med en egen timer kan det vara nödvändigt att hårdkoda den i C-källan för den interna _lsprof-modulen.

Python 3.3 lägger till flera nya funktioner i time som kan användas för att göra exakta mätningar av process- eller väggklocktid. Se till exempel time.perf_counter().