FDR_LOG = 1,
};
+// FDR mode use of the union field in the XRayFileHeader.
+struct alignas(16) FdrAdditionalHeaderData {
+ uint64_t ThreadBufferSize;
+};
+
+static_assert(sizeof(FdrAdditionalHeaderData) == 16,
+ "FdrAdditionalHeaderData != 16 bytes");
+
// This data structure is used to describe the contents of the file. We use this
// for versioning the supported XRay file formats.
struct alignas(32) XRayFileHeader {
// The frequency by which TSC increases per-second.
alignas(8) uint64_t CycleFrequency = 0;
- // The current civiltime timestamp, as retrived from 'clock_gettime'. This
- // allows readers of the file to determine when the file was created or
- // written down.
- struct timespec TS;
+ union {
+ char FreeForm[16];
+ // The current civiltime timestamp, as retrived from 'clock_gettime'. This
+ // allows readers of the file to determine when the file was created or
+ // written down.
+ struct timespec TS;
+
+ struct FdrAdditionalHeaderData FdrData;
+ };
} __attribute__((packed));
static_assert(sizeof(XRayFileHeader) == 32, "XRayFileHeader != 32 bytes");
__sanitizer::memory_order_acquire);
}
+ /// Returns the configured size of the buffers in the buffer queue.
+ size_t ConfiguredBufferSize() const { return BufferSize; }
+
/// Sets the state of the BufferQueue to finalizing, which ensures that:
///
/// - All subsequent attempts to retrieve a Buffer will fail.
// before setting the values in the header.
Header.ConstantTSC = 1;
Header.NonstopTSC = 1;
- clock_gettime(CLOCK_REALTIME, &Header.TS);
+ Header.FdrData = FdrAdditionalHeaderData{LocalBQ->ConfiguredBufferSize()};
retryingWriteAll(Fd, reinterpret_cast<char *>(&Header),
reinterpret_cast<char *>(&Header) + sizeof(Header));
+
LocalBQ->apply([&](const BufferQueue::Buffer &B) {
- retryingWriteAll(Fd, reinterpret_cast<char *>(B.Buffer),
- reinterpret_cast<char *>(B.Buffer) + B.Size);
+ uint64_t BufferSize = B.Size;
+ if (BufferSize > 0) {
+ retryingWriteAll(Fd, reinterpret_cast<char *>(B.Buffer),
+ reinterpret_cast<char *>(B.Buffer) + B.Size);
+ }
});
__sanitizer::atomic_store(&LogFlushStatus,
XRayLogFlushStatus::XRAY_LOG_FLUSHED,
__sanitizer::atomic_sint32_t &LoggingStatus,
const std::shared_ptr<BufferQueue> &BQ) XRAY_NEVER_INSTRUMENT {
// Bail out right away if logging is not initialized yet.
- if (__sanitizer::atomic_load(&LoggingStatus,
- __sanitizer::memory_order_acquire) !=
- XRayLogInitStatus::XRAY_LOG_INITIALIZED)
+ // We should take the opportunity to release the buffer though.
+ auto Status = __sanitizer::atomic_load(&LoggingStatus,
+ __sanitizer::memory_order_acquire);
+ if (Status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) {
+ if (RecordPtr != nullptr &&
+ (Status == XRayLogInitStatus::XRAY_LOG_FINALIZING ||
+ Status == XRayLogInitStatus::XRAY_LOG_FINALIZED)) {
+ writeEOBMetadata();
+ auto EC = BQ->releaseBuffer(Buffer);
+ if (EC != BufferQueue::ErrorCode::Ok) {
+ Report("Failed to release buffer at %p; error=%s\n", Buffer.Buffer,
+ BufferQueue::getErrorString(EC));
+ return;
+ }
+ RecordPtr = nullptr;
+ }
return;
+ }
// We use a thread_local variable to keep track of which CPUs we've already
// run, and the TSC times for these CPUs. This allows us to stop repeating the