1 /*
2  * Copyright (C) 2020 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 #ifndef SRC_TRACE_PROCESSOR_TP_METATRACE_H_
18 #define SRC_TRACE_PROCESSOR_TP_METATRACE_H_
19 
20 #include <array>
21 #include <functional>
22 #include <vector>
23 
24 #include "perfetto/base/time.h"
25 #include "perfetto/ext/base/metatrace_events.h"
26 #include "perfetto/ext/base/string_view.h"
27 #include "perfetto/ext/base/thread_checker.h"
28 
29 // Trace processor maintains its own base implementation to avoid the
30 // threading and task runners which are required by base's metatracing.
31 // Moreover, this metatrace also adds support for args which is missing
32 // from base's metatracing.
33 // On the other hand, this implementation is not (currently) thread-safe
34 // and is likely less performant than base's implementation.
35 namespace perfetto {
36 namespace trace_processor {
37 namespace metatrace {
38 
39 // Stores whether meta-tracing is enabled.
40 extern bool g_enabled;
41 
TraceTimeNowNs()42 inline uint64_t TraceTimeNowNs() {
43   return static_cast<uint64_t>(base::GetBootTimeNs().count());
44 }
45 
46 struct Record {
47   // Timestamp since boot in ns.
48   uint64_t timestamp_ns;
49 
50   // Duration of the event.
51   uint32_t duration_ns;
52 
53   // The name of the event.
54   // This is assumed to be a static/long lived string.
55   const char* event_name;
56 
57   // Extra context for some types of events.
58   // This buffer is leaked once per record - every time a record is
59   // reused, the old memory is released and a new allocation is performed.
60   char* args_buffer = nullptr;
61   uint32_t args_buffer_size = 0;
62 
63   // Adds an arg to the record.
AddArgRecord64   void AddArg(base::StringView key, base::StringView value) {
65     size_t new_buffer_size = args_buffer_size + key.size() + value.size() + 2;
66     args_buffer = static_cast<char*>(realloc(args_buffer, new_buffer_size));
67 
68     memcpy(&args_buffer[args_buffer_size], key.data(), key.size());
69     args_buffer[args_buffer_size + key.size()] = '\0';
70     memcpy(&args_buffer[args_buffer_size + key.size() + 1], value.data(),
71            value.size());
72     args_buffer[new_buffer_size - 1] = '\0';
73 
74     args_buffer_size = static_cast<uint32_t>(new_buffer_size);
75   }
76 
AddArgRecord77   void AddArg(base::StringView key, const std::string& value) {
78     AddArg(key, base::StringView(value));
79   }
80 };
81 
82 // Implementation of fixed-size ring buffer. The implementation of this
83 // class is modelled on the RingBuffer in metatrace.h of base but is different
84 // in a couple of ways:
85 //  1. This class is *not* thread safe.
86 //  2. The Record type stored in this class has the capability of storing
87 //     extra, event-specific context. For example, when tracing SQL query
88 //     execution, we store the query string.
89 //  3. The buffer is designed to be written continuously while meta-tracing
90 //     is enabled and read one-shot at the end of execution.
91 class RingBuffer {
92  public:
93   static constexpr uint32_t kCapacity = 256 * 1024;
94 
95   RingBuffer();
96   ~RingBuffer() = default;
97 
AppendRecord(const char * event_name)98   std::pair<uint64_t, Record*> AppendRecord(const char* event_name) {
99     PERFETTO_DCHECK_THREAD(thread_checker_);
100     PERFETTO_DCHECK(!is_reading_);
101 
102     uint64_t idx = write_idx_++;
103     Record* record = At(idx);
104     record->timestamp_ns = TraceTimeNowNs();
105     record->duration_ns = 0;
106     record->event_name = event_name;
107     record->args_buffer_size = 0;
108     return std::make_pair(idx, record);
109   }
110 
At(uint64_t idx)111   Record* At(uint64_t idx) { return &data_[idx % kCapacity]; }
112 
113   void ReadAll(std::function<void(Record*)>);
114 
GetInstance()115   static RingBuffer* GetInstance() {
116     static RingBuffer* rb = new RingBuffer();
117     return rb;
118   }
119 
IndexOf(Record * record)120   uint64_t IndexOf(Record* record) {
121     return static_cast<uint64_t>(std::distance(data_.data(), record));
122   }
123 
124   // Returns whether the record at the |index| has been overwritten because
125   // of wraps of the ring buffer.
HasOverwritten(uint64_t index)126   bool HasOverwritten(uint64_t index) { return index + kCapacity < write_idx_; }
127 
128  private:
129   bool is_reading_ = false;
130 
131   uint64_t start_idx_ = 0;
132   uint64_t write_idx_ = 0;
133   std::array<Record, kCapacity> data_;
134 
135   PERFETTO_THREAD_CHECKER(thread_checker_)
136 };
137 
138 class ScopedEvent {
139  public:
140   ScopedEvent() = default;
141 
~ScopedEvent()142   ~ScopedEvent() {
143     if (PERFETTO_LIKELY(!record_))
144       return;
145     if (RingBuffer::GetInstance()->HasOverwritten(record_idx_))
146       return;
147     auto now = TraceTimeNowNs();
148     record_->duration_ns = static_cast<uint32_t>(now - record_->timestamp_ns);
149   }
150 
ScopedEvent(ScopedEvent && value)151   ScopedEvent(ScopedEvent&& value) {
152     record_ = value.record_;
153     record_idx_ = value.record_idx_;
154     value.record_ = nullptr;
155   }
156 
157   template <typename Fn = void(Record*)>
158   static ScopedEvent Create(
159       const char* event_id,
160       Fn args_fn = [](Record*) {}) {
161     if (PERFETTO_LIKELY(!g_enabled))
162       return ScopedEvent();
163 
164     ScopedEvent event;
165     std::tie(event.record_idx_, event.record_) =
166         RingBuffer::GetInstance()->AppendRecord(event_id);
167     args_fn(event.record_);
168     return event;
169   }
170 
171  private:
172   ScopedEvent(const ScopedEvent&) = delete;
173   ScopedEvent& operator=(const ScopedEvent&) = delete;
174 
175   ScopedEvent& operator=(ScopedEvent&& value) = delete;
176 
177   Record* record_ = nullptr;
178   uint64_t record_idx_ = 0;
179 };
180 
181 // Enables meta-tracing of trace-processor.
182 void Enable();
183 
184 // Disables meta-tracing of trace-processor and reads all records.
185 void DisableAndReadBuffer(std::function<void(Record*)>);
186 
187 // Boilerplate to derive a unique variable name for the event.
188 #define PERFETTO_TP_METATRACE_UID2(a, b) a##b
189 #define PERFETTO_TP_METATRACE_UID(x) PERFETTO_TP_METATRACE_UID2(metatrace_, x)
190 
191 #define PERFETTO_TP_TRACE(...)                  \
192   auto PERFETTO_TP_METATRACE_UID(__COUNTER__) = \
193       ::perfetto::trace_processor::metatrace::ScopedEvent::Create(__VA_ARGS__)
194 
195 }  // namespace metatrace
196 }  // namespace trace_processor
197 }  // namespace perfetto
198 
199 #endif  // SRC_TRACE_PROCESSOR_TP_METATRACE_H_
200