Repository navigation
gh-138122: Allow tachyon to write and read binary output #142730
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
7dd836b
Add binary I/O header for sampling profiler
pablogsal 83603c7
Add binary writer for sampling profiler
pablogsal 7a58811
Add binary reader for sampling profiler
pablogsal e3ea7a4
Build: add binary I/O files to Unix build
pablogsal 8931b4a
Build: add binary I/O files to Windows build
pablogsal 18287f4
Add Python bindings for binary writer and reader
pablogsal 1f7737e
Add BinaryCollector for sampling profiler
pablogsal 2965eff
Add BinaryReader for sampling profiler replay
pablogsal 427f846
Add --binary and replay command to sampling profiler CLI
pablogsal 1437629
Update collector interface for binary replay support
pablogsal e75513b
Add tests for binary format
pablogsal a520ac1
Add internal documentation for binary format
pablogsal 3ad7a3d
Document binary format and replay command
pablogsal cd4f412
Fix CI
pablogsal 596af7f
Add NEWS entry
pablogsal 1e2400b
Regen and simplify
pablogsal b90e37c
Merge upstream/main into file-output
pablogsal 788c565
Speed up general case
pablogsal 51b3b09
Small fixes
pablogsal 81a8f2d
Merge branch 'main' into file-output
pablogsal 0ccea49
Address Laszlo's review
pablogsal dfc0d31
More fixes from review
pablogsal b9fc778
Fixes and more tests
pablogsal 191458a
Fix c analizer
pablogsal 63c6f50
Update docs
pablogsal 046fe55
Update cli
pablogsal f88c01f
Fixes
pablogsal ed63156
Merge upstream/main
pablogsal c880f85
Fix big endian
pablogsal ad7891c
Fix big endian
pablogsal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add BinaryCollector for sampling profiler
Thin wrapper around the C BinaryWriter. Implements the Collector interface so it can be used interchangeably with other collectors like FlamegraphCollector or GeckoCollector. Compression is configurable: 'auto' uses zstd when available, 'zstd' requires it, 'none' disables compression. The collector passes samples directly to C for encoding without building Python data structures.
- Loading branch information
commit 1f7737e6f009d9b8cb10031866d46772ee0b7a26
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| """Thin Python wrapper around C binary writer for profiling data.""" | ||
|
|
||
| import time | ||
|
|
||
| from .collector import Collector | ||
|
|
||
| # Compression type constants (must match binary_io.h) | ||
| COMPRESSION_NONE = 0 | ||
| COMPRESSION_ZSTD = 1 | ||
|
|
||
|
|
||
| def _resolve_compression(compression): | ||
| """Resolve compression type from string or int. | ||
|
|
||
| Args: | ||
| compression: 'auto', 'zstd', 'none', or int (0/1) | ||
|
|
||
| Returns: | ||
| int: Compression type constant | ||
| """ | ||
| if isinstance(compression, int): | ||
| return compression | ||
|
|
||
| compression = compression.lower() | ||
| if compression == 'none': | ||
| return COMPRESSION_NONE | ||
| elif compression == 'zstd': | ||
| return COMPRESSION_ZSTD | ||
| elif compression == 'auto': | ||
| # Auto: use zstd if available, otherwise none | ||
| import _remote_debugging | ||
| if _remote_debugging.zstd_available(): | ||
| return COMPRESSION_ZSTD | ||
| return COMPRESSION_NONE | ||
| else: | ||
| raise ValueError(f"Unknown compression type: {compression}") | ||
|
|
||
|
|
||
| class BinaryCollector(Collector): | ||
| """High-performance binary collector using C implementation. | ||
|
|
||
| This collector writes profiling data directly to a binary file format | ||
| with optional zstd compression. All I/O is performed in C for maximum | ||
| throughput. | ||
|
|
||
| The binary format uses string/frame deduplication and varint encoding | ||
| for efficient storage. | ||
| """ | ||
|
|
||
| def __init__(self, filename, sample_interval_usec, *, skip_idle=False, | ||
| compression='auto'): | ||
| """Create a new binary collector. | ||
|
|
||
| Args: | ||
| filename: Path to output binary file | ||
| sample_interval_usec: Sampling interval in microseconds | ||
| skip_idle: If True, skip idle threads (not used in binary format) | ||
| compression: 'auto', 'zstd', 'none', or int (0=none, 1=zstd) | ||
| """ | ||
| import _remote_debugging | ||
|
pablogsal marked this conversation as resolved.
Outdated
|
||
|
|
||
| self.filename = filename | ||
| self.sample_interval_usec = sample_interval_usec | ||
| self.skip_idle = skip_idle | ||
|
|
||
| compression_type = _resolve_compression(compression) | ||
| start_time_us = int(time.monotonic() * 1_000_000) | ||
| self._writer = _remote_debugging.BinaryWriter( | ||
| filename, sample_interval_usec, start_time_us, compression=compression_type | ||
| ) | ||
|
|
||
| def collect(self, stack_frames, timestamp_us=None): | ||
| """Collect profiling data from stack frames. | ||
|
|
||
| This passes stack_frames directly to the C writer which handles | ||
| all encoding and buffering. | ||
|
|
||
| Args: | ||
| stack_frames: List of InterpreterInfo objects from _remote_debugging | ||
| timestamp_us: Optional timestamp in microseconds. If not provided, | ||
| uses time.monotonic() to generate one. | ||
| """ | ||
| if timestamp_us is None: | ||
| timestamp_us = int(time.monotonic() * 1_000_000) | ||
| self._writer.write_sample(stack_frames, timestamp_us) | ||
|
|
||
| def collect_failed_sample(self): | ||
| """Record a failed sample attempt (no-op for binary format).""" | ||
| pass | ||
|
|
||
| def export(self, filename=None): | ||
| """Finalize and close the binary file. | ||
|
|
||
| Args: | ||
| filename: Ignored (binary files are written incrementally) | ||
| """ | ||
| self._writer.finalize() | ||
|
|
||
| @property | ||
| def total_samples(self): | ||
| """Total number of samples written.""" | ||
| return self._writer.total_samples | ||
|
|
||
| def get_stats(self): | ||
| """Get encoding statistics. | ||
|
|
||
| Returns: | ||
| Dict with encoding statistics including repeat/full/suffix/pop-push | ||
| record counts, frames written/saved, and compression ratio. | ||
| """ | ||
| return self._writer.get_stats() | ||
|
|
||
| def __enter__(self): | ||
| """Context manager entry.""" | ||
| return self | ||
|
|
||
| def __exit__(self, exc_type, exc_val, exc_tb): | ||
| """Context manager exit - finalize unless there was an error.""" | ||
| if exc_type is None: | ||
| self._writer.finalize() | ||
| else: | ||
| self._writer.close() | ||
| return False | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.