Print unwinder statistics including cache performance.
(self)
| 235 | ) |
| 236 | |
| 237 | def _print_unwinder_stats(self): |
| 238 | """Print unwinder statistics including cache performance.""" |
| 239 | try: |
| 240 | stats = self.unwinder.get_stats() |
| 241 | except RuntimeError: |
| 242 | return # Stats not enabled |
| 243 | |
| 244 | print(f"\n{ANSIColors.BOLD_BLUE}{'='*50}{ANSIColors.RESET}") |
| 245 | print(f"{ANSIColors.BOLD_BLUE}Unwinder Statistics:{ANSIColors.RESET}") |
| 246 | |
| 247 | # Frame cache stats |
| 248 | total_samples = stats.get('total_samples', 0) |
| 249 | frame_cache_hits = stats.get('frame_cache_hits', 0) |
| 250 | frame_cache_partial_hits = stats.get('frame_cache_partial_hits', 0) |
| 251 | frame_cache_misses = stats.get('frame_cache_misses', 0) |
| 252 | total_lookups = frame_cache_hits + frame_cache_partial_hits + frame_cache_misses |
| 253 | |
| 254 | # Calculate percentages |
| 255 | hits_pct = (frame_cache_hits / total_lookups * 100) if total_lookups > 0 else 0 |
| 256 | partial_pct = (frame_cache_partial_hits / total_lookups * 100) if total_lookups > 0 else 0 |
| 257 | misses_pct = (frame_cache_misses / total_lookups * 100) if total_lookups > 0 else 0 |
| 258 | |
| 259 | print(f" {ANSIColors.CYAN}Frame Cache:{ANSIColors.RESET}") |
| 260 | print(f" Total samples: {total_samples:n}") |
| 261 | print(f" Full hits: {frame_cache_hits:n} ({ANSIColors.GREEN}{fmt(hits_pct)}%{ANSIColors.RESET})") |
| 262 | print(f" Partial hits: {frame_cache_partial_hits:n} ({ANSIColors.YELLOW}{fmt(partial_pct)}%{ANSIColors.RESET})") |
| 263 | print(f" Misses: {frame_cache_misses:n} ({ANSIColors.RED}{fmt(misses_pct)}%{ANSIColors.RESET})") |
| 264 | |
| 265 | # Frame read stats |
| 266 | frames_from_cache = stats.get('frames_read_from_cache', 0) |
| 267 | frames_from_memory = stats.get('frames_read_from_memory', 0) |
| 268 | total_frames = frames_from_cache + frames_from_memory |
| 269 | cache_frame_pct = (frames_from_cache / total_frames * 100) if total_frames > 0 else 0 |
| 270 | memory_frame_pct = (frames_from_memory / total_frames * 100) if total_frames > 0 else 0 |
| 271 | |
| 272 | print(f" {ANSIColors.CYAN}Frame Reads:{ANSIColors.RESET}") |
| 273 | print(f" From cache: {frames_from_cache:n} ({ANSIColors.GREEN}{fmt(cache_frame_pct)}%{ANSIColors.RESET})") |
| 274 | print(f" From memory: {frames_from_memory:n} ({ANSIColors.RED}{fmt(memory_frame_pct)}%{ANSIColors.RESET})") |
| 275 | |
| 276 | # Code object cache stats |
| 277 | code_hits = stats.get('code_object_cache_hits', 0) |
| 278 | code_misses = stats.get('code_object_cache_misses', 0) |
| 279 | total_code = code_hits + code_misses |
| 280 | code_hits_pct = (code_hits / total_code * 100) if total_code > 0 else 0 |
| 281 | code_misses_pct = (code_misses / total_code * 100) if total_code > 0 else 0 |
| 282 | |
| 283 | print(f" {ANSIColors.CYAN}Code Object Cache:{ANSIColors.RESET}") |
| 284 | print(f" Hits: {code_hits:n} ({ANSIColors.GREEN}{fmt(code_hits_pct)}%{ANSIColors.RESET})") |
| 285 | print(f" Misses: {code_misses:n} ({ANSIColors.RED}{fmt(code_misses_pct)}%{ANSIColors.RESET})") |
| 286 | |
| 287 | # Memory operations |
| 288 | memory_reads = stats.get('memory_reads', 0) |
| 289 | memory_bytes = stats.get('memory_bytes_read', 0) |
| 290 | if memory_bytes >= 1024 * 1024: |
| 291 | memory_str = f"{fmt(memory_bytes / (1024 * 1024))} MB" |
| 292 | elif memory_bytes >= 1024: |
| 293 | memory_str = f"{fmt(memory_bytes / 1024)} KB" |
| 294 | else: |