Skip to content

Commit 4b661cf

Browse files
committed
trace_processor: Parse adreno_cmdbatch_retired/submitted events
Add custom parsing for kgsl adreno_cmdbatch_retired and adreno_cmdbatch_submitted ftrace events to produce GPU timeline slices in the trace processor.
1 parent 82980e3 commit 4b661cf

File tree

7 files changed

+237
-3
lines changed

7 files changed

+237
-3
lines changed

src/trace_processor/importers/ftrace/ftrace_parser.cc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@ FtraceParser::FtraceParser(TraceProcessorContext* context,
541541
gpu_power_state_off_id_(context->storage->InternString("OFF")),
542542
gpu_power_state_pg_id_(context->storage->InternString("PG")),
543543
gpu_power_state_on_id_(context->storage->InternString("ON")),
544+
gpu_cmdbatch_slice_name_id_(context->storage->InternString("GPU")),
544545
ddic_underrun_id_(context_->storage->InternString("ddic_underrun")),
545546
memcg_reclaim_order_id_(
546547
context->storage->InternString("memcg_reclaim_order")),
@@ -925,6 +926,10 @@ base::Status FtraceParser::ParseFtraceEvent(uint32_t cpu,
925926
ParseKgslGpuFreq(ts, fld_bytes);
926927
break;
927928
}
929+
case FtraceEvent::kKgslAdrenoCmdbatchRetiredFieldNumber: {
930+
ParseKgslAdrenoCmdbatchRetired(ts, fld_bytes);
931+
break;
932+
}
928933
case FtraceEvent::kCpuIdleFieldNumber: {
929934
ParseCpuIdle(ts, fld_bytes);
930935
break;
@@ -1920,6 +1925,37 @@ void FtraceParser::ParseKgslGpuFreq(int64_t timestamp, ConstBytes blob) {
19201925
context_->event_tracker->PushCounter(timestamp, new_freq, track);
19211926
}
19221927

1928+
void FtraceParser::ParseKgslAdrenoCmdbatchRetired(int64_t timestamp,
1929+
protozero::ConstBytes data) {
1930+
protos::pbzero::KgslAdrenoCmdbatchRetiredFtraceEvent::Decoder evt(data);
1931+
1932+
static constexpr auto kBlueprint = TrackCompressor::SliceBlueprint(
1933+
"adreno_gpu_cmdbatch",
1934+
tracks::DimensionBlueprints(tracks::UintDimensionBlueprint("context_id"),
1935+
tracks::UintDimensionBlueprint("prio")),
1936+
tracks::FnNameBlueprint([](uint32_t context_id, uint32_t prio) {
1937+
return base::StackString<64>("Adreno GPU Cmdbatch (Ctx=%u, Prio=%u)",
1938+
context_id, prio);
1939+
}));
1940+
1941+
if (evt.retire() < evt.start()) {
1942+
return;
1943+
}
1944+
// Adreno GPU ticks run at 19.2 MHz, fixed across all Qualcomm mobile SoCs
1945+
// (see KGSL_XO_CLK_FREQ in kgsl_pwrctrl.h).
1946+
constexpr int64_t kAdrenoGpuTicksPerUs = 19200;
1947+
const int64_t duration = static_cast<int64_t>((evt.retire() - evt.start()) *
1948+
1000000 / kAdrenoGpuTicksPerUs);
1949+
1950+
const uint32_t context_id = evt.id();
1951+
TrackId track_id = context_->track_compressor->InternScoped(
1952+
kBlueprint,
1953+
tracks::Dimensions(context_id, static_cast<uint32_t>(evt.prio())),
1954+
timestamp, duration);
1955+
context_->slice_tracker->Scoped(timestamp, track_id, kNullStringId,
1956+
gpu_cmdbatch_slice_name_id_, duration);
1957+
}
1958+
19231959
void FtraceParser::ParseCpuIdle(int64_t timestamp, ConstBytes blob) {
19241960
protos::pbzero::CpuIdleFtraceEvent::Decoder idle(blob);
19251961
TrackId track = context_->track_tracker->InternTrack(

src/trace_processor/importers/ftrace/ftrace_parser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class FtraceParser {
9595
void ParseCpuFreqThrottle(int64_t timestamp, protozero::ConstBytes);
9696
void ParseGpuFreq(int64_t timestamp, protozero::ConstBytes);
9797
void ParseKgslGpuFreq(int64_t timestamp, protozero::ConstBytes);
98+
void ParseKgslAdrenoCmdbatchRetired(int64_t timestamp, protozero::ConstBytes);
9899
void ParseCpuIdle(int64_t timestamp, protozero::ConstBytes);
99100
void ParsePrint(int64_t timestamp, uint32_t pid, protozero::ConstBytes);
100101
void ParseZero(int64_t timestamp, uint32_t pid, protozero::ConstBytes);
@@ -463,6 +464,7 @@ class FtraceParser {
463464
const StringId gpu_power_state_off_id_;
464465
const StringId gpu_power_state_pg_id_;
465466
const StringId gpu_power_state_on_id_;
467+
const StringId gpu_cmdbatch_slice_name_id_;
466468
const StringId ddic_underrun_id_;
467469
std::array<StringId, 8> f2fs_checkpoint_reason_ids_;
468470

src/trace_processor/importers/ftrace/ftrace_tokenizer.cc

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
5252
#include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
5353
#include "protos/perfetto/trace/ftrace/fwtp_ftrace.pbzero.h"
54+
#include "protos/perfetto/trace/ftrace/kgsl.pbzero.h"
5455
#include "protos/perfetto/trace/ftrace/power.pbzero.h"
5556
#include "protos/perfetto/trace/ftrace/thermal_exynos.pbzero.h"
5657
#include "src/trace_processor/util/clock_synchronizer.h"
@@ -68,6 +69,7 @@ using protos::pbzero::FtraceEventBundle;
6869
namespace {
6970

7071
constexpr uint32_t kSequenceScopedClockId = 64;
72+
constexpr uint32_t kAdrenoGpuClockId = 65;
7173

7274
// Fast path for parsing the event id of an ftrace event.
7375
// Speculate on the fact that, if the timestamp was found, the common pid
@@ -154,7 +156,7 @@ base::Status FtraceTokenizer::TokenizeFtraceBundle(
154156

155157
for (auto it = decoder.event(); it; ++it) {
156158
TokenizeFtraceEvent(cpu, clock_id, bundle.slice(it->data(), it->size()),
157-
state);
159+
state, packet_sequence_id);
158160
}
159161

160162
// v50+: optional proto descriptors for generic (i.e. not known at
@@ -214,7 +216,8 @@ void FtraceTokenizer::TokenizeFtraceEvent(
214216
uint32_t cpu,
215217
ClockTracker::ClockId clock_id,
216218
TraceBlobView event,
217-
RefPtr<PacketSequenceStateGeneration> state) {
219+
RefPtr<PacketSequenceStateGeneration> state,
220+
uint32_t packet_sequence_id) {
218221
constexpr auto kTimestampFieldNumber =
219222
protos::pbzero::FtraceEvent::kTimestampFieldNumber;
220223
constexpr auto kTimestampFieldTag = MakeTagVarInt(kTimestampFieldNumber);
@@ -300,6 +303,22 @@ void FtraceTokenizer::TokenizeFtraceEvent(
300303
TokenizeFtraceFwtpPerfettoSlice(cpu, std::move(event), std::move(state));
301304
return;
302305
}
306+
if (PERFETTO_UNLIKELY(event_id ==
307+
protos::pbzero::FtraceEvent::
308+
kKgslAdrenoCmdbatchSubmittedFieldNumber)) {
309+
TokenizeFtraceAdrenoCmdbatchSubmitted(cpu, clock_id, raw_timestamp,
310+
std::move(event), std::move(state),
311+
packet_sequence_id);
312+
return;
313+
}
314+
if (PERFETTO_UNLIKELY(
315+
event_id ==
316+
protos::pbzero::FtraceEvent::kKgslAdrenoCmdbatchRetiredFieldNumber)) {
317+
TokenizeFtraceAdrenoCmdbatchRetired(cpu, clock_id, raw_timestamp,
318+
std::move(event), std::move(state),
319+
packet_sequence_id);
320+
return;
321+
}
303322

304323
std::optional<int64_t> timestamp = context_->clock_tracker->ToTraceTime(
305324
clock_id, static_cast<int64_t>(raw_timestamp));
@@ -493,6 +512,91 @@ FtraceTokenizer::HandleFtraceClockSnapshot(
493512
return clock_id;
494513
}
495514

515+
void FtraceTokenizer::TokenizeFtraceAdrenoCmdbatchSubmitted(
516+
uint32_t cpu,
517+
ClockTracker::ClockId clock_id,
518+
uint64_t raw_timestamp,
519+
TraceBlobView event,
520+
RefPtr<PacketSequenceStateGeneration> state,
521+
uint32_t packet_sequence_id) {
522+
// Adreno GPU ticks run at 19.2 MHz, fixed across all Qualcomm mobile SoCs
523+
// (see KGSL_XO_CLK_FREQ in kgsl_pwrctrl.h).
524+
constexpr int64_t kAdrenoGpuTicksPerUs = 19200;
525+
526+
auto field = GetFtraceEventField(
527+
protos::pbzero::FtraceEvent::kKgslAdrenoCmdbatchSubmittedFieldNumber,
528+
event);
529+
if (!field.has_value())
530+
return;
531+
532+
protos::pbzero::KgslAdrenoCmdbatchSubmittedFtraceEvent::Decoder evt(
533+
field->as_bytes());
534+
// Only register a single clock snapshot: the GPU clock is fixed-frequency
535+
// 19.2 MHz with negligible drift, so one sync point is sufficient.
536+
if (!adreno_gpu_clock_registered_) {
537+
const int64_t sync_time_ns =
538+
static_cast<int64_t>(evt.secs()) * 1000000000LL +
539+
static_cast<int64_t>(evt.usecs()) * 1000LL;
540+
if (sync_time_ns > 0) {
541+
const int64_t gpu_ticks_ns =
542+
static_cast<int64_t>(evt.ticks()) * 1000000 / kAdrenoGpuTicksPerUs;
543+
auto gpu_clock = ClockId::Sequence(context_->trace_id().value,
544+
packet_sequence_id, kAdrenoGpuClockId);
545+
context_->clock_tracker->AddSnapshot({
546+
ClockTracker::ClockTimestamp(gpu_clock, gpu_ticks_ns),
547+
ClockTracker::ClockTimestamp(clock_id, sync_time_ns),
548+
});
549+
adreno_gpu_clock_registered_ = true;
550+
}
551+
}
552+
553+
std::optional<int64_t> timestamp = context_->clock_tracker->ToTraceTime(
554+
clock_id, static_cast<int64_t>(raw_timestamp));
555+
if (!timestamp.has_value()) {
556+
return;
557+
}
558+
module_context_->PushFtraceEvent(
559+
cpu, *timestamp, TracePacketData{std::move(event), std::move(state)});
560+
}
561+
562+
void FtraceTokenizer::TokenizeFtraceAdrenoCmdbatchRetired(
563+
uint32_t cpu,
564+
ClockTracker::ClockId clock_id,
565+
uint64_t raw_timestamp,
566+
TraceBlobView event,
567+
RefPtr<PacketSequenceStateGeneration> state,
568+
uint32_t packet_sequence_id) {
569+
constexpr int64_t kAdrenoGpuTicksPerUs = 19200;
570+
571+
auto field = GetFtraceEventField(
572+
protos::pbzero::FtraceEvent::kKgslAdrenoCmdbatchRetiredFieldNumber,
573+
event);
574+
if (!field.has_value())
575+
return;
576+
577+
protos::pbzero::KgslAdrenoCmdbatchRetiredFtraceEvent::Decoder evt(
578+
field->as_bytes());
579+
auto gpu_clock = ClockId::Sequence(context_->trace_id().value,
580+
packet_sequence_id, kAdrenoGpuClockId);
581+
const int64_t gpu_start_ns =
582+
static_cast<int64_t>(evt.start()) * 1000000 / kAdrenoGpuTicksPerUs;
583+
auto ts = context_->clock_tracker->ToTraceTime(
584+
gpu_clock, gpu_start_ns, std::nullopt, /*suppress_errors=*/true);
585+
if (ts.has_value()) {
586+
module_context_->PushFtraceEvent(
587+
cpu, *ts, TracePacketData{std::move(event), std::move(state)});
588+
return;
589+
}
590+
591+
std::optional<int64_t> timestamp = context_->clock_tracker->ToTraceTime(
592+
clock_id, static_cast<int64_t>(raw_timestamp));
593+
if (!timestamp.has_value()) {
594+
return;
595+
}
596+
module_context_->PushFtraceEvent(
597+
cpu, *timestamp, TracePacketData{std::move(event), std::move(state)});
598+
}
599+
496600
void FtraceTokenizer::TokenizeFtraceGpuWorkPeriod(
497601
uint32_t cpu,
498602
TraceBlobView event,

src/trace_processor/importers/ftrace/ftrace_tokenizer.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ class FtraceTokenizer {
5858
void TokenizeFtraceEvent(uint32_t cpu,
5959
ClockTracker::ClockId,
6060
TraceBlobView event,
61-
RefPtr<PacketSequenceStateGeneration> state);
61+
RefPtr<PacketSequenceStateGeneration> state,
62+
uint32_t packet_sequence_id);
6263
void TokenizeFtraceCompactSched(uint32_t cpu,
6364
ClockTracker::ClockId,
6465
protozero::ConstBytes);
@@ -75,6 +76,20 @@ class FtraceTokenizer {
7576
base::StatusOr<ClockTracker::ClockId> HandleFtraceClockSnapshot(
7677
protos::pbzero::FtraceEventBundle::Decoder& decoder,
7778
uint32_t packet_sequence_id);
79+
void TokenizeFtraceAdrenoCmdbatchSubmitted(
80+
uint32_t cpu,
81+
ClockTracker::ClockId clock_id,
82+
uint64_t raw_timestamp,
83+
TraceBlobView event,
84+
RefPtr<PacketSequenceStateGeneration> state,
85+
uint32_t packet_sequence_id);
86+
void TokenizeFtraceAdrenoCmdbatchRetired(
87+
uint32_t cpu,
88+
ClockTracker::ClockId clock_id,
89+
uint64_t raw_timestamp,
90+
TraceBlobView event,
91+
RefPtr<PacketSequenceStateGeneration> state,
92+
uint32_t packet_sequence_id);
7893
void TokenizeFtraceGpuWorkPeriod(uint32_t cpu,
7994
TraceBlobView event,
8095
RefPtr<PacketSequenceStateGeneration> state);
@@ -109,6 +124,7 @@ class FtraceTokenizer {
109124
GenericFtraceTracker* generic_tracker_;
110125

111126
int64_t latest_ftrace_clock_snapshot_ts_ = 0;
127+
bool adreno_gpu_clock_registered_ = false;
112128
std::vector<bool> per_cpu_seen_first_bundle_;
113129
};
114130

test/trace_processor/diff_tests/include_index.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
from diff_tests.parser.etm.tests import Etm
7676
from diff_tests.parser.etw.tests import Etw
7777
from diff_tests.parser.fs.tests import Fs
78+
from diff_tests.parser.ftrace.adreno_cmdbatch_tests import AdrenoCmdbatch
7879
from diff_tests.parser.ftrace.block_io_tests import BlockIo
7980
from diff_tests.parser.ftrace.ftrace_crop_tests import FtraceCrop
8081
from diff_tests.parser.ftrace.kprobes_tests import Kprobes
@@ -265,6 +266,7 @@ def fetch_all_diff_tests(
265266
ParsingRssStats,
266267
ParsingSysStats,
267268
ParsingMemoryCounters,
269+
AdrenoCmdbatch,
268270
BlockIo,
269271
FtraceCrop,
270272
Kprobes,
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python3
2+
# Copyright (C) 2024 The Android Open Source Project
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
from python.generators.diff_tests.testing import Csv, TextProto
17+
from python.generators.diff_tests.testing import DiffTestBlueprint
18+
from python.generators.diff_tests.testing import TestSuite
19+
20+
21+
class AdrenoCmdbatch(TestSuite):
22+
23+
def test_adreno_cmdbatch_retired_slice(self):
24+
return DiffTestBlueprint(
25+
trace=TextProto(r"""
26+
packet {
27+
clock_snapshot {
28+
clocks { clock_id: 6 timestamp: 1000000000 }
29+
}
30+
}
31+
packet { trusted_packet_sequence_id: 1 ftrace_events {
32+
cpu: 0
33+
event {
34+
timestamp: 1000000000
35+
pid: 100
36+
kgsl_adreno_cmdbatch_submitted {
37+
id: 1
38+
ticks: 19200000
39+
secs: 1
40+
usecs: 0
41+
prio: 0
42+
}
43+
}
44+
event {
45+
timestamp: 3100000000
46+
pid: 100
47+
kgsl_adreno_cmdbatch_retired {
48+
id: 1
49+
start: 38400000
50+
retire: 57600000
51+
prio: 0
52+
}
53+
}
54+
}}
55+
"""),
56+
query="""
57+
SELECT
58+
slice.name as name,
59+
slice.ts as ts,
60+
slice.dur as dur,
61+
track.name as track_name
62+
FROM slice
63+
JOIN track ON slice.track_id = track.id
64+
WHERE track.type = 'adreno_gpu_cmdbatch'
65+
""",
66+
out=Csv("""
67+
"name","ts","dur","track_name"
68+
"GPU",2000000000,1000000000,"Adreno GPU Cmdbatch (Ctx=1, Prio=0)"
69+
"""))

ui/src/plugins/dev.perfetto.TraceProcessorTrack/slice_tracks.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,11 @@ export const SLICE_TRACK_SCHEMAS: ReadonlyArray<SliceTrackTypeSchema> = [
248248
topLevelGroup: 'HARDWARE',
249249
group: undefined,
250250
},
251+
{
252+
type: 'adreno_gpu_cmdbatch',
253+
topLevelGroup: 'HARDWARE',
254+
group: 'GPU Adreno',
255+
},
251256
{
252257
type: 'triggers',
253258
topLevelGroup: 'SYSTEM',

0 commit comments

Comments
 (0)