• 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 "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