xref: /aosp_15_r20/frameworks/native/libs/tracing_perfetto/tests/utils.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright 2024 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 // Copied from //external/perfetto/src/shared_lib/test/utils.cc
18 
19 #include "utils.h"
20 
21 #include "perfetto/public/abi/heap_buffer.h"
22 #include "perfetto/public/pb_msg.h"
23 #include "perfetto/public/pb_utils.h"
24 #include "perfetto/public/protos/config/data_source_config.pzc.h"
25 #include "perfetto/public/protos/config/trace_config.pzc.h"
26 #include "perfetto/public/protos/config/track_event/track_event_config.pzc.h"
27 #include "perfetto/public/tracing_session.h"
28 
29 #include "protos/perfetto/config/ftrace/ftrace_config.pb.h"
30 #include "protos/perfetto/config/track_event/track_event_config.pb.h"
31 #include "protos/perfetto/config/data_source_config.pb.h"
32 #include "protos/perfetto/config/trace_config.pb.h"
33 
34 namespace perfetto {
35 namespace shlib {
36 namespace test_utils {
37 namespace {
38 
ToHexChars(uint8_t val)39 std::string ToHexChars(uint8_t val) {
40   std::string ret;
41   uint8_t high_nibble = (val & 0xF0) >> 4;
42   uint8_t low_nibble = (val & 0xF);
43   static const char hex_chars[] = "0123456789ABCDEF";
44   ret.push_back(hex_chars[high_nibble]);
45   ret.push_back(hex_chars[low_nibble]);
46   return ret;
47 }
48 
49 }  // namespace
50 
Build()51 TracingSession TracingSession::Builder::Build() {
52   perfetto::protos::TraceConfig trace_config;
53   trace_config.add_buffers()->set_size_kb(1024);
54 
55   auto* track_event_ds_config = trace_config.add_data_sources()->mutable_config();
56   auto* ftrace_ds_config = trace_config.add_data_sources()->mutable_config();
57 
58   track_event_ds_config->set_name("track_event");
59   track_event_ds_config->set_target_buffer(0);
60 
61   ftrace_ds_config->set_name("linux.ftrace");
62   ftrace_ds_config->set_target_buffer(0);
63 
64   {
65     auto* ftrace_config = ftrace_ds_config->mutable_ftrace_config();
66     if (!atrace_categories_.empty()) {
67       ftrace_config->add_ftrace_events("ftrace/print");
68       for (const std::string& cat : atrace_categories_) {
69         ftrace_config->add_atrace_categories(cat);
70       }
71 
72       for (const std::string& cat : atrace_categories_prefer_sdk_) {
73         ftrace_config->add_atrace_categories_prefer_sdk(cat);
74       }
75     }
76   }
77 
78   {
79     auto* track_event_config = track_event_ds_config->mutable_track_event_config();
80     if (!enabled_categories_.empty() || !disabled_categories_.empty()) {
81       for (const std::string& cat : enabled_categories_) {
82         track_event_config->add_enabled_categories(cat);
83       }
84 
85       for (const std::string& cat : disabled_categories_) {
86         track_event_config->add_disabled_categories(cat);
87       }
88     }
89   }
90 
91   struct PerfettoTracingSessionImpl* ts =
92       PerfettoTracingSessionCreate(PERFETTO_BACKEND_SYSTEM);
93 
94   std::string trace_config_string;
95   trace_config.SerializeToString(&trace_config_string);
96 
97   PerfettoTracingSessionSetup(ts, trace_config_string.data(), trace_config_string.length());
98 
99   // Fails to start here
100   PerfettoTracingSessionStartBlocking(ts);
101 
102   return TracingSession::Adopt(ts);
103 }
104 
Adopt(struct PerfettoTracingSessionImpl * session)105 TracingSession TracingSession::Adopt(struct PerfettoTracingSessionImpl* session) {
106   TracingSession ret;
107   ret.session_ = session;
108   ret.stopped_ = std::make_unique<WaitableEvent>();
109   PerfettoTracingSessionSetStopCb(
110       ret.session_,
111       [](struct PerfettoTracingSessionImpl*, void* arg) {
112         static_cast<WaitableEvent*>(arg)->Notify();
113       },
114       ret.stopped_.get());
115   return ret;
116 }
117 
TracingSession(TracingSession && other)118 TracingSession::TracingSession(TracingSession&& other) noexcept {
119   session_ = other.session_;
120   other.session_ = nullptr;
121   stopped_ = std::move(other.stopped_);
122   other.stopped_ = nullptr;
123 }
124 
~TracingSession()125 TracingSession::~TracingSession() {
126   if (!session_) {
127     return;
128   }
129   if (!stopped_->IsNotified()) {
130     PerfettoTracingSessionStopBlocking(session_);
131     stopped_->WaitForNotification();
132   }
133   PerfettoTracingSessionDestroy(session_);
134 }
135 
FlushBlocking(uint32_t timeout_ms)136 bool TracingSession::FlushBlocking(uint32_t timeout_ms) {
137   WaitableEvent notification;
138   bool result;
139   auto* cb = new std::function<void(bool)>([&](bool success) {
140     result = success;
141     notification.Notify();
142   });
143   PerfettoTracingSessionFlushAsync(
144       session_, timeout_ms,
145       [](PerfettoTracingSessionImpl*, bool success, void* user_arg) {
146         auto* f = reinterpret_cast<std::function<void(bool)>*>(user_arg);
147         (*f)(success);
148         delete f;
149       },
150       cb);
151   notification.WaitForNotification();
152   return result;
153 }
154 
WaitForStopped()155 void TracingSession::WaitForStopped() {
156   stopped_->WaitForNotification();
157 }
158 
StopBlocking()159 void TracingSession::StopBlocking() {
160   PerfettoTracingSessionStopBlocking(session_);
161 }
162 
ReadBlocking()163 std::vector<uint8_t> TracingSession::ReadBlocking() {
164   std::vector<uint8_t> data;
165   PerfettoTracingSessionReadTraceBlocking(
166       session_,
167       [](struct PerfettoTracingSessionImpl*, const void* trace_data,
168          size_t size, bool, void* user_arg) {
169         auto& dst = *static_cast<std::vector<uint8_t>*>(user_arg);
170         auto* src = static_cast<const uint8_t*>(trace_data);
171         dst.insert(dst.end(), src, src + size);
172       },
173       &data);
174   return data;
175 }
176 
177 }  // namespace test_utils
178 }  // namespace shlib
179 }  // namespace perfetto
180 
PrintTo(const PerfettoPbDecoderField & field,std::ostream * pos)181 void PrintTo(const PerfettoPbDecoderField& field, std::ostream* pos) {
182   std::ostream& os = *pos;
183   PerfettoPbDecoderStatus status =
184       static_cast<PerfettoPbDecoderStatus>(field.status);
185   switch (status) {
186     case PERFETTO_PB_DECODER_ERROR:
187       os << "MALFORMED PROTOBUF";
188       break;
189     case PERFETTO_PB_DECODER_DONE:
190       os << "DECODER DONE";
191       break;
192     case PERFETTO_PB_DECODER_OK:
193       switch (field.wire_type) {
194         case PERFETTO_PB_WIRE_TYPE_DELIMITED:
195           os << "\"";
196           for (size_t i = 0; i < field.value.delimited.len; i++) {
197             os << perfetto::shlib::test_utils::ToHexChars(
198                       field.value.delimited.start[i])
199                << " ";
200           }
201           os << "\"";
202           break;
203         case PERFETTO_PB_WIRE_TYPE_VARINT:
204           os << "varint: " << field.value.integer64;
205           break;
206         case PERFETTO_PB_WIRE_TYPE_FIXED32:
207           os << "fixed32: " << field.value.integer32;
208           break;
209         case PERFETTO_PB_WIRE_TYPE_FIXED64:
210           os << "fixed64: " << field.value.integer64;
211           break;
212       }
213       break;
214   }
215 }
216