xref: /aosp_15_r20/external/perfetto/src/base/metatrace.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/metatrace.h"
18*6dbdd20aSAndroid Build Coastguard Worker 
19*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/compiler.h"
20*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/task_runner.h"
21*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/time.h"
22*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/file_utils.h"
23*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/thread_annotations.h"
24*6dbdd20aSAndroid Build Coastguard Worker 
25*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
26*6dbdd20aSAndroid Build Coastguard Worker namespace metatrace {
27*6dbdd20aSAndroid Build Coastguard Worker 
28*6dbdd20aSAndroid Build Coastguard Worker std::atomic<uint32_t> g_enabled_tags{0};
29*6dbdd20aSAndroid Build Coastguard Worker std::atomic<uint64_t> g_enabled_timestamp{0};
30*6dbdd20aSAndroid Build Coastguard Worker 
31*6dbdd20aSAndroid Build Coastguard Worker // static members
32*6dbdd20aSAndroid Build Coastguard Worker std::array<Record, RingBuffer::kCapacity> RingBuffer::records_;
33*6dbdd20aSAndroid Build Coastguard Worker std::atomic<bool> RingBuffer::read_task_queued_;
34*6dbdd20aSAndroid Build Coastguard Worker std::atomic<uint64_t> RingBuffer::wr_index_;
35*6dbdd20aSAndroid Build Coastguard Worker std::atomic<uint64_t> RingBuffer::rd_index_;
36*6dbdd20aSAndroid Build Coastguard Worker std::atomic<bool> RingBuffer::has_overruns_;
37*6dbdd20aSAndroid Build Coastguard Worker Record RingBuffer::bankruptcy_record_;
38*6dbdd20aSAndroid Build Coastguard Worker 
39*6dbdd20aSAndroid Build Coastguard Worker namespace {
40*6dbdd20aSAndroid Build Coastguard Worker 
41*6dbdd20aSAndroid Build Coastguard Worker // std::function<> is not trivially de/constructible. This struct wraps it in a
42*6dbdd20aSAndroid Build Coastguard Worker // heap-allocated struct to avoid static initializers.
43*6dbdd20aSAndroid Build Coastguard Worker struct Delegate {
GetInstanceperfetto::metatrace::__anon906ae12a0111::Delegate44*6dbdd20aSAndroid Build Coastguard Worker   static Delegate* GetInstance() {
45*6dbdd20aSAndroid Build Coastguard Worker     static Delegate* instance = new Delegate();
46*6dbdd20aSAndroid Build Coastguard Worker     return instance;
47*6dbdd20aSAndroid Build Coastguard Worker   }
48*6dbdd20aSAndroid Build Coastguard Worker 
49*6dbdd20aSAndroid Build Coastguard Worker   base::TaskRunner* task_runner = nullptr;
50*6dbdd20aSAndroid Build Coastguard Worker   std::function<void()> read_task;
51*6dbdd20aSAndroid Build Coastguard Worker };
52*6dbdd20aSAndroid Build Coastguard Worker 
53*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
54*6dbdd20aSAndroid Build Coastguard Worker 
Enable(std::function<void ()> read_task,base::TaskRunner * task_runner,uint32_t tags)55*6dbdd20aSAndroid Build Coastguard Worker bool Enable(std::function<void()> read_task,
56*6dbdd20aSAndroid Build Coastguard Worker             base::TaskRunner* task_runner,
57*6dbdd20aSAndroid Build Coastguard Worker             uint32_t tags) {
58*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(read_task);
59*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(task_runner->RunsTasksOnCurrentThread());
60*6dbdd20aSAndroid Build Coastguard Worker   if (g_enabled_tags.load(std::memory_order_acquire))
61*6dbdd20aSAndroid Build Coastguard Worker     return false;
62*6dbdd20aSAndroid Build Coastguard Worker 
63*6dbdd20aSAndroid Build Coastguard Worker   Delegate* dg = Delegate::GetInstance();
64*6dbdd20aSAndroid Build Coastguard Worker   dg->task_runner = task_runner;
65*6dbdd20aSAndroid Build Coastguard Worker   dg->read_task = std::move(read_task);
66*6dbdd20aSAndroid Build Coastguard Worker   RingBuffer::Reset();
67*6dbdd20aSAndroid Build Coastguard Worker   g_enabled_timestamp.store(TraceTimeNowNs(), std::memory_order_relaxed);
68*6dbdd20aSAndroid Build Coastguard Worker   g_enabled_tags.store(tags, std::memory_order_release);
69*6dbdd20aSAndroid Build Coastguard Worker   return true;
70*6dbdd20aSAndroid Build Coastguard Worker }
71*6dbdd20aSAndroid Build Coastguard Worker 
Disable()72*6dbdd20aSAndroid Build Coastguard Worker void Disable() {
73*6dbdd20aSAndroid Build Coastguard Worker   g_enabled_tags.store(0, std::memory_order_release);
74*6dbdd20aSAndroid Build Coastguard Worker   Delegate* dg = Delegate::GetInstance();
75*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(!dg->task_runner ||
76*6dbdd20aSAndroid Build Coastguard Worker                   dg->task_runner->RunsTasksOnCurrentThread());
77*6dbdd20aSAndroid Build Coastguard Worker   dg->task_runner = nullptr;
78*6dbdd20aSAndroid Build Coastguard Worker   dg->read_task = nullptr;
79*6dbdd20aSAndroid Build Coastguard Worker }
80*6dbdd20aSAndroid Build Coastguard Worker 
81*6dbdd20aSAndroid Build Coastguard Worker // static
Reset()82*6dbdd20aSAndroid Build Coastguard Worker void RingBuffer::Reset() {
83*6dbdd20aSAndroid Build Coastguard Worker   bankruptcy_record_.clear();
84*6dbdd20aSAndroid Build Coastguard Worker   for (Record& record : records_)
85*6dbdd20aSAndroid Build Coastguard Worker     record.clear();
86*6dbdd20aSAndroid Build Coastguard Worker   wr_index_ = 0;
87*6dbdd20aSAndroid Build Coastguard Worker   rd_index_ = 0;
88*6dbdd20aSAndroid Build Coastguard Worker   has_overruns_ = false;
89*6dbdd20aSAndroid Build Coastguard Worker   read_task_queued_ = false;
90*6dbdd20aSAndroid Build Coastguard Worker }
91*6dbdd20aSAndroid Build Coastguard Worker 
92*6dbdd20aSAndroid Build Coastguard Worker // static
AppendNewRecord()93*6dbdd20aSAndroid Build Coastguard Worker Record* RingBuffer::AppendNewRecord() {
94*6dbdd20aSAndroid Build Coastguard Worker   auto wr_index = wr_index_.fetch_add(1, std::memory_order_acq_rel);
95*6dbdd20aSAndroid Build Coastguard Worker 
96*6dbdd20aSAndroid Build Coastguard Worker   // rd_index can only monotonically increase, we don't care if we read an
97*6dbdd20aSAndroid Build Coastguard Worker   // older value, we'll just hit the slow-path a bit earlier if it happens.
98*6dbdd20aSAndroid Build Coastguard Worker   auto rd_index = rd_index_.load(std::memory_order_relaxed);
99*6dbdd20aSAndroid Build Coastguard Worker 
100*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DCHECK(wr_index >= rd_index);
101*6dbdd20aSAndroid Build Coastguard Worker   auto size = wr_index - rd_index;
102*6dbdd20aSAndroid Build Coastguard Worker   if (PERFETTO_LIKELY(size < kCapacity / 2))
103*6dbdd20aSAndroid Build Coastguard Worker     return At(wr_index);
104*6dbdd20aSAndroid Build Coastguard Worker 
105*6dbdd20aSAndroid Build Coastguard Worker   // Slow-path: Enqueue the read task and handle overruns.
106*6dbdd20aSAndroid Build Coastguard Worker   bool expected = false;
107*6dbdd20aSAndroid Build Coastguard Worker   if (RingBuffer::read_task_queued_.compare_exchange_strong(expected, true)) {
108*6dbdd20aSAndroid Build Coastguard Worker     Delegate* dg = Delegate::GetInstance();
109*6dbdd20aSAndroid Build Coastguard Worker     if (dg->task_runner) {
110*6dbdd20aSAndroid Build Coastguard Worker       dg->task_runner->PostTask([] {
111*6dbdd20aSAndroid Build Coastguard Worker         // Meta-tracing might have been disabled in the meantime.
112*6dbdd20aSAndroid Build Coastguard Worker         auto read_task = Delegate::GetInstance()->read_task;
113*6dbdd20aSAndroid Build Coastguard Worker         if (read_task)
114*6dbdd20aSAndroid Build Coastguard Worker           read_task();
115*6dbdd20aSAndroid Build Coastguard Worker         RingBuffer::read_task_queued_ = false;
116*6dbdd20aSAndroid Build Coastguard Worker       });
117*6dbdd20aSAndroid Build Coastguard Worker     }
118*6dbdd20aSAndroid Build Coastguard Worker   }
119*6dbdd20aSAndroid Build Coastguard Worker 
120*6dbdd20aSAndroid Build Coastguard Worker   if (PERFETTO_LIKELY(size < kCapacity))
121*6dbdd20aSAndroid Build Coastguard Worker     return At(wr_index);
122*6dbdd20aSAndroid Build Coastguard Worker 
123*6dbdd20aSAndroid Build Coastguard Worker   has_overruns_.store(true, std::memory_order_release);
124*6dbdd20aSAndroid Build Coastguard Worker   wr_index_.fetch_sub(1, std::memory_order_acq_rel);
125*6dbdd20aSAndroid Build Coastguard Worker 
126*6dbdd20aSAndroid Build Coastguard Worker   // In the case of overflows, threads will race writing on the same memory
127*6dbdd20aSAndroid Build Coastguard Worker   // location and TSan will rightly complain. This is fine though because nobody
128*6dbdd20aSAndroid Build Coastguard Worker   // will read the bankruptcy record and it's designed to contain garbage.
129*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(&bankruptcy_record_, sizeof(Record),
130*6dbdd20aSAndroid Build Coastguard Worker                                       "nothing reads bankruptcy_record_")
131*6dbdd20aSAndroid Build Coastguard Worker   return &bankruptcy_record_;
132*6dbdd20aSAndroid Build Coastguard Worker }
133*6dbdd20aSAndroid Build Coastguard Worker 
134*6dbdd20aSAndroid Build Coastguard Worker // static
IsOnValidTaskRunner()135*6dbdd20aSAndroid Build Coastguard Worker bool RingBuffer::IsOnValidTaskRunner() {
136*6dbdd20aSAndroid Build Coastguard Worker   auto* task_runner = Delegate::GetInstance()->task_runner;
137*6dbdd20aSAndroid Build Coastguard Worker   return task_runner && task_runner->RunsTasksOnCurrentThread();
138*6dbdd20aSAndroid Build Coastguard Worker }
139*6dbdd20aSAndroid Build Coastguard Worker 
140*6dbdd20aSAndroid Build Coastguard Worker }  // namespace metatrace
141*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
142