|
12 | 12 | from .stack_collector import CollapsedStackCollector, FlamegraphCollector |
13 | 13 | from .heatmap_collector import HeatmapCollector |
14 | 14 | from .gecko_collector import GeckoCollector |
| 15 | +from .binary_collector import BinaryCollector |
15 | 16 | from .constants import ( |
16 | 17 | PROFILING_MODE_WALL, |
17 | 18 | PROFILING_MODE_CPU, |
@@ -137,6 +138,10 @@ def sample(self, collector, duration_sec=10, *, async_aware=False): |
137 | 138 | if self.collect_stats: |
138 | 139 | self._print_unwinder_stats() |
139 | 140 |
|
| 141 | + # Print binary I/O stats if using binary collector |
| 142 | + if isinstance(collector, BinaryCollector): |
| 143 | + self._print_binary_stats(collector) |
| 144 | + |
140 | 145 | # Pass stats to flamegraph collector if it's the right type |
141 | 146 | if hasattr(collector, 'set_stats'): |
142 | 147 | collector.set_stats(self.sample_interval_usec, running_time, sample_rate, error_rate, missed_samples, mode=self.mode) |
@@ -278,6 +283,56 @@ def _print_unwinder_stats(self): |
278 | 283 | if stale_invalidations > 0: |
279 | 284 | print(f" {ANSIColors.YELLOW}Stale cache invalidations: {stale_invalidations}{ANSIColors.RESET}") |
280 | 285 |
|
| 286 | + def _print_binary_stats(self, collector): |
| 287 | + """Print binary I/O encoding statistics.""" |
| 288 | + try: |
| 289 | + stats = collector.get_stats() |
| 290 | + except (ValueError, RuntimeError): |
| 291 | + return # Collector closed or stats unavailable |
| 292 | + |
| 293 | + print(f" {ANSIColors.CYAN}Binary Encoding:{ANSIColors.RESET}") |
| 294 | + |
| 295 | + # Record type counts |
| 296 | + repeat_records = stats.get('repeat_records', 0) |
| 297 | + repeat_samples = stats.get('repeat_samples', 0) |
| 298 | + full_records = stats.get('full_records', 0) |
| 299 | + suffix_records = stats.get('suffix_records', 0) |
| 300 | + pop_push_records = stats.get('pop_push_records', 0) |
| 301 | + total_records = stats.get('total_records', 0) |
| 302 | + |
| 303 | + if total_records > 0: |
| 304 | + repeat_pct = repeat_records / total_records * 100 |
| 305 | + full_pct = full_records / total_records * 100 |
| 306 | + suffix_pct = suffix_records / total_records * 100 |
| 307 | + pop_push_pct = pop_push_records / total_records * 100 |
| 308 | + else: |
| 309 | + repeat_pct = full_pct = suffix_pct = pop_push_pct = 0 |
| 310 | + |
| 311 | + print(f" Records: {total_records:,}") |
| 312 | + print(f" RLE repeat: {repeat_records:,} ({ANSIColors.GREEN}{repeat_pct:.1f}%{ANSIColors.RESET}) [{repeat_samples:,} samples]") |
| 313 | + print(f" Full stack: {full_records:,} ({full_pct:.1f}%)") |
| 314 | + print(f" Suffix match: {suffix_records:,} ({suffix_pct:.1f}%)") |
| 315 | + print(f" Pop-push: {pop_push_records:,} ({pop_push_pct:.1f}%)") |
| 316 | + |
| 317 | + # Frame efficiency |
| 318 | + frames_written = stats.get('total_frames_written', 0) |
| 319 | + frames_saved = stats.get('frames_saved', 0) |
| 320 | + compression_pct = stats.get('frame_compression_pct', 0) |
| 321 | + |
| 322 | + print(f" {ANSIColors.CYAN}Frame Efficiency:{ANSIColors.RESET}") |
| 323 | + print(f" Frames written: {frames_written:,}") |
| 324 | + print(f" Frames saved: {frames_saved:,} ({ANSIColors.GREEN}{compression_pct:.1f}%{ANSIColors.RESET})") |
| 325 | + |
| 326 | + # Bytes written |
| 327 | + bytes_written = stats.get('bytes_written', 0) |
| 328 | + if bytes_written >= 1024 * 1024: |
| 329 | + bytes_str = f"{bytes_written / (1024 * 1024):.1f} MB" |
| 330 | + elif bytes_written >= 1024: |
| 331 | + bytes_str = f"{bytes_written / 1024:.1f} KB" |
| 332 | + else: |
| 333 | + bytes_str = f"{bytes_written} B" |
| 334 | + print(f" Bytes (pre-zstd): {bytes_str}") |
| 335 | + |
281 | 336 |
|
282 | 337 | def sample( |
283 | 338 | pid, |
|
0 commit comments