xref: /aosp_15_r20/external/swiftshader/third_party/marl/src/trace.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2019 The Marl Authors.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker 
15*03ce13f7SAndroid Build Coastguard Worker // The Trace API produces a trace event file that can be consumed with Chrome's
16*03ce13f7SAndroid Build Coastguard Worker // about:tracing viewer.
17*03ce13f7SAndroid Build Coastguard Worker // Documentation can be found at:
18*03ce13f7SAndroid Build Coastguard Worker //   https://www.chromium.org/developers/how-tos/trace-event-profiling-tool
19*03ce13f7SAndroid Build Coastguard Worker //   https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit
20*03ce13f7SAndroid Build Coastguard Worker 
21*03ce13f7SAndroid Build Coastguard Worker #include "marl/trace.h"
22*03ce13f7SAndroid Build Coastguard Worker 
23*03ce13f7SAndroid Build Coastguard Worker #include "marl/defer.h"
24*03ce13f7SAndroid Build Coastguard Worker #include "marl/scheduler.h"
25*03ce13f7SAndroid Build Coastguard Worker #include "marl/thread.h"
26*03ce13f7SAndroid Build Coastguard Worker 
27*03ce13f7SAndroid Build Coastguard Worker #if MARL_TRACE_ENABLED
28*03ce13f7SAndroid Build Coastguard Worker 
29*03ce13f7SAndroid Build Coastguard Worker #include <atomic>
30*03ce13f7SAndroid Build Coastguard Worker #include <fstream>
31*03ce13f7SAndroid Build Coastguard Worker 
32*03ce13f7SAndroid Build Coastguard Worker namespace {
33*03ce13f7SAndroid Build Coastguard Worker 
34*03ce13f7SAndroid Build Coastguard Worker // Chrome traces can choke or error on very large trace files.
35*03ce13f7SAndroid Build Coastguard Worker // Limit the number of events created to this number.
36*03ce13f7SAndroid Build Coastguard Worker static constexpr int MaxEvents = 100000;
37*03ce13f7SAndroid Build Coastguard Worker 
threadFiberID(uint32_t threadID,uint32_t fiberID)38*03ce13f7SAndroid Build Coastguard Worker uint64_t threadFiberID(uint32_t threadID, uint32_t fiberID) {
39*03ce13f7SAndroid Build Coastguard Worker   return static_cast<uint64_t>(threadID) * 31 + static_cast<uint64_t>(fiberID);
40*03ce13f7SAndroid Build Coastguard Worker }
41*03ce13f7SAndroid Build Coastguard Worker 
42*03ce13f7SAndroid Build Coastguard Worker }  // anonymous namespace
43*03ce13f7SAndroid Build Coastguard Worker 
44*03ce13f7SAndroid Build Coastguard Worker namespace marl {
45*03ce13f7SAndroid Build Coastguard Worker 
get()46*03ce13f7SAndroid Build Coastguard Worker Trace* Trace::get() {
47*03ce13f7SAndroid Build Coastguard Worker   static Trace trace;
48*03ce13f7SAndroid Build Coastguard Worker   return &trace;
49*03ce13f7SAndroid Build Coastguard Worker }
50*03ce13f7SAndroid Build Coastguard Worker 
Trace()51*03ce13f7SAndroid Build Coastguard Worker Trace::Trace() {
52*03ce13f7SAndroid Build Coastguard Worker   nameThread("main");
53*03ce13f7SAndroid Build Coastguard Worker   thread = std::thread([&] {
54*03ce13f7SAndroid Build Coastguard Worker     Thread::setName("Trace worker");
55*03ce13f7SAndroid Build Coastguard Worker 
56*03ce13f7SAndroid Build Coastguard Worker     auto out = std::fstream("chrome.trace", std::ios_base::out);
57*03ce13f7SAndroid Build Coastguard Worker 
58*03ce13f7SAndroid Build Coastguard Worker     out << "[" << std::endl;
59*03ce13f7SAndroid Build Coastguard Worker     defer(out << std::endl << "]" << std::endl);
60*03ce13f7SAndroid Build Coastguard Worker 
61*03ce13f7SAndroid Build Coastguard Worker     auto first = true;
62*03ce13f7SAndroid Build Coastguard Worker     for (int i = 0; i < MaxEvents; i++) {
63*03ce13f7SAndroid Build Coastguard Worker       auto event = take();
64*03ce13f7SAndroid Build Coastguard Worker       if (event->type() == Event::Type::Shutdown) {
65*03ce13f7SAndroid Build Coastguard Worker         return;
66*03ce13f7SAndroid Build Coastguard Worker       }
67*03ce13f7SAndroid Build Coastguard Worker       if (!first) {
68*03ce13f7SAndroid Build Coastguard Worker         out << "," << std::endl;
69*03ce13f7SAndroid Build Coastguard Worker       };
70*03ce13f7SAndroid Build Coastguard Worker       first = false;
71*03ce13f7SAndroid Build Coastguard Worker       out << "{" << std::endl;
72*03ce13f7SAndroid Build Coastguard Worker       event->write(out);
73*03ce13f7SAndroid Build Coastguard Worker       out << "}";
74*03ce13f7SAndroid Build Coastguard Worker     }
75*03ce13f7SAndroid Build Coastguard Worker 
76*03ce13f7SAndroid Build Coastguard Worker     stopped = true;
77*03ce13f7SAndroid Build Coastguard Worker 
78*03ce13f7SAndroid Build Coastguard Worker     while (take()->type() != Event::Type::Shutdown) {
79*03ce13f7SAndroid Build Coastguard Worker     }
80*03ce13f7SAndroid Build Coastguard Worker   });
81*03ce13f7SAndroid Build Coastguard Worker }
82*03ce13f7SAndroid Build Coastguard Worker 
~Trace()83*03ce13f7SAndroid Build Coastguard Worker Trace::~Trace() {
84*03ce13f7SAndroid Build Coastguard Worker   put(new Shutdown());
85*03ce13f7SAndroid Build Coastguard Worker   thread.join();
86*03ce13f7SAndroid Build Coastguard Worker }
87*03ce13f7SAndroid Build Coastguard Worker 
nameThread(const char * fmt,...)88*03ce13f7SAndroid Build Coastguard Worker void Trace::nameThread(const char* fmt, ...) {
89*03ce13f7SAndroid Build Coastguard Worker   if (stopped) {
90*03ce13f7SAndroid Build Coastguard Worker     return;
91*03ce13f7SAndroid Build Coastguard Worker   }
92*03ce13f7SAndroid Build Coastguard Worker   auto event = new NameThreadEvent();
93*03ce13f7SAndroid Build Coastguard Worker 
94*03ce13f7SAndroid Build Coastguard Worker   va_list vararg;
95*03ce13f7SAndroid Build Coastguard Worker   va_start(vararg, fmt);
96*03ce13f7SAndroid Build Coastguard Worker   vsnprintf(event->name, Trace::MaxEventNameLength, fmt, vararg);
97*03ce13f7SAndroid Build Coastguard Worker   va_end(vararg);
98*03ce13f7SAndroid Build Coastguard Worker 
99*03ce13f7SAndroid Build Coastguard Worker   put(event);
100*03ce13f7SAndroid Build Coastguard Worker }
101*03ce13f7SAndroid Build Coastguard Worker 
beginEvent(const char * fmt,...)102*03ce13f7SAndroid Build Coastguard Worker void Trace::beginEvent(const char* fmt, ...) {
103*03ce13f7SAndroid Build Coastguard Worker   if (stopped) {
104*03ce13f7SAndroid Build Coastguard Worker     return;
105*03ce13f7SAndroid Build Coastguard Worker   }
106*03ce13f7SAndroid Build Coastguard Worker   auto event = new BeginEvent();
107*03ce13f7SAndroid Build Coastguard Worker 
108*03ce13f7SAndroid Build Coastguard Worker   va_list vararg;
109*03ce13f7SAndroid Build Coastguard Worker   va_start(vararg, fmt);
110*03ce13f7SAndroid Build Coastguard Worker   vsnprintf(event->name, Trace::MaxEventNameLength, fmt, vararg);
111*03ce13f7SAndroid Build Coastguard Worker   va_end(vararg);
112*03ce13f7SAndroid Build Coastguard Worker 
113*03ce13f7SAndroid Build Coastguard Worker   event->timestamp = timestamp();
114*03ce13f7SAndroid Build Coastguard Worker   put(event);
115*03ce13f7SAndroid Build Coastguard Worker }
116*03ce13f7SAndroid Build Coastguard Worker 
endEvent()117*03ce13f7SAndroid Build Coastguard Worker void Trace::endEvent() {
118*03ce13f7SAndroid Build Coastguard Worker   if (stopped) {
119*03ce13f7SAndroid Build Coastguard Worker     return;
120*03ce13f7SAndroid Build Coastguard Worker   }
121*03ce13f7SAndroid Build Coastguard Worker   auto event = new EndEvent();
122*03ce13f7SAndroid Build Coastguard Worker   event->timestamp = timestamp();
123*03ce13f7SAndroid Build Coastguard Worker   put(event);
124*03ce13f7SAndroid Build Coastguard Worker }
125*03ce13f7SAndroid Build Coastguard Worker 
beginAsyncEvent(uint32_t id,const char * fmt,...)126*03ce13f7SAndroid Build Coastguard Worker void Trace::beginAsyncEvent(uint32_t id, const char* fmt, ...) {
127*03ce13f7SAndroid Build Coastguard Worker   if (stopped) {
128*03ce13f7SAndroid Build Coastguard Worker     return;
129*03ce13f7SAndroid Build Coastguard Worker   }
130*03ce13f7SAndroid Build Coastguard Worker   auto event = new AsyncStartEvent();
131*03ce13f7SAndroid Build Coastguard Worker 
132*03ce13f7SAndroid Build Coastguard Worker   va_list vararg;
133*03ce13f7SAndroid Build Coastguard Worker   va_start(vararg, fmt);
134*03ce13f7SAndroid Build Coastguard Worker   vsnprintf(event->name, Trace::MaxEventNameLength, fmt, vararg);
135*03ce13f7SAndroid Build Coastguard Worker   va_end(vararg);
136*03ce13f7SAndroid Build Coastguard Worker 
137*03ce13f7SAndroid Build Coastguard Worker   event->timestamp = timestamp();
138*03ce13f7SAndroid Build Coastguard Worker   event->id = id;
139*03ce13f7SAndroid Build Coastguard Worker   put(event);
140*03ce13f7SAndroid Build Coastguard Worker }
141*03ce13f7SAndroid Build Coastguard Worker 
endAsyncEvent(uint32_t id,const char * fmt,...)142*03ce13f7SAndroid Build Coastguard Worker void Trace::endAsyncEvent(uint32_t id, const char* fmt, ...) {
143*03ce13f7SAndroid Build Coastguard Worker   if (stopped) {
144*03ce13f7SAndroid Build Coastguard Worker     return;
145*03ce13f7SAndroid Build Coastguard Worker   }
146*03ce13f7SAndroid Build Coastguard Worker   auto event = new AsyncEndEvent();
147*03ce13f7SAndroid Build Coastguard Worker 
148*03ce13f7SAndroid Build Coastguard Worker   va_list vararg;
149*03ce13f7SAndroid Build Coastguard Worker   va_start(vararg, fmt);
150*03ce13f7SAndroid Build Coastguard Worker   vsnprintf(event->name, Trace::MaxEventNameLength, fmt, vararg);
151*03ce13f7SAndroid Build Coastguard Worker   va_end(vararg);
152*03ce13f7SAndroid Build Coastguard Worker 
153*03ce13f7SAndroid Build Coastguard Worker   event->timestamp = timestamp();
154*03ce13f7SAndroid Build Coastguard Worker   event->id = id;
155*03ce13f7SAndroid Build Coastguard Worker   put(event);
156*03ce13f7SAndroid Build Coastguard Worker }
157*03ce13f7SAndroid Build Coastguard Worker 
timestamp()158*03ce13f7SAndroid Build Coastguard Worker uint64_t Trace::timestamp() {
159*03ce13f7SAndroid Build Coastguard Worker   auto now = std::chrono::high_resolution_clock::now();
160*03ce13f7SAndroid Build Coastguard Worker   auto diff =
161*03ce13f7SAndroid Build Coastguard Worker       std::chrono::duration_cast<std::chrono::microseconds>(now - createdAt);
162*03ce13f7SAndroid Build Coastguard Worker   return static_cast<uint64_t>(diff.count());
163*03ce13f7SAndroid Build Coastguard Worker }
164*03ce13f7SAndroid Build Coastguard Worker 
put(Event * event)165*03ce13f7SAndroid Build Coastguard Worker void Trace::put(Event* event) {
166*03ce13f7SAndroid Build Coastguard Worker   auto idx = eventQueueWriteIdx++ % eventQueues.size();
167*03ce13f7SAndroid Build Coastguard Worker   auto& queue = eventQueues[idx];
168*03ce13f7SAndroid Build Coastguard Worker   std::unique_lock<std::mutex> lock(queue.mutex);
169*03ce13f7SAndroid Build Coastguard Worker   auto notify = queue.data.size() == 0;
170*03ce13f7SAndroid Build Coastguard Worker   queue.data.push(std::unique_ptr<Event>(event));
171*03ce13f7SAndroid Build Coastguard Worker   lock.unlock();
172*03ce13f7SAndroid Build Coastguard Worker   if (notify) {
173*03ce13f7SAndroid Build Coastguard Worker     queue.condition.notify_one();
174*03ce13f7SAndroid Build Coastguard Worker   }
175*03ce13f7SAndroid Build Coastguard Worker }
176*03ce13f7SAndroid Build Coastguard Worker 
take()177*03ce13f7SAndroid Build Coastguard Worker std::unique_ptr<Trace::Event> Trace::take() {
178*03ce13f7SAndroid Build Coastguard Worker   auto idx = eventQueueReadIdx++ % eventQueues.size();
179*03ce13f7SAndroid Build Coastguard Worker   auto& queue = eventQueues[idx];
180*03ce13f7SAndroid Build Coastguard Worker   std::unique_lock<std::mutex> lock(queue.mutex);
181*03ce13f7SAndroid Build Coastguard Worker   queue.condition.wait(lock, [&queue] { return queue.data.size() > 0; });
182*03ce13f7SAndroid Build Coastguard Worker   auto event = std::move(queue.data.front());
183*03ce13f7SAndroid Build Coastguard Worker   queue.data.pop();
184*03ce13f7SAndroid Build Coastguard Worker   return event;
185*03ce13f7SAndroid Build Coastguard Worker }
186*03ce13f7SAndroid Build Coastguard Worker 
187*03ce13f7SAndroid Build Coastguard Worker #define QUOTE(x) "\"" << x << "\""
188*03ce13f7SAndroid Build Coastguard Worker #define INDENT "  "
189*03ce13f7SAndroid Build Coastguard Worker 
Event()190*03ce13f7SAndroid Build Coastguard Worker Trace::Event::Event()
191*03ce13f7SAndroid Build Coastguard Worker     : threadID(std::hash<std::thread::id>()(std::this_thread::get_id())) {
192*03ce13f7SAndroid Build Coastguard Worker   if (auto fiber = Scheduler::Fiber::current()) {
193*03ce13f7SAndroid Build Coastguard Worker     fiberID = fiber->id;
194*03ce13f7SAndroid Build Coastguard Worker   }
195*03ce13f7SAndroid Build Coastguard Worker }
196*03ce13f7SAndroid Build Coastguard Worker 
write(std::ostream & out) const197*03ce13f7SAndroid Build Coastguard Worker void Trace::Event::write(std::ostream& out) const {
198*03ce13f7SAndroid Build Coastguard Worker   out << INDENT << QUOTE("name") << ": " << QUOTE(name) << "," << std::endl;
199*03ce13f7SAndroid Build Coastguard Worker   if (categories != nullptr) {
200*03ce13f7SAndroid Build Coastguard Worker     out << INDENT << QUOTE("cat") << ": "
201*03ce13f7SAndroid Build Coastguard Worker         << "\"";
202*03ce13f7SAndroid Build Coastguard Worker     auto first = true;
203*03ce13f7SAndroid Build Coastguard Worker     for (auto category = *categories; category != nullptr; category++) {
204*03ce13f7SAndroid Build Coastguard Worker       if (!first) {
205*03ce13f7SAndroid Build Coastguard Worker         out << ",";
206*03ce13f7SAndroid Build Coastguard Worker       }
207*03ce13f7SAndroid Build Coastguard Worker       out << category;
208*03ce13f7SAndroid Build Coastguard Worker     }
209*03ce13f7SAndroid Build Coastguard Worker     out << "\"," << std::endl;
210*03ce13f7SAndroid Build Coastguard Worker   }
211*03ce13f7SAndroid Build Coastguard Worker   if (fiberID != 0) {
212*03ce13f7SAndroid Build Coastguard Worker     out << INDENT << QUOTE("args") << ": "
213*03ce13f7SAndroid Build Coastguard Worker         << "{" << std::endl
214*03ce13f7SAndroid Build Coastguard Worker         << INDENT << INDENT << QUOTE("fiber") << ": " << fiberID << std::endl
215*03ce13f7SAndroid Build Coastguard Worker         << INDENT << "}," << std::endl;
216*03ce13f7SAndroid Build Coastguard Worker   }
217*03ce13f7SAndroid Build Coastguard Worker   if (threadID != 0) {
218*03ce13f7SAndroid Build Coastguard Worker     out << INDENT << QUOTE("tid") << ": " << threadFiberID(threadID, fiberID)
219*03ce13f7SAndroid Build Coastguard Worker         << "," << std::endl;
220*03ce13f7SAndroid Build Coastguard Worker   }
221*03ce13f7SAndroid Build Coastguard Worker   out << INDENT << QUOTE("ph") << ": " << QUOTE(static_cast<char>(type()))
222*03ce13f7SAndroid Build Coastguard Worker       << "," << std::endl
223*03ce13f7SAndroid Build Coastguard Worker       << INDENT << QUOTE("pid") << ": " << processID << "," << std::endl
224*03ce13f7SAndroid Build Coastguard Worker       << INDENT << QUOTE("ts") << ": " << timestamp << std::endl;
225*03ce13f7SAndroid Build Coastguard Worker }
226*03ce13f7SAndroid Build Coastguard Worker 
write(std::ostream & out) const227*03ce13f7SAndroid Build Coastguard Worker void Trace::NameThreadEvent::write(std::ostream& out) const {
228*03ce13f7SAndroid Build Coastguard Worker   out << INDENT << QUOTE("name") << ": " << QUOTE("thread_name") << ","
229*03ce13f7SAndroid Build Coastguard Worker       << std::endl
230*03ce13f7SAndroid Build Coastguard Worker       << INDENT << QUOTE("ph") << ": " << QUOTE("M") << "," << std::endl
231*03ce13f7SAndroid Build Coastguard Worker       << INDENT << QUOTE("pid") << ": " << processID << "," << std::endl
232*03ce13f7SAndroid Build Coastguard Worker       << INDENT << QUOTE("tid") << ": " << threadFiberID(threadID, fiberID)
233*03ce13f7SAndroid Build Coastguard Worker       << "," << std::endl
234*03ce13f7SAndroid Build Coastguard Worker       << INDENT << QUOTE("args") << ": {" << QUOTE("name") << ": "
235*03ce13f7SAndroid Build Coastguard Worker       << QUOTE(name) << "}" << std::endl;
236*03ce13f7SAndroid Build Coastguard Worker }
237*03ce13f7SAndroid Build Coastguard Worker 
write(std::ostream & out) const238*03ce13f7SAndroid Build Coastguard Worker void Trace::AsyncEvent::write(std::ostream& out) const {
239*03ce13f7SAndroid Build Coastguard Worker   out << INDENT << QUOTE("id") << ": " << QUOTE(id) << "," << std::endl
240*03ce13f7SAndroid Build Coastguard Worker       << INDENT << QUOTE("cat") << ": " << QUOTE("async") << "," << std::endl;
241*03ce13f7SAndroid Build Coastguard Worker   Event::write(out);
242*03ce13f7SAndroid Build Coastguard Worker }
243*03ce13f7SAndroid Build Coastguard Worker 
244*03ce13f7SAndroid Build Coastguard Worker }  // namespace marl
245*03ce13f7SAndroid Build Coastguard Worker 
246*03ce13f7SAndroid Build Coastguard Worker #endif  // MARL_TRACE_ENABLED