66logger = logging .getLogger (__name__ )
77
88
9- class Profile :
9+ class Context :
1010 """
1111 Class that holds the total execution time and call count of potentially multiple executions of the same label.
1212 Reports its contents as a single-line string.
1313
1414 TODO: Make profiles nestable by accumulating them at the context close.
1515 """
1616
17- def __init__ (self , label ):
17+ def __init__ (self , label : str , profiler : Profiler ):
18+ self .__profiler = profiler
19+
1820 self .__label = label
1921 self .__start_time = 0
20- self .__seconds = 0.0
21- self .__count = 0
2222
2323 def __enter__ (self ):
2424 self .__start_time = time .time ()
2525
2626 def __exit__ (self , exc_type , exc_val , exc_tb ):
27- self .__seconds = time .time () - self .__start_time
28- self .__count += 1
27+ self .__profiler .accumulate (
28+ self .__label ,
29+ time .time () - self .__start_time ,
30+ )
31+
32+
33+ class Profile :
34+ """
35+ Class that holds the total execution time and call count of potentially multiple executions of the same label.
36+ Reports its contents as a single-line string.
37+
38+ TODO: Make profiles nestable by accumulating them at the context close.
39+ """
40+
41+ def __init__ (self , label ):
42+ self .__label = label
43+ self .__seconds = 0.0
44+ self .__count = 0
2945
3046 def __str__ (self ):
3147 if self .__count == 0 :
@@ -47,23 +63,39 @@ class Profiler:
4763
4864 def __init__ (self ):
4965 self .__profiles = {}
66+ self .__lock = threading .RLock ()
5067
51- def profile (self , label : str ) -> Profile :
68+ def profile (self , label : str ) -> Context :
5269 """
53- Return the profile for the given label. Uses previously existing profile, if any, or makes a new instance .
70+ Return a context to hold the profile timing .
5471
5572 Args:
5673 label (str): label identifying the profile
5774
5875 Returns:
5976 Profile: a new profile object, or previously existing one
6077 """
61- profile = self .__profiles .get (label )
62- if profile is None :
63- profile = Profile (label )
64- self .__profiles [label ] = profile
78+ return Context (label , self )
79+
80+ def accumulate (self , label : str , seconds : float ) -> None :
81+ """
82+ Accumulate a report into the profile for the given label.
83+ Uses previously existing profile, if any, or makes a new instance.
84+
85+ Args:
86+ label (str): label identifying the profile
6587
66- return profile
88+ Returns:
89+ Profile: a new profile object, or previously existing one
90+ """
91+ with self .__lock :
92+ profile = self .__profiles .get (label )
93+ if profile is None :
94+ profile = Profile (label )
95+ self .__profiles [label ] = profile
96+
97+ profile .seconds += seconds
98+ profile .count += 1
6799
68100 def __str__ (self ) -> str :
69101 lines = []
0 commit comments