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