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 event_queue_[head_].trace_token = trace_token; 69 event_queue_[head_].event_type = event_type; 70 event_queue_[head_].module = module; 71 event_queue_[head_].trace_id = trace_id; 72 event_queue_[head_].flags = flags; 73 event_queue_[head_].data_size = data_size; 74 for (size_t i = 0; i < data_size; i++) { 75 event_queue_[head_].data_buffer[i] = 76 reinterpret_cast<const std::byte*>(data_buffer)[i]; 77 } 78 head_ = (head_ + 1) % kSize; 79 is_empty_ = false; 80 return pw::OkStatus(); 81 } 82 PeekFront()83 const volatile QueueEventBlock* PeekFront() const { 84 if (IsEmpty()) { 85 return nullptr; 86 } 87 return &event_queue_[tail_]; 88 } 89 PopFront()90 void PopFront() { 91 if (!IsEmpty()) { 92 tail_ = (tail_ + 1) % kSize; 93 is_empty_ = (tail_ == head_); 94 } 95 } 96 Clear()97 void Clear() { 98 head_ = 0; 99 tail_ = 0; 100 is_empty_ = true; 101 } 102 IsEmpty()103 bool IsEmpty() const { return is_empty_; } IsFull()104 bool IsFull() const { return !is_empty_ && (head_ == tail_); } 105 106 private: 107 std::array<volatile QueueEventBlock, kSize> event_queue_; 108 volatile size_t head_ = 0; // Next write 109 volatile size_t tail_ = 0; // Next read 110 volatile bool is_empty_ = 111 true; // Used to distinquish if head==tail is empty or full 112 }; 113 114 } // namespace internal 115 116 class TokenizedTraceImpl { 117 public: Enable(bool enable)118 void Enable(bool enable) { 119 if (enable != enabled_ && enable) { 120 event_queue_.Clear(); 121 } 122 enabled_ = enable; 123 } IsEnabled()124 bool IsEnabled() const { return enabled_; } 125 126 void HandleTraceEvent(uint32_t trace_token, 127 EventType event_type, 128 const char* module, 129 uint32_t trace_id, 130 uint8_t flags, 131 const void* data_buffer, 132 size_t data_size); 133 134 private: 135 using TraceQueue = internal::TraceQueue<PW_TRACE_QUEUE_SIZE_EVENTS>; 136 PW_TRACE_TIME_TYPE last_trace_time_ = 0; 137 bool enabled_ = false; 138 TraceQueue event_queue_; 139 140 void HandleNextItemInQueue( 141 const volatile TraceQueue::QueueEventBlock* event_block); 142 }; 143 144 // A singleton object of the TokenizedTraceImpl class which can be used to 145 // interface with trace using the C++ API. 146 // Example: pw::trace::TokenizedTrace::Instance().Enable(true); 147 class TokenizedTrace { 148 public: Instance()149 static TokenizedTraceImpl& Instance() { return instance_; }; 150 151 private: 152 static TokenizedTraceImpl instance_; 153 }; 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