Path: blob/main/contrib/llvm-project/compiler-rt/lib/xray/xray_fdr_log_writer.h
35263 views
//===-- xray_fdr_log_writer.h ---------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of XRay, a function call tracing system.9//10//===----------------------------------------------------------------------===//11#ifndef COMPILER_RT_LIB_XRAY_XRAY_FDR_LOG_WRITER_H_12#define COMPILER_RT_LIB_XRAY_XRAY_FDR_LOG_WRITER_H_1314#include "xray_buffer_queue.h"15#include "xray_fdr_log_records.h"16#include <functional>17#include <tuple>18#include <type_traits>19#include <utility>2021namespace __xray {2223template <size_t Index> struct SerializerImpl {24template <class Tuple,25typename std::enable_if<26Index<std::tuple_size<27typename std::remove_reference<Tuple>::type>::value,28int>::type = 0> static void serializeTo(char *Buffer,29Tuple &&T) {30auto P = reinterpret_cast<const char *>(&std::get<Index>(T));31constexpr auto Size = sizeof(std::get<Index>(T));32internal_memcpy(Buffer, P, Size);33SerializerImpl<Index + 1>::serializeTo(Buffer + Size,34std::forward<Tuple>(T));35}3637template <class Tuple,38typename std::enable_if<39Index >= std::tuple_size<typename std::remove_reference<40Tuple>::type>::value,41int>::type = 0>42static void serializeTo(char *, Tuple &&) {}43};4445using Serializer = SerializerImpl<0>;4647template <class Tuple, size_t Index> struct AggregateSizesImpl {48static constexpr size_t value =49sizeof(typename std::tuple_element<Index, Tuple>::type) +50AggregateSizesImpl<Tuple, Index - 1>::value;51};5253template <class Tuple> struct AggregateSizesImpl<Tuple, 0> {54static constexpr size_t value =55sizeof(typename std::tuple_element<0, Tuple>::type);56};5758template <class Tuple> struct AggregateSizes {59static constexpr size_t value =60AggregateSizesImpl<Tuple, std::tuple_size<Tuple>::value - 1>::value;61};6263template <MetadataRecord::RecordKinds Kind, class... DataTypes>64MetadataRecord createMetadataRecord(DataTypes &&... Ds) {65static_assert(AggregateSizes<std::tuple<DataTypes...>>::value <=66sizeof(MetadataRecord) - 1,67"Metadata payload longer than metadata buffer!");68MetadataRecord R;69R.Type = 1;70R.RecordKind = static_cast<uint8_t>(Kind);71Serializer::serializeTo(R.Data,72std::make_tuple(std::forward<DataTypes>(Ds)...));73return R;74}7576class FDRLogWriter {77BufferQueue::Buffer &Buffer;78char *NextRecord = nullptr;7980template <class T> void writeRecord(const T &R) {81internal_memcpy(NextRecord, reinterpret_cast<const char *>(&R), sizeof(T));82NextRecord += sizeof(T);83// We need this atomic fence here to ensure that other threads attempting to84// read the bytes in the buffer will see the writes committed before the85// extents are updated.86atomic_thread_fence(memory_order_release);87atomic_fetch_add(Buffer.Extents, sizeof(T), memory_order_acq_rel);88}8990public:91explicit FDRLogWriter(BufferQueue::Buffer &B, char *P)92: Buffer(B), NextRecord(P) {93DCHECK_NE(Buffer.Data, nullptr);94DCHECK_NE(NextRecord, nullptr);95}9697explicit FDRLogWriter(BufferQueue::Buffer &B)98: FDRLogWriter(B, static_cast<char *>(B.Data)) {}99100template <MetadataRecord::RecordKinds Kind, class... Data>101bool writeMetadata(Data &&... Ds) {102// TODO: Check boundary conditions:103// 1) Buffer is full, and cannot handle one metadata record.104// 2) Buffer queue is finalising.105writeRecord(createMetadataRecord<Kind>(std::forward<Data>(Ds)...));106return true;107}108109template <size_t N> size_t writeMetadataRecords(MetadataRecord (&Recs)[N]) {110constexpr auto Size = sizeof(MetadataRecord) * N;111internal_memcpy(NextRecord, reinterpret_cast<const char *>(Recs), Size);112NextRecord += Size;113// We need this atomic fence here to ensure that other threads attempting to114// read the bytes in the buffer will see the writes committed before the115// extents are updated.116atomic_thread_fence(memory_order_release);117atomic_fetch_add(Buffer.Extents, Size, memory_order_acq_rel);118return Size;119}120121enum class FunctionRecordKind : uint8_t {122Enter = 0x00,123Exit = 0x01,124TailExit = 0x02,125EnterArg = 0x03,126};127128bool writeFunction(FunctionRecordKind Kind, int32_t FuncId, int32_t Delta) {129FunctionRecord R;130R.Type = 0;131R.RecordKind = uint8_t(Kind);132R.FuncId = FuncId;133R.TSCDelta = Delta;134writeRecord(R);135return true;136}137138bool writeFunctionWithArg(FunctionRecordKind Kind, int32_t FuncId,139int32_t Delta, uint64_t Arg) {140// We need to write the function with arg into the buffer, and then141// atomically update the buffer extents. This ensures that any reads142// synchronised on the buffer extents record will always see the writes143// that happen before the atomic update.144FunctionRecord R;145R.Type = 0;146R.RecordKind = uint8_t(Kind);147R.FuncId = FuncId;148R.TSCDelta = Delta;149MetadataRecord A =150createMetadataRecord<MetadataRecord::RecordKinds::CallArgument>(Arg);151NextRecord = reinterpret_cast<char *>(internal_memcpy(152NextRecord, reinterpret_cast<char *>(&R), sizeof(R))) +153sizeof(R);154NextRecord = reinterpret_cast<char *>(internal_memcpy(155NextRecord, reinterpret_cast<char *>(&A), sizeof(A))) +156sizeof(A);157// We need this atomic fence here to ensure that other threads attempting to158// read the bytes in the buffer will see the writes committed before the159// extents are updated.160atomic_thread_fence(memory_order_release);161atomic_fetch_add(Buffer.Extents, sizeof(R) + sizeof(A),162memory_order_acq_rel);163return true;164}165166bool writeCustomEvent(int32_t Delta, const void *Event, int32_t EventSize) {167// We write the metadata record and the custom event data into the buffer168// first, before we atomically update the extents for the buffer. This169// allows us to ensure that any threads reading the extents of the buffer170// will only ever see the full metadata and custom event payload accounted171// (no partial writes accounted).172MetadataRecord R =173createMetadataRecord<MetadataRecord::RecordKinds::CustomEventMarker>(174EventSize, Delta);175NextRecord = reinterpret_cast<char *>(internal_memcpy(176NextRecord, reinterpret_cast<char *>(&R), sizeof(R))) +177sizeof(R);178NextRecord = reinterpret_cast<char *>(179internal_memcpy(NextRecord, Event, EventSize)) +180EventSize;181182// We need this atomic fence here to ensure that other threads attempting to183// read the bytes in the buffer will see the writes committed before the184// extents are updated.185atomic_thread_fence(memory_order_release);186atomic_fetch_add(Buffer.Extents, sizeof(R) + EventSize,187memory_order_acq_rel);188return true;189}190191bool writeTypedEvent(int32_t Delta, uint16_t EventType, const void *Event,192int32_t EventSize) {193// We do something similar when writing out typed events, see194// writeCustomEvent(...) above for details.195MetadataRecord R =196createMetadataRecord<MetadataRecord::RecordKinds::TypedEventMarker>(197EventSize, Delta, EventType);198NextRecord = reinterpret_cast<char *>(internal_memcpy(199NextRecord, reinterpret_cast<char *>(&R), sizeof(R))) +200sizeof(R);201NextRecord = reinterpret_cast<char *>(202internal_memcpy(NextRecord, Event, EventSize)) +203EventSize;204205// We need this atomic fence here to ensure that other threads attempting to206// read the bytes in the buffer will see the writes committed before the207// extents are updated.208atomic_thread_fence(memory_order_release);209atomic_fetch_add(Buffer.Extents, EventSize, memory_order_acq_rel);210return true;211}212213char *getNextRecord() const { return NextRecord; }214215void resetRecord() {216NextRecord = reinterpret_cast<char *>(Buffer.Data);217atomic_store(Buffer.Extents, 0, memory_order_release);218}219220void undoWrites(size_t B) {221DCHECK_GE(NextRecord - B, reinterpret_cast<char *>(Buffer.Data));222NextRecord -= B;223atomic_fetch_sub(Buffer.Extents, B, memory_order_acq_rel);224}225226}; // namespace __xray227228} // namespace __xray229230#endif // COMPILER-RT_LIB_XRAY_XRAY_FDR_LOG_WRITER_H_231232233