Skip to content

Commit 114c344

Browse files
committed
Add perfetto trace output
1 parent a285e72 commit 114c344

File tree

4 files changed

+148
-1
lines changed

4 files changed

+148
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@
1616
# output files
1717
profiling.db
1818
profiling.csv
19+
profiling.pftrace
1920
trace.json

preciceprofiling/common.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import sqlite3
88
import json
99
import pathlib
10+
import collections
1011

1112
from preciceprofiling.merge import warning, MERGED_FILE_VERSION
1213

@@ -119,6 +120,11 @@ def makeData(s):
119120
def participants(self):
120121
return [name for (name,) in self._cur.execute("SELECT name FROM participants")]
121122

123+
def ranks(self):
124+
return cur.execute(
125+
"SELECT DISTINCT participant, rank FROM full_events"
126+
).fetchall()
127+
122128
def events(self):
123129
return [name for (name,) in self._cur.execute("SELECT name FROM names")]
124130

@@ -155,3 +161,100 @@ def toExportDataFrame(self, unit):
155161
schema=schema,
156162
)
157163
return df
164+
165+
def toPFTrace(self):
166+
import uuid
167+
from perfetto.trace_builder.proto_builder import TraceProtoBuilder
168+
from perfetto.protos.perfetto.trace.perfetto_trace_pb2 import (
169+
TrackEvent,
170+
TrackDescriptor,
171+
TracePacket,
172+
)
173+
174+
Event = collections.namedtuple("Event", ["name", "ts", "dur", "data"])
175+
176+
def eventsFor(participant, rank):
177+
for e in self._cur.execute(
178+
"SELECT event, (ts - (SELECT min(ts) FROM events))*1000 as ts , dur*1000, data FROM full_events WHERE dur > 0 AND event <> '_GLOBAL' AND participant == ? AND rank == ? ORDER BY ts ASC",
179+
(participant, rank),
180+
):
181+
yield Event(*e)
182+
183+
TPS_ID = 2025
184+
185+
builder = TraceProtoBuilder()
186+
187+
participants = {
188+
p: uuid.uuid4().int & ((1 << 63) - 1) for p in self.participants()
189+
}
190+
191+
for p, u in participants.items():
192+
pkt = builder.add_packet()
193+
pkt.track_descriptor.uuid = u
194+
pkt.track_descriptor.name = p
195+
pkt.track_descriptor.child_ordering = TrackDescriptor.EXPLICIT
196+
pkt.trusted_packet_sequence_id = TPS_ID
197+
198+
ranks = [
199+
(p, r, i)
200+
for i, (p, r) in enumerate(
201+
self.ranks(),
202+
start=10,
203+
)
204+
]
205+
206+
for p, r, u in ranks:
207+
pkt = builder.add_packet()
208+
pkt.track_descriptor.uuid = u
209+
pkt.track_descriptor.name = f"Rank {r}"
210+
pkt.track_descriptor.parent_uuid = participants[p]
211+
pkt.track_descriptor.sibling_order_rank = r
212+
pkt.trusted_packet_sequence_id = TPS_ID
213+
pkt.sequence_flags = TracePacket.SEQ_INCREMENTAL_STATE_CLEARED
214+
215+
seen = {}
216+
217+
for p, r, u in ranks:
218+
active = []
219+
for e in eventsFor(p, r):
220+
221+
# end past events
222+
for a in active:
223+
if (a.ts + a.dur) <= e.ts:
224+
pkt = builder.add_packet()
225+
pkt.timestamp = a.ts + a.dur
226+
pkt.track_event.type = TrackEvent.TYPE_SLICE_END
227+
pkt.track_event.track_uuid = u
228+
pkt.trusted_packet_sequence_id = TPS_ID
229+
pkt.sequence_flags = TracePacket.SEQ_NEEDS_INCREMENTAL_STATE
230+
231+
# discard inactive
232+
active = [a for a in active if (a.ts + a.dur) > e.ts]
233+
active.append(e)
234+
235+
# add new event
236+
pkt = builder.add_packet()
237+
pkt.timestamp = e.ts
238+
pkt.track_event.type = TrackEvent.TYPE_SLICE_BEGIN
239+
pkt.track_event.track_uuid = u
240+
pkt.trusted_packet_sequence_id = TPS_ID
241+
name = e.name.rpartition("/")[-1]
242+
if name in seen:
243+
pkt.track_event.name_iid = seen[name]
244+
else:
245+
pkt.track_event.name = name
246+
entry = pkt.interned_data.event_names.add()
247+
entry.iid = seen[name] = len(seen) + 1
248+
entry.name = name
249+
pkt.sequence_flags = TracePacket.SEQ_NEEDS_INCREMENTAL_STATE
250+
251+
# end leftover events
252+
for a in active:
253+
pkt = builder.add_packet()
254+
pkt.timestamp = a.ts + a.dur
255+
pkt.track_event.type = TrackEvent.TYPE_SLICE_END
256+
pkt.track_event.track_uuid = u
257+
pkt.trusted_packet_sequence_id = TPS_ID
258+
pkt.sequence_flags = TracePacket.SEQ_NEEDS_INCREMENTAL_STATE
259+
260+
return builder.serialize()

preciceprofiling/pftrace.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from preciceprofiling.common import Run
2+
import argparse
3+
import sys
4+
import pathlib
5+
from preciceprofiling.parsers import addInputArgument
6+
7+
8+
def makePFTraceParser(add_help: bool = True):
9+
trace_help = "Transform profiling to the perfetto trace."
10+
trace = argparse.ArgumentParser(description=trace_help, add_help=add_help)
11+
addInputArgument(trace)
12+
trace.add_argument(
13+
"-o",
14+
"--output",
15+
default="profiling.pftrace",
16+
type=pathlib.Path,
17+
help="The resulting perfetto trace file",
18+
)
19+
return trace
20+
21+
22+
def runPFTrace(ns):
23+
return pftraceCommand(ns.profilingfile, ns.output)
24+
25+
26+
def pftraceCommand(profilingfile, outfile):
27+
run = Run(profilingfile)
28+
print(f"Building perfetto trace")
29+
trace = run.toPFTrace()
30+
print(f"Writing to {outfile}")
31+
outfile.write_bytes(trace)
32+
return 0
33+
34+
35+
def main():
36+
parser = makePFTraceParser()
37+
ns = parser.parse_args()
38+
return runPFTrace(ns)
39+
40+
41+
if __name__ == "__main__":
42+
sys.exit(main())

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
66
name="precice-profiling"
77
dynamic = [ "version" ]
88
dependencies = [
9-
"typing_extensions", "orjson >= 3", "polars >= 0.19.0", "matplotlib"
9+
"typing_extensions", "orjson >= 3", "polars >= 0.19.0", "matplotlib", "perfetto"
1010
]
1111
requires-python = ">=3.10"
1212
authors = [
@@ -40,6 +40,7 @@ precice-profiling-analyze = "preciceprofiling.analyze:main"
4040
precice-profiling-trace = "preciceprofiling.trace:main"
4141
precice-profiling-export = "preciceprofiling.export:main"
4242
precice-profiling-histogram = "preciceprofiling.histogram:main"
43+
precice-profiling-pftrace = "preciceprofiling.pftrace:main"
4344

4445
[tool.setuptools]
4546
packages=["preciceprofiling"]

0 commit comments

Comments
 (0)