xref: /aosp_15_r20/external/pigweed/pw_trace_tokenized/public/pw_trace_tokenized/trace_tokenized.h (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 // This file provides the interface for working with the tokenized trace
17 // backend.
18 
19 #pragma once
20 
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <string.h>
24 
25 #ifndef PW_TRACE_GET_TIME_DELTA
26 #ifdef __cplusplus
27 #include <type_traits>
28 #endif  // __cplusplus
29 #endif  // PW_TRACE_GET_TIME_DELTA
30 
31 #include "pw_status/status.h"
32 #include "pw_tokenizer/tokenize.h"
33 #include "pw_trace_tokenized/config.h"
34 #include "pw_trace_tokenized/internal/trace_tokenized_internal.h"
35 
36 #ifdef __cplusplus
37 namespace pw {
38 namespace trace {
39 
40 using EventType = pw_trace_EventType;
41 
42 namespace internal {
43 
44 // Simple ring buffer which is suitable for use in a critical section.
45 template <size_t kSize>
46 class TraceQueue {
47  public:
48   struct QueueEventBlock {
49     uint32_t trace_token;
50     EventType event_type;
51     const char* module;
52     uint32_t trace_id;
53     uint8_t flags;
54     size_t data_size;
55     std::byte data_buffer[PW_TRACE_BUFFER_MAX_DATA_SIZE_BYTES];
56   };
57 
TryPushBack(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)58   pw::Status TryPushBack(uint32_t trace_token,
59                          EventType event_type,
60                          const char* module,
61                          uint32_t trace_id,
62                          uint8_t flags,
63                          const void* data_buffer,
64                          size_t data_size) {
65     if (IsFull()) {
66       return pw::Status::ResourceExhausted();
67     }
68     if (data_size > PW_TRACE_BUFFER_MAX_DATA_SIZE_BYTES) {
69       return pw::Status::InvalidArgument();
70     }
71     event_queue_[head_].trace_token = trace_token;
72     event_queue_[head_].event_type = event_type;
73     event_queue_[head_].module = module;
74     event_queue_[head_].trace_id = trace_id;
75     event_queue_[head_].flags = flags;
76     event_queue_[head_].data_size = data_size;
77     for (size_t i = 0; i < data_size; i++) {
78       event_queue_[head_].data_buffer[i] =
79           reinterpret_cast<const std::byte*>(data_buffer)[i];
80     }
81     head_ = (head_ + 1) % kSize;
82     is_empty_ = false;
83     return pw::OkStatus();
84   }
85 
PeekFront()86   const volatile QueueEventBlock* PeekFront() const {
87     if (IsEmpty()) {
88       return nullptr;
89     }
90     return &event_queue_[tail_];
91   }
92 
PopFront()93   void PopFront() {
94     if (!IsEmpty()) {
95       tail_ = (tail_ + 1) % kSize;
96       is_empty_ = (tail_ == head_);
97     }
98   }
99 
Clear()100   void Clear() {
101     head_ = 0;
102     tail_ = 0;
103     is_empty_ = true;
104   }
105 
IsEmpty()106   bool IsEmpty() const { return is_empty_; }
IsFull()107   bool IsFull() const { return !is_empty_ && (head_ == tail_); }
108 
109  private:
110   std::array<volatile QueueEventBlock, kSize> event_queue_;
111   volatile size_t head_ = 0;  // Next write
112   volatile size_t tail_ = 0;  // Next read
113   volatile bool is_empty_ =
114       true;  // Used to distinquish if head==tail is empty or full
115 };
116 
117 }  // namespace internal
118 
119 // C++ API interfact to the tokenized tracer
120 // Example: pw::trace::GetTokenizedTracer().Enable(true);
121 class Callbacks;
122 class TokenizedTracer {
123  public:
TokenizedTracer(Callbacks & callbacks)124   TokenizedTracer(Callbacks& callbacks) : callbacks_(callbacks) {}
Enable(bool enable)125   void Enable(bool enable) {
126     if (enable != enabled_ && enable) {
127       event_queue_.Clear();
128     }
129     enabled_ = enable;
130   }
IsEnabled()131   bool IsEnabled() const { return enabled_; }
132 
133   void HandleTraceEvent(uint32_t trace_token,
134                         EventType event_type,
135                         const char* module,
136                         uint32_t trace_id,
137                         uint8_t flags,
138                         const void* data_buffer,
139                         size_t data_size);
140 
141  private:
142   using TraceQueue = internal::TraceQueue<PW_TRACE_QUEUE_SIZE_EVENTS>;
143   PW_TRACE_TIME_TYPE last_trace_time_ = 0;
144   bool enabled_ = false;
145   TraceQueue event_queue_;
146   Callbacks& callbacks_;
147 
148   void HandleNextItemInQueue(
149       const volatile TraceQueue::QueueEventBlock* event_block);
150 };
151 
152 // Returns a reference of the global tokenized tracer
153 TokenizedTracer& GetTokenizedTracer();
154 
155 }  // namespace trace
156 }  // namespace pw
157 #endif  // __cplusplus
158 
159 // PW_TRACE_SET_ENABLED is used to enable or disable tracing.
160 #define PW_TRACE_SET_ENABLED(enabled) pw_trace_Enable(enabled)
161 
162 // PW_TRACE_REF provides the uint32_t token value for a specific trace event.
163 // this can be used in the callback to perform specific actions for that trace.
164 // All the fields must match exactly to generate the correct trace reference.
165 // If the trace does not have a group, use PW_TRACE_GROUP_LABEL_DEFAULT.
166 //
167 // For example this can be used to skip a specific trace:
168 //   pw_trace_TraceEventReturnFlags TraceEventCallback(
169 //       uint32_t trace_ref,
170 //       pw_trace_EventType event_type,
171 //       const char* module,
172 //       uint32_t trace_id,
173 //       uint8_t flags) {
174 //     auto skip_trace_ref = PW_TRACE_REF(PW_TRACE_TYPE_INSTANT,
175 //                                        "test_module",    // Module
176 //                                        "test_label",     // Label
177 //                                        PW_TRACE_FLAGS_DEFAULT,
178 //                                        PW_TRACE_GROUP_LABEL_DEFAULT);
179 //     if (trace_ref == skip_trace_ref) {
180 //       return PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT;
181 //     }
182 //     return 0;
183 //   }
184 //
185 // The above trace ref would provide the tokenize value for the string:
186 //     "1|0|test_module||test_label"
187 //
188 // Another example:
189 //    #define PW_TRACE_MODULE test_module
190 //    PW_TRACE_INSTANT_DATA_FLAG(2, "label", "group", id, "%d", 5, 1);
191 // Would internally generate a token value for the string:
192 //    "1|2|test_module|group|label|%d"
193 // The trace_id, and data value are runtime values and not included in the
194 // token string.
195 #define PW_TRACE_REF(event_type, module, label, flags, group)          \
196   PW_TOKENIZE_STRING_DOMAIN("trace",                                   \
197                             PW_STRINGIFY(event_type) "|" PW_STRINGIFY( \
198                                 flags) "|" module "|" group "|" label)
199 
200 #define PW_TRACE_REF_DATA(event_type, module, label, flags, group, type)    \
201   PW_TOKENIZE_STRING_DOMAIN(                                                \
202       "trace",                                                              \
203       PW_STRINGIFY(event_type) "|" PW_STRINGIFY(flags) "|" module "|" group \
204                                                        "|" label "|" type)
205