1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Buffer layout. 6 // This is an internal header between trace-engine and trace-provider. 7 // It may also be used by various tests. 8 9 #pragma once 10 11 #include <assert.h> 12 #include <stdint.h> 13 #include <trace-engine/context.h> 14 15 namespace trace { 16 namespace internal { 17 18 // This header provides framing information about the buffer, for use in 19 // implementing circular buffering and double(streaming) buffering. 20 // 21 // Writing to the buffer has conceptually three modes: 22 // oneshot, circular, streaming. 23 // 24 // Buffers are passed from Trace Manager to Trace Provider in vmos. 25 // How the buffer is treated depends on the writing mode. 26 // For "oneshot" mode the vmo is one big simple buffer. 27 // Using one big buffer means durable and non-durable records all share the 28 // same buffer. 29 // For simplicity in the code, oneshot mode uses rolling buffer 0. 30 // For "circular" and "streaming" buffering modes, the vmo is treated as a 31 // "virtual buffer" and is split into three logical parts: 32 // - one buffer for "durable" records 33 // - two buffers, labeled 0 and 1, for "non-durable" records, called 34 // "rolling buffers" 35 // Writing switches back and forth between the two rolling buffers as each 36 // fills. Streaming buffering differs from circular buffering in that the Trace 37 // Manager is involved in saving each rolling buffer as it fills. 38 // Besides consistency, a nice property of using two separate buffers for 39 // circular mode is that, because records are variable sized, there are no 40 // issues trying to find the "first" non-durable record in the complete virtual 41 // buffer after a wrap: It's always the first record of the other rolling 42 // buffer. 43 // 44 // To help preserve data integrity tracing stops when the durable buffer fills, 45 // even in circular mode. 46 // TODO(dje): Relax this restriction, and accept potentially more lost data. 47 // 48 // Durable records: 49 // - initialization record 50 // - string table 51 // - thread table 52 // TODO(dje): Move initialization record to header? 53 // 54 // Non-durable records: 55 // - everything else 56 // 57 // The total physical buffer is laid out as follows (without gaps): 58 // - header 59 // - durable buffer (empty in oneshot mode) 60 // - non-durable buffer 0 61 // - non-durable buffer 1 (empty in oneshot mode) 62 // 63 // It is an invariant that: 64 // oneshot: 65 // total_size == header + rolling_buffer_size 66 // circular/streaming: 67 // total_size == header + durable_buffer_size + 2 * rolling_buffer_size 68 // 69 // All buffer sizes must be a multiple of 8 as all records are a multiple of 8. 70 71 struct trace_buffer_header { 72 // Standard magic number field. 73 uint64_t magic; 74 #define TRACE_BUFFER_HEADER_MAGIC ((uint64_t) 0x627566ee68656164ull) 75 76 uint16_t version; 77 #define TRACE_BUFFER_HEADER_V0 ((uint16_t) 0) 78 79 // One of |trace_buffering_mode_t|. 80 uint8_t buffering_mode; 81 82 // For alignment and future concerns. 83 uint8_t reserved1; 84 85 // A count of the number of times writing wrapped. 86 // If zero then writing didn't wrap. If non-zero then |wrapped_count % 2| 87 // is the buffer number where writing finished. 88 uint32_t wrapped_count; 89 90 // The size of the buffer in bytes, including this header. 91 // In other words this is the size of the vmo. 92 uint64_t total_size; 93 94 // The size in bytes of the durable record buffer. 95 // This is zero in oneshot mode. 96 uint64_t durable_buffer_size; 97 98 // The size in bytes of each of the rolling record buffers. 99 uint64_t rolling_buffer_size; 100 101 // The offset, from the first data byte, to the end of recorded durable 102 // data. This starts at zero and is not written to while writing the buffer 103 // is active. This remains zero in oneshot mode (since there is no separate 104 // buffer for durable records). It is written to when the buffer fills or 105 // when tracing is stopped. 106 uint64_t durable_data_end; 107 108 // The offset, from the first data byte, to the end of recorded data. 109 // In oneshot mode only [0] is used. This starts at zero and is not written 110 // to while writing the buffer is active. It is written to when the buffer 111 // fills or when tracing is stopped. 112 uint64_t rolling_data_end[2]; 113 114 // Total number of records dropped thus far. 115 uint64_t num_records_dropped; 116 117 // The header is padded out to a size of 128 to provide room for growth, 118 // and to simplify internal buffer size calcs. 119 // The remainder of the header is reserved. 120 uint64_t reserved[7]; 121 }; 122 123 static_assert(sizeof(trace_buffer_header) == 128, ""); 124 125 } // namespace internal 126 } // namespace trace 127 128 // Update the buffer header and snapshot a copy of it. 129 // This is only intended to be used for testing purposes. 130 // 131 // This function is not thread-safe relative to the collected data, and 132 // assumes tracing is stopped or at least paused. 133 void trace_context_snapshot_buffer_header( 134 trace_prolonged_context_t* context, 135 ::trace::internal::trace_buffer_header* header); 136