Skip to content

Commit 76f0126

Browse files
fixup! Store Tachyon samples in bounded columnar blocks
Constant stream ID and timestamp residual columns normally contain the same one-byte varint for every sample. The reader expanded that byte into a per-sample buffer and then decoded the same value repeatedly. Use the stored byte directly for these columns and exclude it from the shared block buffer. Other constant columns continue through the general expansion path.
1 parent 0c3614a commit 76f0126

2 files changed

Lines changed: 79 additions & 18 deletions

File tree

‎Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,23 @@ def test_replay_decodes_every_frame_id_width(self):
18961896
self.assertEqual([frame["filename"] for frame in frames],
18971897
[f"{frame_id}.py"])
18981898

1899+
def test_replay_reads_constant_stream_and_residual_columns(self):
1900+
"""Constant stream index and residual columns decode every sample."""
1901+
# Every sample is in stream 0 and one microsecond late (zigzag 2).
1902+
filename = self._write_single_block(
1903+
3, b"\x01\x00\x00\x00\x02", residuals=b"\x02" * 3,
1904+
descriptors={self.COLUMN_STREAM_IDS: (self.COLUMN_CONSTANT, 3),
1905+
self.COLUMN_TIMESTAMP_RESIDUALS:
1906+
(self.COLUMN_CONSTANT, 3)})
1907+
collector = mock.Mock()
1908+
with BinaryReader(filename) as reader:
1909+
interval = reader.get_info()["sample_interval_us"]
1910+
self.assertEqual(reader.replay_samples(collector), 3)
1911+
timestamps = [ts for call in collector.collect.call_args_list
1912+
for ts in call.args[1]]
1913+
self.assertEqual(timestamps,
1914+
[2 + i * (interval + 1) for i in range(3)])
1915+
18991916
def test_replay_rejects_reentrant_replay(self):
19001917
"""Replaying from inside the same reader's collector raises."""
19011918
filename = self._write_single_block(
@@ -1949,6 +1966,10 @@ def test_replay_rejects_invalid_block(self):
19491966
("stream table repeats a thread",
19501967
dict(stream_table=struct.pack("=QI", 1, 0) * 2)),
19511968
("sample refers to an unknown stream", dict(stream_ids=b"\x01")),
1969+
("sample refers to an unknown stream",
1970+
dict(num_samples=2, stream_ids=b"\x01",
1971+
descriptors={self.COLUMN_STREAM_IDS:
1972+
(self.COLUMN_CONSTANT, 2)})),
19521973
("stream index column has trailing data",
19531974
dict(num_samples=2, header_samples=1)),
19541975
("timestamp column has trailing data",

‎Modules/_remote_debugging/binary_io_reader.c‎

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,17 +1028,41 @@ reader_parse_block_header(BinaryReader *reader, const ByteBuffer *section,
10281028
return 0;
10291029
}
10301030

1031+
/* A constant stream index or residual column that holds the same one-byte
1032+
* varint for every sample is read from its stored byte, not expanded. */
1033+
static int
1034+
constant_varint_column(const DecodedBlock *block, unsigned column,
1035+
uint8_t value)
1036+
{
1037+
const ColumnDescriptor *descriptor = &block->header.columns[column];
1038+
return (column == COLUMN_SAMPLE_STREAM_IDS ||
1039+
column == COLUMN_TIMESTAMP_RESIDUALS) &&
1040+
descriptor->encoding == COLUMN_CONSTANT &&
1041+
descriptor->decoded_size == block->header.sample_count &&
1042+
value < 0x80;
1043+
}
1044+
10311045
static int
10321046
decode_block_columns(BinaryReader *reader, const ByteBuffer *section,
10331047
size_t *offset, DecodedBlock *block)
10341048
{
10351049
const ColumnDescriptor *descriptors = block->header.columns;
1036-
/* Constant and zstd columns share one buffer, reused across blocks.
1037-
* It is reserved up front so decoded columns never move. */
1050+
/* Find where each column is stored and how much of the shared buffer
1051+
* the expanded and decompressed columns need. The buffer is reused
1052+
* across blocks and reserved up front so decoded columns never move. */
1053+
uint8_t *stored[COLUMN_COUNT];
10381054
size_t buffered_total = 0;
10391055
for (unsigned column = 0; column < COLUMN_COUNT; column++) {
1040-
if (descriptors[column].encoding != COMPRESSION_NONE) {
1041-
buffered_total += descriptors[column].decoded_size;
1056+
const ColumnDescriptor *descriptor = &descriptors[column];
1057+
if (descriptor->stored_size > section->size - *offset) {
1058+
return block_error("column extends past the sample section");
1059+
}
1060+
stored[column] = section->data + *offset;
1061+
*offset += descriptor->stored_size;
1062+
if (descriptor->encoding == COMPRESSION_ZSTD ||
1063+
(descriptor->encoding == COLUMN_CONSTANT &&
1064+
!constant_varint_column(block, column, stored[column][0]))) {
1065+
buffered_total += descriptor->decoded_size;
10421066
}
10431067
}
10441068
ByteBuffer *buffer = &reader->block_data;
@@ -1049,10 +1073,7 @@ decode_block_columns(BinaryReader *reader, const ByteBuffer *section,
10491073
buffer->size = 0;
10501074
for (unsigned column = 0; column < COLUMN_COUNT; column++) {
10511075
const ColumnDescriptor *descriptor = &descriptors[column];
1052-
if (descriptor->stored_size > section->size - *offset) {
1053-
return block_error("column extends past the sample section");
1054-
}
1055-
uint8_t *stored_data = section->data + *offset;
1076+
uint8_t *stored_data = stored[column];
10561077
ByteBuffer *decoded = &block->columns[column];
10571078
decoded->size = descriptor->decoded_size;
10581079
switch (descriptor->encoding) {
@@ -1061,6 +1082,11 @@ decode_block_columns(BinaryReader *reader, const ByteBuffer *section,
10611082
decoded->data = stored_data;
10621083
break;
10631084
case COLUMN_CONSTANT:
1085+
if (constant_varint_column(block, column, stored_data[0])) {
1086+
decoded->data = stored_data;
1087+
decoded->size = 1;
1088+
break;
1089+
}
10641090
decoded->data = buffer->data + buffer->size;
10651091
memset(decoded->data, stored_data[0], decoded->size);
10661092
buffer->size += decoded->size;
@@ -1076,7 +1102,6 @@ decode_block_columns(BinaryReader *reader, const ByteBuffer *section,
10761102
default:
10771103
return block_error("unknown column encoding");
10781104
}
1079-
*offset += descriptor->stored_size;
10801105
}
10811106
return 0;
10821107
}
@@ -1203,23 +1228,38 @@ decode_samples(BinaryReader *reader, DecodedBlock *block)
12031228
&block->columns[COLUMN_SAMPLE_STREAM_IDS];
12041229
const ByteBuffer *residual_column =
12051230
&block->columns[COLUMN_TIMESTAMP_RESIDUALS];
1231+
int constant_stream_ids = constant_varint_column(
1232+
block, COLUMN_SAMPLE_STREAM_IDS, stream_id_column->data[0]);
1233+
int constant_residuals = constant_varint_column(
1234+
block, COLUMN_TIMESTAMP_RESIDUALS, residual_column->data[0]);
12061235
size_t stream_id_offset = 0;
12071236
size_t residual_offset = 0;
1237+
int64_t constant_residual = 0;
1238+
if (constant_residuals) {
1239+
constant_residual = decode_varint_i64(residual_column->data,
1240+
&residual_offset, 1);
1241+
}
12081242
for (uint32_t sample = 0; sample < block->header.sample_count; sample++) {
12091243
uint64_t stream_id;
1210-
if (block_read_varint(stream_id_column, &stream_id_offset,
1211-
&stream_id) < 0) {
1244+
if (constant_stream_ids) {
1245+
stream_id = stream_id_column->data[0];
1246+
}
1247+
else if (block_read_varint(stream_id_column, &stream_id_offset,
1248+
&stream_id) < 0) {
12121249
return -1;
12131250
}
12141251
if (stream_id >= block->stream_count) {
12151252
return block_error("sample refers to an unknown stream");
12161253
}
1217-
size_t prev_offset = residual_offset;
1218-
int64_t residual = decode_varint_i64(residual_column->data,
1219-
&residual_offset,
1220-
residual_column->size);
1221-
if (residual_offset == prev_offset) {
1222-
return -1;
1254+
int64_t residual = constant_residual;
1255+
if (!constant_residuals) {
1256+
size_t prev_offset = residual_offset;
1257+
residual = decode_varint_i64(residual_column->data,
1258+
&residual_offset,
1259+
residual_column->size);
1260+
if (residual_offset == prev_offset) {
1261+
return -1;
1262+
}
12231263
}
12241264

12251265
/* Timestamp is the expected time plus the stored residual */
@@ -1230,7 +1270,7 @@ decode_samples(BinaryReader *reader, DecodedBlock *block)
12301270
stream_ids[sample] = (uint32_t)stream_id;
12311271
timestamps[sample] = stream->prev_timestamp;
12321272
}
1233-
if (stream_id_offset != stream_id_column->size) {
1273+
if (!constant_stream_ids && stream_id_offset != stream_id_column->size) {
12341274
return block_error("stream index column has trailing data");
12351275
}
12361276
if (residual_offset != residual_column->size) {

0 commit comments

Comments
 (0)