xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/ftrace/pkvm_hyp_cpu_tracker.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2023 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 
17 #include "src/trace_processor/importers/ftrace/pkvm_hyp_cpu_tracker.h"
18 
19 #include "perfetto/base/logging.h"
20 #include "perfetto/ext/base/string_utils.h"
21 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
22 #include "protos/perfetto/trace/ftrace/hyp.pbzero.h"
23 #include "src/trace_processor/importers/common/slice_tracker.h"
24 #include "src/trace_processor/importers/common/track_tracker.h"
25 
26 namespace perfetto::trace_processor {
27 namespace {
28 
GetTrackName(uint32_t cpu)29 TrackTracker::LegacyCharArrayName GetTrackName(uint32_t cpu) {
30   return TrackTracker::LegacyCharArrayName{
31       base::StackString<255>("pkVM Hypervisor CPU %u", cpu)};
32 }
33 
34 }  // namespace
35 
PkvmHypervisorCpuTracker(TraceProcessorContext * context)36 PkvmHypervisorCpuTracker::PkvmHypervisorCpuTracker(
37     TraceProcessorContext* context)
38     : context_(context),
39       category_(context->storage->InternString("pkvm_hyp")),
40       slice_name_(context->storage->InternString("hyp")),
41       hyp_enter_reason_(context->storage->InternString("hyp_enter_reason")) {}
42 
43 // static
IsPkvmHypervisorEvent(uint32_t event_id)44 bool PkvmHypervisorCpuTracker::IsPkvmHypervisorEvent(uint32_t event_id) {
45   using protos::pbzero::FtraceEvent;
46   switch (event_id) {
47     case FtraceEvent::kHypEnterFieldNumber:
48     case FtraceEvent::kHypExitFieldNumber:
49     case FtraceEvent::kHostHcallFieldNumber:
50     case FtraceEvent::kHostMemAbortFieldNumber:
51     case FtraceEvent::kHostSmcFieldNumber:
52       return true;
53     default:
54       return false;
55   }
56 }
57 
ParseHypEvent(uint32_t cpu,int64_t timestamp,uint32_t event_id,protozero::ConstBytes blob)58 void PkvmHypervisorCpuTracker::ParseHypEvent(uint32_t cpu,
59                                              int64_t timestamp,
60                                              uint32_t event_id,
61                                              protozero::ConstBytes blob) {
62   using protos::pbzero::FtraceEvent;
63   switch (event_id) {
64     case FtraceEvent::kHypEnterFieldNumber:
65       ParseHypEnter(cpu, timestamp);
66       break;
67     case FtraceEvent::kHypExitFieldNumber:
68       ParseHypExit(cpu, timestamp);
69       break;
70     case FtraceEvent::kHostHcallFieldNumber:
71       ParseHostHcall(cpu, blob);
72       break;
73     case FtraceEvent::kHostMemAbortFieldNumber:
74       ParseHostMemAbort(cpu, blob);
75       break;
76     case FtraceEvent::kHostSmcFieldNumber:
77       ParseHostSmc(cpu, blob);
78       break;
79     // TODO(b/249050813): add remaining hypervisor events
80     default:
81       PERFETTO_FATAL("Not a hypervisor event %d", event_id);
82   }
83 }
84 
ParseHypEnter(uint32_t cpu,int64_t timestamp)85 void PkvmHypervisorCpuTracker::ParseHypEnter(uint32_t cpu, int64_t timestamp) {
86   // TODO(b/249050813): handle bad events (e.g. 2 hyp_enter in a row)
87   TrackId track_id = context_->track_tracker->InternCpuTrack(
88       tracks::pkvm_hypervisor, cpu, GetTrackName(cpu));
89   context_->slice_tracker->Begin(timestamp, track_id, category_, slice_name_);
90 }
91 
ParseHypExit(uint32_t cpu,int64_t timestamp)92 void PkvmHypervisorCpuTracker::ParseHypExit(uint32_t cpu, int64_t timestamp) {
93   // TODO(b/249050813): handle bad events (e.g. 2 hyp_exit in a row)
94   TrackId track_id = context_->track_tracker->InternCpuTrack(
95       tracks::pkvm_hypervisor, cpu, GetTrackName(cpu));
96   context_->slice_tracker->End(timestamp, track_id);
97 }
98 
ParseHostHcall(uint32_t cpu,protozero::ConstBytes blob)99 void PkvmHypervisorCpuTracker::ParseHostHcall(uint32_t cpu,
100                                               protozero::ConstBytes blob) {
101   protos::pbzero::HostHcallFtraceEvent::Decoder evt(blob.data, blob.size);
102   TrackId track_id = context_->track_tracker->InternCpuTrack(
103       tracks::pkvm_hypervisor, cpu, GetTrackName(cpu));
104 
105   auto args_inserter = [this, &evt](ArgsTracker::BoundInserter* inserter) {
106     StringId host_hcall = context_->storage->InternString("host_hcall");
107     StringId id = context_->storage->InternString("id");
108     StringId invalid = context_->storage->InternString("invalid");
109     inserter->AddArg(hyp_enter_reason_, Variadic::String(host_hcall));
110     inserter->AddArg(id, Variadic::UnsignedInteger(evt.id()));
111     inserter->AddArg(invalid, Variadic::UnsignedInteger(evt.invalid()));
112   };
113   context_->slice_tracker->AddArgs(track_id, category_, slice_name_,
114                                    args_inserter);
115 }
116 
ParseHostSmc(uint32_t cpu,protozero::ConstBytes blob)117 void PkvmHypervisorCpuTracker::ParseHostSmc(uint32_t cpu,
118                                             protozero::ConstBytes blob) {
119   protos::pbzero::HostSmcFtraceEvent::Decoder evt(blob.data, blob.size);
120   TrackId track_id = context_->track_tracker->InternCpuTrack(
121       tracks::pkvm_hypervisor, cpu, GetTrackName(cpu));
122 
123   auto args_inserter = [this, &evt](ArgsTracker::BoundInserter* inserter) {
124     StringId host_smc = context_->storage->InternString("host_smc");
125     StringId id = context_->storage->InternString("id");
126     StringId forwarded = context_->storage->InternString("forwarded");
127     inserter->AddArg(hyp_enter_reason_, Variadic::String(host_smc));
128     inserter->AddArg(id, Variadic::UnsignedInteger(evt.id()));
129     inserter->AddArg(forwarded, Variadic::UnsignedInteger(evt.forwarded()));
130   };
131   context_->slice_tracker->AddArgs(track_id, category_, slice_name_,
132                                    args_inserter);
133 }
134 
ParseHostMemAbort(uint32_t cpu,protozero::ConstBytes blob)135 void PkvmHypervisorCpuTracker::ParseHostMemAbort(uint32_t cpu,
136                                                  protozero::ConstBytes blob) {
137   protos::pbzero::HostMemAbortFtraceEvent::Decoder evt(blob.data, blob.size);
138   TrackId track_id = context_->track_tracker->InternCpuTrack(
139       tracks::pkvm_hypervisor, cpu, GetTrackName(cpu));
140 
141   auto args_inserter = [this, &evt](ArgsTracker::BoundInserter* inserter) {
142     StringId host_mem_abort = context_->storage->InternString("host_mem_abort");
143     StringId esr = context_->storage->InternString("esr");
144     StringId addr = context_->storage->InternString("addr");
145     inserter->AddArg(hyp_enter_reason_, Variadic::String(host_mem_abort));
146     inserter->AddArg(esr, Variadic::UnsignedInteger(evt.esr()));
147     inserter->AddArg(addr, Variadic::UnsignedInteger(evt.addr()));
148   };
149   context_->slice_tracker->AddArgs(track_id, category_, slice_name_,
150                                    args_inserter);
151 }
152 
153 }  // namespace perfetto::trace_processor
154