Skip to content

Commit 4dfd4e1

Browse files
committed
tp: add Python API for ExportToArrow
Adds export_to_arrow() to the Python TraceProcessor API which streams the TAR archive of Arrow IPC files to an output path.
1 parent f8ab2d4 commit 4dfd4e1

File tree

3 files changed

+48
-0
lines changed

3 files changed

+48
-0
lines changed

python/perfetto/trace_processor/api.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,17 @@ def metric(self, metrics: List[str]):
272272
metrics.ParseFromString(response.metrics)
273273
return metrics
274274

275+
def export_to_arrow(self, output_path: str):
276+
"""Export all intrinsic tables as a TAR archive of Arrow IPC files.
277+
278+
The archive is streamed directly to disk without materializing in memory.
279+
280+
Args:
281+
output_path: Path to write the TAR archive to.
282+
"""
283+
with open(output_path, 'wb') as f:
284+
self.http.export_to_arrow(f)
285+
275286
@property
276287
def metadata(self) -> Dict[str, str]:
277288
"""Returns metadata associated with this trace.

python/perfetto/trace_processor/http.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,13 @@ def disable_and_read_metatrace(self):
106106
result = self.protos.DisableAndReadMetatraceResult()
107107
result.ParseFromString(f.read())
108108
return result
109+
110+
def export_to_arrow(self, output_file):
111+
"""Streams the arrow TAR archive directly to an open file object."""
112+
self.conn.request('POST', '/export_to_arrow')
113+
with self.conn.getresponse() as f:
114+
while True:
115+
chunk = f.read(65536)
116+
if not chunk:
117+
break
118+
output_file.write(chunk)

python/test/api_integrationtest.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,3 +646,30 @@ def resolve(self):
646646
'_path': example_android_trace_path()
647647
}
648648
self.assertEqual(tp.metadata, expected_metadata)
649+
650+
def test_export_to_arrow(self):
651+
import tarfile
652+
with create_tp(trace=example_android_trace_path()) as tp:
653+
with tempfile.NamedTemporaryFile(suffix='.tar', delete=False) as f:
654+
output_path = f.name
655+
try:
656+
tp.export_to_arrow(output_path)
657+
658+
# Verify the output is a valid TAR archive.
659+
self.assertTrue(tarfile.is_tarfile(output_path))
660+
661+
with tarfile.open(output_path) as tf:
662+
names = tf.getnames()
663+
# Should contain metadata.json and at least one .arrow file.
664+
self.assertIn('metadata.json', names)
665+
arrow_files = [n for n in names if n.endswith('.arrow')]
666+
self.assertGreater(len(arrow_files), 0)
667+
668+
# Verify arrow files have ARROW1 magic bytes.
669+
for name in arrow_files:
670+
member = tf.extractfile(name)
671+
self.assertIsNotNone(member)
672+
data = member.read()
673+
self.assertTrue(data[:6] == b'ARROW1', f'{name} missing ARROW1 header')
674+
finally:
675+
os.unlink(output_path)

0 commit comments

Comments
 (0)