Package: pyprof
PyProfA pure python time profilerInstallationpipinstallpyprofExamplefrompyprofimportprofile,Profiler,reportimporttimefromconcurrent.futuresimportThreadPoolExecutorfromtests.test_utilsimportclose# `profile` can be used as a decorator directly.# In such cases, the name of the Profiler is automatically extracted@profiledeff():time.sleep(0.1)# `profile` can be used as a context managerwithprofile("sleep"):time.sleep(0.03)# `profile` can be used as a decorator with a specified name@profile('single-thread')defh():foriinrange(10):f()@profile('multi-thread')defg():withThreadPoolExecutor()asexecutor:foriinrange(10):executor.submit(f)deftest_main():h()assertProfiler.get("/single-thread").count==1assertclose(Profiler.get("/single-thread").total,10*0.13)# Profiler automatically find parent ProfilerassertProfiler.get("/single-thread/f").count==10assertclose(Profiler.get("/single-thread/f").total,10*0.13)assertclose(Profiler.get("/single-thread/f").average,0.13)assertclose(Profiler.get("/single-thread/f").standard_deviation,0.)assertclose(Profiler.get("/single-thread/f/sleep").total,10*0.03)assertclose(Profiler.get("/single-thread/f/sleep").average,0.03)assertclose(Profiler.get("/single-thread/f/sleep").standard_deviation,0.)g()assertProfiler.get("/multi-thread").count==1# Profiler cannot automatically find parent Profiler in other threadsassertProfiler.get("/f").count==10assertclose(Profiler.get("/f").total,10*0.13)assertclose(Profiler.get("/f").average,0.13)assertclose(Profiler.get("/f").standard_deviation,0.)assertclose(Profiler.get("/f/sleep").total,10*0.03)assertclose(Profiler.get("/f/sleep").average,0.03)assertclose(Profiler.get("/f/sleep").standard_deviation,0.)# print a formatted time usage reportprint(report())# filter componentsprint(report(min_total_percent=0.1,min_parent_percent=0.5))# `profile` automatically print report if `report_printer` is givenwithprofile('auto-print',report_printer=print):f()withprofile('auto-print',report_printer=print):f()assertProfiler.get("/auto-print").count==2# use `flush=True` to reset a Profiler and all its childrenwithprofile('auto-print',report_printer=print,flush=True):f()assertProfiler.get("/auto-print").count==1if__name__=='__main__':test_main()Output|path                  |%total     |%parent    |count   |total      |mean(±std)              |min-max              |
|                      |    100.00%|    100.00%|      12|     2.862s|     0.238(±     0.334)s|     0.137~     1.345|
|/f                    |     48.14%|     48.14%|      10|     1.378s|     0.138(±     0.000)s|     0.137~     0.138|
|/f/sleep              |     11.85%|     24.63%|      10|     0.339s|     0.034(±     0.001)s|     0.032~     0.035|
|/multi-thread         |      4.87%|      4.87%|       1|     0.139s|     0.139(±     0.000)s|     0.139~     0.139|
|/single-thread        |     47.00%|     47.00%|       1|     1.345s|     1.345(±     0.000)s|     1.345~     1.345|
|/single-thread/f      |     46.98%|     99.97%|      10|     1.345s|     0.134(±     0.002)s|     0.130~     0.138|
|/single-thread/f/sleep|     11.30%|     24.05%|      10|     0.323s|     0.032(±     0.002)s|     0.030~     0.035|

|path               |%total     |%parent    |count   |total      |mean(±std)              |min-max              |
|/auto-print        |      4.63%|      4.63%|       1|     0.139s|     0.139(±     0.000)s|     0.139~     0.139|
|/auto-print/f      |      4.63%|     99.97%|       1|     0.139s|     0.139(±     0.000)s|     0.139~     0.139|
|/auto-print/f/sleep|      1.17%|     25.37%|       1|     0.035s|     0.035(±     0.000)s|     0.035~     0.035|

|path               |%total     |%parent    |count   |total      |mean(±std)              |min-max              |
|/auto-print        |      8.71%|      8.71%|       2|     0.273s|     0.137(±     0.002)s|     0.134~     0.139|
|/auto-print/f      |      8.71%|     99.97%|       2|     0.273s|     0.136(±     0.002)s|     0.134~     0.139|
|/auto-print/f/sleep|      2.09%|     23.99%|       2|     0.065s|     0.033(±     0.002)s|     0.030~     0.035|

|path               |%total     |%parent    |count   |total      |mean(±std)              |min-max              |
|/auto-print        |      4.25%|      4.25%|       1|     0.139s|     0.139(±     0.000)s|     0.139~     0.139|
|/auto-print/f      |      4.24%|     99.98%|       1|     0.139s|     0.139(±     0.000)s|     0.139~     0.139|
|/auto-print/f/sleep|      1.06%|     24.90%|       1|     0.035s|     0.035(±     0.000)s|     0.035~     0.035|OverheadThe average overhead is less than 0.1ms.importtimefrompyprofimportprofile,Profilerreal_time=0.@profiledeff():tic=time.perf_counter()time.sleep(1e-2)globalreal_timereal_time+=time.perf_counter()-ticdeftest_overhead():n_times=100foriinrange(n_times):f()total_time=Profiler.get("/f").totalprint(f'total={total_time:.4f}s real_time={real_time:.4f}s')average_overhead=(total_time-real_time)/n_timesassertaverage_overhead<1e-4# 0.1msprint(f'average overhead={average_overhead*1000:.4f}ms')RoadmapAutomatically decide column width for more columns inreportSupport capture parent profiler in a multi-thread contextSupport multi-process (currently Profilers in subprocesses are all detached)