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