| import collections |
| import os |
| |
| from .collector import Collector |
| |
| |
| class StackTraceCollector(Collector): |
| def __init__(self): |
| self.call_trees = [] |
| self.function_samples = collections.defaultdict(int) |
| |
| def collect(self, stack_frames): |
| for thread_id, frames in stack_frames: |
| if frames: |
| # Store the complete call stack (reverse order - root first) |
| call_tree = list(reversed(frames)) |
| self.call_trees.append(call_tree) |
| |
| # Count samples per function |
| for frame in frames: |
| self.function_samples[frame] += 1 |
| |
| |
| class CollapsedStackCollector(StackTraceCollector): |
| def export(self, filename): |
| stack_counter = collections.Counter() |
| for call_tree in self.call_trees: |
| # Call tree is already in root->leaf order |
| stack_str = ";".join( |
| f"{os.path.basename(f[0])}:{f[2]}:{f[1]}" for f in call_tree |
| ) |
| stack_counter[stack_str] += 1 |
| |
| with open(filename, "w") as f: |
| for stack, count in stack_counter.items(): |
| f.write(f"{stack} {count}\n") |
| print(f"Collapsed stack output written to {filename}") |