77class PstatsCollector (Collector ):
88 def __init__ (self , sample_interval_usec ):
99 self .result = collections .defaultdict (
10- lambda : dict (total_calls = 0 , total_rec_calls = 0 , inline_calls = 0 )
10+ lambda : dict (total_rec_calls = 0 , direct_calls = 0 , cumulative_calls = 0 )
1111 )
1212 self .stats = {}
1313 self .sample_interval_usec = sample_interval_usec
@@ -20,16 +20,22 @@ def collect(self, stack_frames):
2020 if not frames :
2121 continue
2222
23+ # Process each frame in the stack to track cumulative calls
24+ for frame in frames :
25+ location = (frame .filename , frame .lineno , frame .funcname )
26+ self .result [location ]["cumulative_calls" ] += 1
27+
28+ # The top frame gets counted as an inline call (directly executing)
2329 top_frame = frames [0 ]
2430 top_location = (
2531 top_frame .filename ,
2632 top_frame .lineno ,
2733 top_frame .funcname ,
2834 )
2935
30- self .result [top_location ]["inline_calls" ] += 1
31- self .result [top_location ]["total_calls" ] += 1
36+ self .result [top_location ]["direct_calls" ] += 1
3237
38+ # Track caller-callee relationships for call graph
3339 for i in range (1 , len (frames )):
3440 callee_frame = frames [i - 1 ]
3541 caller_frame = frames [i ]
@@ -47,13 +53,6 @@ def collect(self, stack_frames):
4753
4854 self .callers [callee ][caller ] += 1
4955
50- if len (frames ) <= 1 :
51- continue
52-
53- for frame in frames [1 :]:
54- location = (frame .filename , frame .lineno , frame .funcname )
55- self .result [location ]["total_calls" ] += 1
56-
5756 def export (self , filename ):
5857 self .create_stats ()
5958 self ._dump_stats (filename )
@@ -69,14 +68,13 @@ def create_stats(self):
6968 sample_interval_sec = self .sample_interval_usec / 1_000_000
7069 callers = {}
7170 for fname , call_counts in self .result .items ():
72- total = call_counts ["inline_calls" ] * sample_interval_sec
73- cumulative = call_counts ["total_calls" ] * sample_interval_sec
71+ total = call_counts ["direct_calls" ] * sample_interval_sec
72+ cumulative_calls = call_counts ["cumulative_calls" ]
73+ cumulative = cumulative_calls * sample_interval_sec
7474 callers = dict (self .callers .get (fname , {}))
7575 self .stats [fname ] = (
76- call_counts ["total_calls" ],
77- call_counts ["total_rec_calls" ]
78- if call_counts ["total_rec_calls" ]
79- else call_counts ["total_calls" ],
76+ call_counts ["direct_calls" ], # cc = direct calls for sample percentage
77+ cumulative_calls , # nc = cumulative calls for cumulative percentage
8078 total ,
8179 cumulative ,
8280 callers ,
0 commit comments