1*6dbdd20aSAndroid Build Coastguard Worker /* 2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project 3*6dbdd20aSAndroid Build Coastguard Worker * 4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*6dbdd20aSAndroid Build Coastguard Worker * 8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*6dbdd20aSAndroid Build Coastguard Worker * 10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License. 15*6dbdd20aSAndroid Build Coastguard Worker */ 16*6dbdd20aSAndroid Build Coastguard Worker 17*6dbdd20aSAndroid Build Coastguard Worker #ifndef SRC_BASE_LOG_RING_BUFFER_H_ 18*6dbdd20aSAndroid Build Coastguard Worker #define SRC_BASE_LOG_RING_BUFFER_H_ 19*6dbdd20aSAndroid Build Coastguard Worker 20*6dbdd20aSAndroid Build Coastguard Worker #include <stddef.h> 21*6dbdd20aSAndroid Build Coastguard Worker #include <stdio.h> 22*6dbdd20aSAndroid Build Coastguard Worker 23*6dbdd20aSAndroid Build Coastguard Worker #include <array> 24*6dbdd20aSAndroid Build Coastguard Worker #include <atomic> 25*6dbdd20aSAndroid Build Coastguard Worker 26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_view.h" 27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/thread_annotations.h" 28*6dbdd20aSAndroid Build Coastguard Worker 29*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto { 30*6dbdd20aSAndroid Build Coastguard Worker namespace base { 31*6dbdd20aSAndroid Build Coastguard Worker 32*6dbdd20aSAndroid Build Coastguard Worker // Defined out of line because a static constexpr requires static storage if 33*6dbdd20aSAndroid Build Coastguard Worker // ODR-used, not worth adding a .cc file just for tests. 34*6dbdd20aSAndroid Build Coastguard Worker constexpr size_t kLogRingBufEntries = 8; 35*6dbdd20aSAndroid Build Coastguard Worker constexpr size_t kLogRingBufMsgLen = 256; 36*6dbdd20aSAndroid Build Coastguard Worker 37*6dbdd20aSAndroid Build Coastguard Worker // A static non-allocating ring-buffer to hold the most recent log events. 38*6dbdd20aSAndroid Build Coastguard Worker // This class is really an implementation detail of logging.cc. The only reason 39*6dbdd20aSAndroid Build Coastguard Worker // why is fully defined in a dedicated header is for allowing unittesting, 40*6dbdd20aSAndroid Build Coastguard Worker // without leaking extra headers into logging.h (which is a high-fanout header). 41*6dbdd20aSAndroid Build Coastguard Worker // This is used to report the last logs in a crash report when a CHECK/FATAL 42*6dbdd20aSAndroid Build Coastguard Worker // is encountered. 43*6dbdd20aSAndroid Build Coastguard Worker // This class has just an Append() method to insert events into the buffer and 44*6dbdd20aSAndroid Build Coastguard Worker // a Read() to read the events in FIFO order. Read() is non-destructive. 45*6dbdd20aSAndroid Build Coastguard Worker // 46*6dbdd20aSAndroid Build Coastguard Worker // Thread safety considerations: 47*6dbdd20aSAndroid Build Coastguard Worker // - The Append() method can be called concurrently by several threads, unless 48*6dbdd20aSAndroid Build Coastguard Worker // there are > kLogRingBufEntries concurrent threads. Even if that happens, 49*6dbdd20aSAndroid Build Coastguard Worker // case some events will contain a mix of strings but the behavior of 50*6dbdd20aSAndroid Build Coastguard Worker // futher Append() and Read() is still defined. 51*6dbdd20aSAndroid Build Coastguard Worker // - The Read() method is not thread safe but it's fine in practice. Even if 52*6dbdd20aSAndroid Build Coastguard Worker // it's called concurrently with other Append(), it only causes some partial 53*6dbdd20aSAndroid Build Coastguard Worker // events to be emitted in output. 54*6dbdd20aSAndroid Build Coastguard Worker // In both cases, we never rely purely on \0, all operations are size-bound. 55*6dbdd20aSAndroid Build Coastguard Worker // 56*6dbdd20aSAndroid Build Coastguard Worker // See logging_unittest.cc for tests. 57*6dbdd20aSAndroid Build Coastguard Worker class LogRingBuffer { 58*6dbdd20aSAndroid Build Coastguard Worker public: 59*6dbdd20aSAndroid Build Coastguard Worker LogRingBuffer() = default; 60*6dbdd20aSAndroid Build Coastguard Worker LogRingBuffer(const LogRingBuffer&) = delete; 61*6dbdd20aSAndroid Build Coastguard Worker LogRingBuffer& operator=(const LogRingBuffer&) = delete; 62*6dbdd20aSAndroid Build Coastguard Worker LogRingBuffer(LogRingBuffer&&) = delete; 63*6dbdd20aSAndroid Build Coastguard Worker LogRingBuffer& operator=(LogRingBuffer&&) = delete; 64*6dbdd20aSAndroid Build Coastguard Worker 65*6dbdd20aSAndroid Build Coastguard Worker // This takes three arguments because it fits its only caller (logging.cc). 66*6dbdd20aSAndroid Build Coastguard Worker // The args are just concatenated together (plus one space before the msg). Append(StringView tstamp,StringView source,StringView log_msg)67*6dbdd20aSAndroid Build Coastguard Worker void Append(StringView tstamp, StringView source, StringView log_msg) { 68*6dbdd20aSAndroid Build Coastguard Worker // Reserve atomically a slot in the ring buffer, so any concurrent Append() 69*6dbdd20aSAndroid Build Coastguard Worker // won't overlap (unless too many concurrent Append() happen together). 70*6dbdd20aSAndroid Build Coastguard Worker // There is no strict synchronization here, |event_slot_| is atomic only for 71*6dbdd20aSAndroid Build Coastguard Worker // the sake of avoiding colliding on the same slot but does NOT guarantee 72*6dbdd20aSAndroid Build Coastguard Worker // full consistency and integrity of the log messages written in each slot. 73*6dbdd20aSAndroid Build Coastguard Worker // A release-store (or acq+rel) won't be enough for full consistency. Two 74*6dbdd20aSAndroid Build Coastguard Worker // threads that race on Append() and take the N+1 and N+2 slots could finish 75*6dbdd20aSAndroid Build Coastguard Worker // the write in reverse order. So Read() would need to synchronize with 76*6dbdd20aSAndroid Build Coastguard Worker // something else (either a per-slot atomic flag or with a second atomic 77*6dbdd20aSAndroid Build Coastguard Worker // counter which is incremented after the snprintf). Both options increase 78*6dbdd20aSAndroid Build Coastguard Worker // the cost of Append() with no huge benefits (90% of the perfetto services 79*6dbdd20aSAndroid Build Coastguard Worker // where we use it is single thread, and the log ring buffer is disabled 80*6dbdd20aSAndroid Build Coastguard Worker // on non-standalone builds like the SDK). 81*6dbdd20aSAndroid Build Coastguard Worker uint32_t slot = event_slot_.fetch_add(1, std::memory_order_relaxed); 82*6dbdd20aSAndroid Build Coastguard Worker slot = slot % kLogRingBufEntries; 83*6dbdd20aSAndroid Build Coastguard Worker 84*6dbdd20aSAndroid Build Coastguard Worker char* const msg = events_[slot]; 85*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(msg, kLogRingBufMsgLen, 86*6dbdd20aSAndroid Build Coastguard Worker "see comments in log_ring_buffer.h") 87*6dbdd20aSAndroid Build Coastguard Worker snprintf(msg, kLogRingBufMsgLen, "%.*s%.*s %.*s", 88*6dbdd20aSAndroid Build Coastguard Worker static_cast<int>(tstamp.size()), tstamp.data(), 89*6dbdd20aSAndroid Build Coastguard Worker static_cast<int>(source.size()), source.data(), 90*6dbdd20aSAndroid Build Coastguard Worker static_cast<int>(log_msg.size()), log_msg.data()); 91*6dbdd20aSAndroid Build Coastguard Worker } 92*6dbdd20aSAndroid Build Coastguard Worker 93*6dbdd20aSAndroid Build Coastguard Worker // Reads back the buffer in FIFO order, up to |len - 1| characters at most 94*6dbdd20aSAndroid Build Coastguard Worker // (the -1 is because a NUL terminator is always appended, unless |len| == 0). 95*6dbdd20aSAndroid Build Coastguard Worker // The string written in |dst| is guaranteed to be NUL-terminated, even if 96*6dbdd20aSAndroid Build Coastguard Worker // |len| < buffer contents length. 97*6dbdd20aSAndroid Build Coastguard Worker // Returns the number of bytes written in output, excluding the \0 terminator. Read(char * dst,size_t len)98*6dbdd20aSAndroid Build Coastguard Worker size_t Read(char* dst, size_t len) { 99*6dbdd20aSAndroid Build Coastguard Worker if (len == 0) 100*6dbdd20aSAndroid Build Coastguard Worker return 0; 101*6dbdd20aSAndroid Build Coastguard Worker // This is a relaxed-load because we don't need to fully synchronize on the 102*6dbdd20aSAndroid Build Coastguard Worker // writing path for the reasons described in the fetch_add() above. 103*6dbdd20aSAndroid Build Coastguard Worker const uint32_t event_slot = event_slot_.load(std::memory_order_relaxed); 104*6dbdd20aSAndroid Build Coastguard Worker size_t dst_written = 0; 105*6dbdd20aSAndroid Build Coastguard Worker for (uint32_t pos = 0; pos < kLogRingBufEntries; ++pos) { 106*6dbdd20aSAndroid Build Coastguard Worker const uint32_t slot = (event_slot + pos) % kLogRingBufEntries; 107*6dbdd20aSAndroid Build Coastguard Worker const char* src = events_[slot]; 108*6dbdd20aSAndroid Build Coastguard Worker if (*src == '\0') 109*6dbdd20aSAndroid Build Coastguard Worker continue; // Empty slot. Skip. 110*6dbdd20aSAndroid Build Coastguard Worker char* const wptr = dst + dst_written; 111*6dbdd20aSAndroid Build Coastguard Worker // |src| might not be null terminated. This can happen if some 112*6dbdd20aSAndroid Build Coastguard Worker // thread-race happened. Limit the copy length. 113*6dbdd20aSAndroid Build Coastguard Worker const size_t limit = std::min(len - dst_written, kLogRingBufMsgLen); 114*6dbdd20aSAndroid Build Coastguard Worker for (size_t i = 0; i < limit; ++i) { 115*6dbdd20aSAndroid Build Coastguard Worker const char c = src[i]; 116*6dbdd20aSAndroid Build Coastguard Worker ++dst_written; 117*6dbdd20aSAndroid Build Coastguard Worker if (c == '\0' || i == limit - 1) { 118*6dbdd20aSAndroid Build Coastguard Worker wptr[i] = '\n'; 119*6dbdd20aSAndroid Build Coastguard Worker break; 120*6dbdd20aSAndroid Build Coastguard Worker } 121*6dbdd20aSAndroid Build Coastguard Worker // Skip non-printable ASCII characters to avoid confusing crash reports. 122*6dbdd20aSAndroid Build Coastguard Worker // Note that this deliberately mangles \n. Log messages should not have 123*6dbdd20aSAndroid Build Coastguard Worker // a \n in the middle and are NOT \n terminated. The trailing \n between 124*6dbdd20aSAndroid Build Coastguard Worker // each line is appended by the if () branch above. 125*6dbdd20aSAndroid Build Coastguard Worker const bool is_printable = c >= ' ' && c <= '~'; 126*6dbdd20aSAndroid Build Coastguard Worker wptr[i] = is_printable ? c : '?'; 127*6dbdd20aSAndroid Build Coastguard Worker } 128*6dbdd20aSAndroid Build Coastguard Worker } 129*6dbdd20aSAndroid Build Coastguard Worker // Ensure that the output string is null-terminated. 130*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(dst_written <= len); 131*6dbdd20aSAndroid Build Coastguard Worker if (dst_written == len) { 132*6dbdd20aSAndroid Build Coastguard Worker // In case of truncation we replace the last char with \0. But the return 133*6dbdd20aSAndroid Build Coastguard Worker // value is the number of chars without \0, hence the --. 134*6dbdd20aSAndroid Build Coastguard Worker dst[--dst_written] = '\0'; 135*6dbdd20aSAndroid Build Coastguard Worker } else { 136*6dbdd20aSAndroid Build Coastguard Worker dst[dst_written] = '\0'; 137*6dbdd20aSAndroid Build Coastguard Worker } 138*6dbdd20aSAndroid Build Coastguard Worker return dst_written; 139*6dbdd20aSAndroid Build Coastguard Worker } 140*6dbdd20aSAndroid Build Coastguard Worker 141*6dbdd20aSAndroid Build Coastguard Worker private: 142*6dbdd20aSAndroid Build Coastguard Worker using EventBuf = char[kLogRingBufMsgLen]; 143*6dbdd20aSAndroid Build Coastguard Worker EventBuf events_[kLogRingBufEntries]{}; 144*6dbdd20aSAndroid Build Coastguard Worker 145*6dbdd20aSAndroid Build Coastguard Worker static_assert((kLogRingBufEntries & (kLogRingBufEntries - 1)) == 0, 146*6dbdd20aSAndroid Build Coastguard Worker "kLogRingBufEntries must be a power of two"); 147*6dbdd20aSAndroid Build Coastguard Worker 148*6dbdd20aSAndroid Build Coastguard Worker // A monotonically increasing counter incremented on each event written. 149*6dbdd20aSAndroid Build Coastguard Worker // It determines which of the kLogRingBufEntries indexes in |events_| should 150*6dbdd20aSAndroid Build Coastguard Worker // be used next. 151*6dbdd20aSAndroid Build Coastguard Worker // It grows >> kLogRingBufEntries, it's supposed to be always used 152*6dbdd20aSAndroid Build Coastguard Worker // mod(kLogRingBufEntries). A static_assert in the .cc file ensures that 153*6dbdd20aSAndroid Build Coastguard Worker // kLogRingBufEntries is a power of two so wraps are aligned. 154*6dbdd20aSAndroid Build Coastguard Worker std::atomic<uint32_t> event_slot_{}; 155*6dbdd20aSAndroid Build Coastguard Worker }; 156*6dbdd20aSAndroid Build Coastguard Worker 157*6dbdd20aSAndroid Build Coastguard Worker } // namespace base 158*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto 159*6dbdd20aSAndroid Build Coastguard Worker 160*6dbdd20aSAndroid Build Coastguard Worker #endif // SRC_BASE_LOG_RING_BUFFER_H_ 161