diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc index 2544be8e7be..5a35514a06c 100644 --- a/src/trace_processor/importers/ftrace/ftrace_parser.cc +++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc @@ -542,6 +542,7 @@ FtraceParser::FtraceParser(TraceProcessorContext* context, gpu_power_state_off_id_(context->storage->InternString("OFF")), gpu_power_state_pg_id_(context->storage->InternString("PG")), gpu_power_state_on_id_(context->storage->InternString("ON")), + gpu_cmdbatch_slice_name_id_(context->storage->InternString("GPU")), ddic_underrun_id_(context_->storage->InternString("ddic_underrun")), memcg_reclaim_order_id_( context->storage->InternString("memcg_reclaim_order")), @@ -939,6 +940,14 @@ base::Status FtraceParser::ParseFtraceEvent(uint32_t cpu, ParseKgslGpuFreq(ts, fld_bytes); break; } + case FtraceEvent::kKgslAdrenoCmdbatchSyncFieldNumber: { + ParseKgslAdrenoCmdbatchSync(ts, fld_bytes); + break; + } + case FtraceEvent::kKgslAdrenoCmdbatchRetiredFieldNumber: { + ParseKgslAdrenoCmdbatchRetired(ts, fld_bytes); + break; + } case FtraceEvent::kCpuIdleFieldNumber: { ParseCpuIdle(ts, fld_bytes); break; @@ -1931,6 +1940,53 @@ void FtraceParser::ParseKgslGpuFreq(int64_t timestamp, ConstBytes blob) { context_->event_tracker->PushCounter(timestamp, new_freq, track); } +void FtraceParser::ParseKgslAdrenoCmdbatchSync(int64_t timestamp, + protozero::ConstBytes data) { + protos::pbzero::KgslAdrenoCmdbatchSyncFtraceEvent::Decoder evt(data); + adreno_cmdbatch_sync_points_.Insert( + evt.timestamp(), AdrenoCmdbatchSyncPoint{timestamp, evt.ticks()}); +} + +void FtraceParser::ParseKgslAdrenoCmdbatchRetired(int64_t timestamp, + protozero::ConstBytes data) { + protos::pbzero::KgslAdrenoCmdbatchRetiredFtraceEvent::Decoder evt(data); + + static constexpr auto kBlueprint = TrackCompressor::SliceBlueprint( + "adreno_gpu_cmdbatch", + tracks::DimensionBlueprints(tracks::UintDimensionBlueprint("context_id"), + tracks::UintDimensionBlueprint("prio")), + tracks::FnNameBlueprint([](uint32_t context_id, uint32_t prio) { + return base::StackString<64>("GPU (Ctx=%u, Prio=%u)", context_id, prio); + })); + + if (evt.retire() < evt.start()) { + return; + } + + // Adreno GPU ticks run at 19.2 MHz, fixed across all Qualcomm mobile SoCs + // (see KGSL_XO_CLK_FREQ in kgsl_pwrctrl.h). + constexpr int64_t kAdrenoXoFreqHz = 19200000; + const int64_t duration = static_cast(evt.retire() - evt.start()) * + 1000000000 / kAdrenoXoFreqHz; + + int64_t gpu_start_ts = timestamp; + auto* sync = adreno_cmdbatch_sync_points_.Find(evt.timestamp()); + if (sync) { + gpu_start_ts = + sync->trace_ts + static_cast(evt.start() - sync->gpu_ticks) * + 1000000000 / kAdrenoXoFreqHz; + adreno_cmdbatch_sync_points_.Erase(evt.timestamp()); + } + + const uint32_t context_id = evt.id(); + TrackId track_id = context_->track_compressor->InternScoped( + kBlueprint, + tracks::Dimensions(context_id, static_cast(evt.prio())), + gpu_start_ts, duration); + context_->slice_tracker->Scoped(gpu_start_ts, track_id, kNullStringId, + gpu_cmdbatch_slice_name_id_, duration); +} + void FtraceParser::ParseCpuIdle(int64_t timestamp, ConstBytes blob) { protos::pbzero::CpuIdleFtraceEvent::Decoder idle(blob); TrackId track = context_->track_tracker->InternTrack( diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.h b/src/trace_processor/importers/ftrace/ftrace_parser.h index 205b226d72c..730836f5963 100644 --- a/src/trace_processor/importers/ftrace/ftrace_parser.h +++ b/src/trace_processor/importers/ftrace/ftrace_parser.h @@ -95,6 +95,8 @@ class FtraceParser { void ParseCpuFreqThrottle(int64_t timestamp, protozero::ConstBytes); void ParseGpuFreq(int64_t timestamp, protozero::ConstBytes); void ParseKgslGpuFreq(int64_t timestamp, protozero::ConstBytes); + void ParseKgslAdrenoCmdbatchSync(int64_t timestamp, protozero::ConstBytes); + void ParseKgslAdrenoCmdbatchRetired(int64_t timestamp, protozero::ConstBytes); void ParseCpuIdle(int64_t timestamp, protozero::ConstBytes); void ParsePrint(int64_t timestamp, uint32_t pid, protozero::ConstBytes); void ParseZero(int64_t timestamp, uint32_t pid, protozero::ConstBytes); @@ -463,6 +465,15 @@ class FtraceParser { const StringId gpu_power_state_off_id_; const StringId gpu_power_state_pg_id_; const StringId gpu_power_state_on_id_; + + struct AdrenoCmdbatchSyncPoint { + int64_t trace_ts; + uint64_t gpu_ticks; + }; + base::FlatHashMap + adreno_cmdbatch_sync_points_; + + const StringId gpu_cmdbatch_slice_name_id_; const StringId ddic_underrun_id_; std::array f2fs_checkpoint_reason_ids_; diff --git a/test/trace_processor/diff_tests/include_index.py b/test/trace_processor/diff_tests/include_index.py index b66a216b722..2214fadf4fe 100644 --- a/test/trace_processor/diff_tests/include_index.py +++ b/test/trace_processor/diff_tests/include_index.py @@ -75,6 +75,7 @@ from diff_tests.parser.etm.tests import Etm from diff_tests.parser.etw.tests import Etw from diff_tests.parser.fs.tests import Fs +from diff_tests.parser.ftrace.adreno_cmdbatch_tests import AdrenoCmdbatch from diff_tests.parser.ftrace.block_io_tests import BlockIo from diff_tests.parser.ftrace.ftrace_crop_tests import FtraceCrop from diff_tests.parser.ftrace.kprobes_tests import Kprobes @@ -266,6 +267,7 @@ def fetch_all_diff_tests( ParsingRssStats, ParsingSysStats, ParsingMemoryCounters, + AdrenoCmdbatch, BlockIo, FtraceCrop, Kprobes, diff --git a/test/trace_processor/diff_tests/parser/ftrace/adreno_cmdbatch_tests.py b/test/trace_processor/diff_tests/parser/ftrace/adreno_cmdbatch_tests.py new file mode 100644 index 00000000000..aacc8a8dfeb --- /dev/null +++ b/test/trace_processor/diff_tests/parser/ftrace/adreno_cmdbatch_tests.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# Copyright (C) 2024 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from python.generators.diff_tests.testing import Csv, TextProto +from python.generators.diff_tests.testing import DiffTestBlueprint +from python.generators.diff_tests.testing import TestSuite + + +class AdrenoCmdbatch(TestSuite): + + def test_adreno_cmdbatch_retired_slice(self): + return DiffTestBlueprint( + trace=TextProto(r""" +packet { trusted_packet_sequence_id: 1 ftrace_events { + cpu: 0 + event { + timestamp: 1000000000 + pid: 100 + kgsl_adreno_cmdbatch_sync { + id: 1 + timestamp: 42 + ticks: 19200000 + prio: 0 + } + } + event { + timestamp: 3100000000 + pid: 100 + kgsl_adreno_cmdbatch_retired { + id: 1 + timestamp: 42 + start: 38400000 + retire: 57600000 + prio: 0 + } + } + }} + """), + query=""" + SELECT + slice.name as name, + slice.ts as ts, + slice.dur as dur, + track.name as track_name + FROM slice + JOIN track ON slice.track_id = track.id + WHERE track.type = 'adreno_gpu_cmdbatch' + """, + out=Csv(""" + "name","ts","dur","track_name" + "GPU",2000000000,1000000000,"GPU (Ctx=1, Prio=0)" + """)) diff --git a/ui/src/plugins/dev.perfetto.TraceProcessorTrack/slice_tracks.ts b/ui/src/plugins/dev.perfetto.TraceProcessorTrack/slice_tracks.ts index 32d9762249f..a30d231eebe 100644 --- a/ui/src/plugins/dev.perfetto.TraceProcessorTrack/slice_tracks.ts +++ b/ui/src/plugins/dev.perfetto.TraceProcessorTrack/slice_tracks.ts @@ -258,6 +258,11 @@ export const SLICE_TRACK_SCHEMAS: ReadonlyArray = [ topLevelGroup: 'HARDWARE', group: undefined, }, + { + type: 'adreno_gpu_cmdbatch', + topLevelGroup: 'GPU', + group: 'Adreno Cmdbatch', + }, { type: 'triggers', topLevelGroup: 'SYSTEM',