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