xref: /aosp_15_r20/external/pigweed/pw_trace_tokenized/trace.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 //==============================================================================
15 //
16 
17 #include "pw_trace/trace.h"
18 
19 #include "pw_preprocessor/util.h"
20 #include "pw_trace_tokenized/trace_callback.h"
21 #include "pw_trace_tokenized/trace_tokenized.h"
22 #include "pw_varint/varint.h"
23 
24 namespace pw {
25 namespace trace {
26 
GetCallbacks()27 Callbacks& GetCallbacks() {
28   static Callbacks callbacks;
29   return callbacks;
30 }
31 
GetTokenizedTracer()32 TokenizedTracer& GetTokenizedTracer() {
33   static TokenizedTracer tokenized_tracer(GetCallbacks());
34   return tokenized_tracer;
35 }
36 
37 using TraceEvent = pw_trace_tokenized_TraceEvent;
38 
HandleTraceEvent(uint32_t trace_token,EventType event_type,const char * module,uint32_t trace_id,uint8_t flags,const void * data_buffer,size_t data_size)39 void TokenizedTracer::HandleTraceEvent(uint32_t trace_token,
40                                        EventType event_type,
41                                        const char* module,
42                                        uint32_t trace_id,
43                                        uint8_t flags,
44                                        const void* data_buffer,
45                                        size_t data_size) {
46   // Early exit if disabled and no callbacks are register to receive events
47   // while disabled.
48   if (!enabled_ && callbacks_.GetCalledOnEveryEventCount() == 0) {
49     return;
50   }
51 
52   TraceEvent event = {
53       .trace_token = trace_token,
54       .event_type = event_type,
55       .module = module,
56       .flags = flags,
57       .trace_id = trace_id,
58       .data_size = data_size,
59       .data_buffer = data_buffer,
60   };
61 
62   // Call any event callback which is registered to receive every event.
63   pw_trace_TraceEventReturnFlags ret_flags = 0;
64   ret_flags |=
65       callbacks_.CallEventCallbacks(Callbacks::kCallOnEveryEvent, &event);
66   // Return if disabled.
67   if ((PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT & ret_flags) || !enabled_) {
68     return;
69   }
70 
71   // Call any event callback not already called.
72   ret_flags |=
73       callbacks_.CallEventCallbacks(Callbacks::kCallOnlyWhenEnabled, &event);
74   // Return if disabled (from a callback) or if a callback has indicated the
75   // sample should be skipped.
76   if ((PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT & ret_flags) || !enabled_) {
77     return;
78   }
79 
80   // Create trace event
81   PW_TRACE_QUEUE_LOCK();
82   if (!event_queue_
83            .TryPushBack(event.trace_token,
84                         event.event_type,
85                         event.module,
86                         event.trace_id,
87                         event.flags,
88                         event.data_buffer,
89                         event.data_size)
90            .ok()) {
91     // Queue full dropping sample
92     // TODO(rgoliver): Allow other strategies, for example: drop oldest, try
93     // empty queue, or block.
94   }
95   PW_TRACE_QUEUE_UNLOCK();
96 
97   // Sample is now in queue (if not dropped), try to empty the queue if not
98   // already being emptied.
99   if (PW_TRACE_TRY_LOCK()) {
100     while (!event_queue_.IsEmpty()) {
101       HandleNextItemInQueue(event_queue_.PeekFront());
102       event_queue_.PopFront();
103     }
104     PW_TRACE_UNLOCK();
105   }
106 
107   // Disable after processing if an event callback had set the flag.
108   if (PW_TRACE_EVENT_RETURN_FLAGS_DISABLE_AFTER_PROCESSING & ret_flags) {
109     enabled_ = false;
110   }
111 }
112 
HandleNextItemInQueue(const volatile TraceQueue::QueueEventBlock * event_block)113 void TokenizedTracer::HandleNextItemInQueue(
114     const volatile TraceQueue::QueueEventBlock* event_block) {
115   // Get next item in queue
116   uint32_t trace_token = event_block->trace_token;
117   EventType event_type = event_block->event_type;
118   uint32_t trace_id = event_block->trace_id;
119   const std::byte* data_buffer =
120       const_cast<const std::byte*>(event_block->data_buffer);
121   size_t data_size = event_block->data_size;
122 
123   // Create header to store trace info
124   static constexpr size_t kMaxHeaderSize =
125       sizeof(trace_token) + pw::varint::kMaxVarint64SizeBytes +  // time
126       pw::varint::kMaxVarint64SizeBytes;                         // trace_id
127   std::byte header[kMaxHeaderSize];
128   memcpy(header, &trace_token, sizeof(trace_token));
129   size_t header_size = sizeof(trace_token);
130 
131   // Compute delta of time elapsed since last trace entry.
132   PW_TRACE_TIME_TYPE trace_time = pw_trace_GetTraceTime();
133   PW_TRACE_TIME_TYPE delta =
134       (last_trace_time_ == 0)
135           ? 0
136           : PW_TRACE_GET_TIME_DELTA(last_trace_time_, trace_time);
137   header_size += pw::varint::Encode(
138       delta,
139       span<std::byte>(&header[header_size], kMaxHeaderSize - header_size));
140   last_trace_time_ = trace_time;
141 
142   // Calculate packet id if needed.
143   if (PW_TRACE_HAS_TRACE_ID(event_type)) {
144     header_size += pw::varint::Encode(
145         trace_id,
146         span<std::byte>(&header[header_size], kMaxHeaderSize - header_size));
147   }
148 
149   // Send encoded output to any registered trace sinks.
150   callbacks_.CallSinks(
151       span<const std::byte>(header, header_size),
152       span<const std::byte>(reinterpret_cast<const std::byte*>(data_buffer),
153                             data_size));
154 }
155 
CallEventCallbacks(CallOnEveryEvent called_on_every_event,TraceEvent * event)156 pw_trace_TraceEventReturnFlags Callbacks::CallEventCallbacks(
157     CallOnEveryEvent called_on_every_event, TraceEvent* event) {
158   pw_trace_TraceEventReturnFlags ret_flags = 0;
159   for (size_t i = 0; i < PW_TRACE_CONFIG_MAX_EVENT_CALLBACKS; i++) {
160     if (event_callbacks_[i].callback &&
161         event_callbacks_[i].called_on_every_event == called_on_every_event) {
162       ret_flags |=
163           GetEventCallback(i)->callback(event_callbacks_[i].user_data, event);
164     }
165   }
166   return ret_flags;
167 }
168 
CallSinks(span<const std::byte> header,span<const std::byte> data)169 void Callbacks::CallSinks(span<const std::byte> header,
170                           span<const std::byte> data) {
171   for (size_t sink_idx = 0; sink_idx < PW_TRACE_CONFIG_MAX_SINKS; sink_idx++) {
172     void* user_data = sink_callbacks_[sink_idx].user_data;
173     if (sink_callbacks_[sink_idx].start_block) {
174       sink_callbacks_[sink_idx].start_block(user_data,
175                                             header.size() + data.size());
176     }
177     if (sink_callbacks_[sink_idx].add_bytes) {
178       sink_callbacks_[sink_idx].add_bytes(
179           user_data, header.data(), header.size());
180       if (!data.empty()) {
181         sink_callbacks_[sink_idx].add_bytes(
182             user_data, data.data(), data.size());
183       }
184     }
185     if (sink_callbacks_[sink_idx].end_block) {
186       sink_callbacks_[sink_idx].end_block(user_data);
187     }
188   }
189 }
190 
RegisterSink(SinkStartBlock start_func,SinkAddBytes add_bytes_func,SinkEndBlock end_block_func,void * user_data,SinkHandle * handle)191 pw::Status Callbacks::RegisterSink(SinkStartBlock start_func,
192                                    SinkAddBytes add_bytes_func,
193                                    SinkEndBlock end_block_func,
194                                    void* user_data,
195                                    SinkHandle* handle) {
196   pw_Status status = PW_STATUS_RESOURCE_EXHAUSTED;
197   PW_TRACE_LOCK();
198   for (size_t sink_idx = 0; sink_idx < PW_TRACE_CONFIG_MAX_SINKS; sink_idx++) {
199     if (IsSinkFree(sink_idx)) {
200       sink_callbacks_[sink_idx].start_block = start_func;
201       sink_callbacks_[sink_idx].add_bytes = add_bytes_func;
202       sink_callbacks_[sink_idx].end_block = end_block_func;
203       sink_callbacks_[sink_idx].user_data = user_data;
204       if (handle) {
205         *handle = sink_idx;
206       }
207       status = PW_STATUS_OK;
208       break;
209     }
210   }
211   PW_TRACE_UNLOCK();
212   return status;
213 }
214 
UnregisterSink(SinkHandle handle)215 pw::Status Callbacks::UnregisterSink(SinkHandle handle) {
216   PW_TRACE_LOCK();
217   if (handle >= PW_TRACE_CONFIG_MAX_SINKS) {
218     return PW_STATUS_INVALID_ARGUMENT;
219   }
220   sink_callbacks_[handle].start_block = nullptr;
221   sink_callbacks_[handle].add_bytes = nullptr;
222   sink_callbacks_[handle].end_block = nullptr;
223   PW_TRACE_UNLOCK();
224   return PW_STATUS_OK;
225 }
226 
UnregisterAllSinks()227 pw::Status Callbacks::UnregisterAllSinks() {
228   for (size_t sink_idx = 0; sink_idx < PW_TRACE_CONFIG_MAX_SINKS; sink_idx++) {
229     UnregisterSink(sink_idx)
230         .IgnoreError();  // TODO: b/242598609 - Handle Status properly
231   }
232   return PW_STATUS_OK;
233 }
234 
GetSink(SinkHandle handle)235 Callbacks::SinkCallbacks* Callbacks::GetSink(SinkHandle handle) {
236   if (handle >= PW_TRACE_CONFIG_MAX_EVENT_CALLBACKS) {
237     return nullptr;
238   }
239   return &sink_callbacks_[handle];
240 }
241 
RegisterEventCallback(EventCallback callback,CallOnEveryEvent called_on_every_event,void * user_data,EventCallbackHandle * handle)242 pw::Status Callbacks::RegisterEventCallback(
243     EventCallback callback,
244     CallOnEveryEvent called_on_every_event,
245     void* user_data,
246     EventCallbackHandle* handle) {
247   pw_Status status = PW_STATUS_RESOURCE_EXHAUSTED;
248   PW_TRACE_LOCK();
249   for (size_t i = 0; i < PW_TRACE_CONFIG_MAX_EVENT_CALLBACKS; i++) {
250     if (event_callbacks_[i].callback == nullptr) {
251       event_callbacks_[i].callback = callback;
252       event_callbacks_[i].user_data = user_data;
253       event_callbacks_[i].called_on_every_event = called_on_every_event;
254       called_on_every_event_count_ += called_on_every_event ? 1 : 0;
255       if (handle) {
256         *handle = i;
257       }
258       status = PW_STATUS_OK;
259       break;
260     }
261   }
262   PW_TRACE_UNLOCK();
263   return status;
264 }
265 
UnregisterEventCallback(EventCallbackHandle handle)266 pw::Status Callbacks::UnregisterEventCallback(EventCallbackHandle handle) {
267   PW_TRACE_LOCK();
268   if (handle >= PW_TRACE_CONFIG_MAX_EVENT_CALLBACKS) {
269     return PW_STATUS_INVALID_ARGUMENT;
270   }
271   event_callbacks_[handle].callback = nullptr;
272   event_callbacks_[handle].user_data = nullptr;
273   called_on_every_event_count_ +=
274       event_callbacks_[handle].called_on_every_event ? 1 : 0;
275   event_callbacks_[handle].called_on_every_event = kCallOnlyWhenEnabled;
276   PW_TRACE_UNLOCK();
277   return PW_STATUS_OK;
278 }
279 
UnregisterAllEventCallbacks()280 pw::Status Callbacks::UnregisterAllEventCallbacks() {
281   for (size_t i = 0; i < PW_TRACE_CONFIG_MAX_EVENT_CALLBACKS; i++) {
282     UnregisterEventCallback(i)
283         .IgnoreError();  // TODO: b/242598609 - Handle Status properly
284   }
285   return PW_STATUS_OK;
286 }
287 
GetEventCallback(EventCallbackHandle handle)288 Callbacks::EventCallbacks* Callbacks::GetEventCallback(
289     EventCallbackHandle handle) {
290   if (handle >= PW_TRACE_CONFIG_MAX_EVENT_CALLBACKS) {
291     return nullptr;
292   }
293   return &event_callbacks_[handle];
294 }
295 
296 // C functions
297 
298 PW_EXTERN_C_START
299 
pw_trace_Enable(bool enable)300 void pw_trace_Enable(bool enable) { GetTokenizedTracer().Enable(enable); }
301 
pw_trace_IsEnabled()302 bool pw_trace_IsEnabled() { return GetTokenizedTracer().IsEnabled(); }
303 
pw_trace_TraceEvent(uint32_t trace_token,pw_trace_EventType event_type,const char * module,uint32_t trace_id,uint8_t flags,const void * data_buffer,size_t data_size)304 void pw_trace_TraceEvent(uint32_t trace_token,
305                          pw_trace_EventType event_type,
306                          const char* module,
307                          uint32_t trace_id,
308                          uint8_t flags,
309                          const void* data_buffer,
310                          size_t data_size) {
311   GetTokenizedTracer().HandleTraceEvent(
312       trace_token, event_type, module, trace_id, flags, data_buffer, data_size);
313 }
314 
pw_trace_RegisterSink(pw_trace_SinkStartBlock start_func,pw_trace_SinkAddBytes add_bytes_func,pw_trace_SinkEndBlock end_block_func,void * user_data,pw_trace_SinkHandle * handle)315 pw_Status pw_trace_RegisterSink(pw_trace_SinkStartBlock start_func,
316                                 pw_trace_SinkAddBytes add_bytes_func,
317                                 pw_trace_SinkEndBlock end_block_func,
318                                 void* user_data,
319                                 pw_trace_SinkHandle* handle) {
320   return GetCallbacks()
321       .RegisterSink(
322           start_func, add_bytes_func, end_block_func, user_data, handle)
323       .code();
324 }
325 
pw_trace_UnregisterSink(pw_trace_EventCallbackHandle handle)326 pw_Status pw_trace_UnregisterSink(pw_trace_EventCallbackHandle handle) {
327   return GetCallbacks().UnregisterSink(handle).code();
328 }
329 
pw_trace_RegisterEventCallback(pw_trace_EventCallback callback,pw_trace_ShouldCallOnEveryEvent called_on_every_event,void * user_data,pw_trace_EventCallbackHandle * handle)330 pw_Status pw_trace_RegisterEventCallback(
331     pw_trace_EventCallback callback,
332     pw_trace_ShouldCallOnEveryEvent called_on_every_event,
333     void* user_data,
334     pw_trace_EventCallbackHandle* handle) {
335   return GetCallbacks()
336       .RegisterEventCallback(
337           callback,
338           static_cast<Callbacks::CallOnEveryEvent>(called_on_every_event),
339           user_data,
340           handle)
341       .code();
342 }
343 
pw_trace_UnregisterEventCallback(pw_trace_EventCallbackHandle handle)344 pw_Status pw_trace_UnregisterEventCallback(
345     pw_trace_EventCallbackHandle handle) {
346   return GetCallbacks().UnregisterEventCallback(handle).code();
347 }
348 
349 PW_EXTERN_C_END
350 
351 }  // namespace trace
352 }  // namespace pw
353