1*0b57cec5SDimitry Andric //===-- xray_fdr_controller.h ---------------------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file is a part of XRay, a function call tracing system. 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 12*0b57cec5SDimitry Andric #ifndef COMPILER_RT_LIB_XRAY_XRAY_FDR_CONTROLLER_H_ 13*0b57cec5SDimitry Andric #define COMPILER_RT_LIB_XRAY_XRAY_FDR_CONTROLLER_H_ 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric #include <limits> 16*0b57cec5SDimitry Andric #include <time.h> 17*0b57cec5SDimitry Andric 18*0b57cec5SDimitry Andric #include "xray/xray_interface.h" 19*0b57cec5SDimitry Andric #include "xray/xray_records.h" 20*0b57cec5SDimitry Andric #include "xray_buffer_queue.h" 21*0b57cec5SDimitry Andric #include "xray_fdr_log_writer.h" 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric namespace __xray { 24*0b57cec5SDimitry Andric 25*0b57cec5SDimitry Andric template <size_t Version = 5> class FDRController { 26*0b57cec5SDimitry Andric BufferQueue *BQ; 27*0b57cec5SDimitry Andric BufferQueue::Buffer &B; 28*0b57cec5SDimitry Andric FDRLogWriter &W; 29*0b57cec5SDimitry Andric int (*WallClockReader)(clockid_t, struct timespec *) = 0; 30*0b57cec5SDimitry Andric uint64_t CycleThreshold = 0; 31*0b57cec5SDimitry Andric 32*0b57cec5SDimitry Andric uint64_t LastFunctionEntryTSC = 0; 33*0b57cec5SDimitry Andric uint64_t LatestTSC = 0; 34*0b57cec5SDimitry Andric uint16_t LatestCPU = 0; 35*0b57cec5SDimitry Andric tid_t TId = 0; 36*0b57cec5SDimitry Andric pid_t PId = 0; 37*0b57cec5SDimitry Andric bool First = true; 38*0b57cec5SDimitry Andric 39*0b57cec5SDimitry Andric uint32_t UndoableFunctionEnters = 0; 40*0b57cec5SDimitry Andric uint32_t UndoableTailExits = 0; 41*0b57cec5SDimitry Andric finalized()42*0b57cec5SDimitry Andric bool finalized() const XRAY_NEVER_INSTRUMENT { 43*0b57cec5SDimitry Andric return BQ == nullptr || BQ->finalizing(); 44*0b57cec5SDimitry Andric } 45*0b57cec5SDimitry Andric hasSpace(size_t S)46*0b57cec5SDimitry Andric bool hasSpace(size_t S) XRAY_NEVER_INSTRUMENT { 47*0b57cec5SDimitry Andric return B.Data != nullptr && B.Generation == BQ->generation() && 48*0b57cec5SDimitry Andric W.getNextRecord() + S <= reinterpret_cast<char *>(B.Data) + B.Size; 49*0b57cec5SDimitry Andric } 50*0b57cec5SDimitry Andric mask(int32_t FuncId)51*0b57cec5SDimitry Andric constexpr int32_t mask(int32_t FuncId) const XRAY_NEVER_INSTRUMENT { 52*0b57cec5SDimitry Andric return FuncId & ((1 << 29) - 1); 53*0b57cec5SDimitry Andric } 54*0b57cec5SDimitry Andric getNewBuffer()55*0b57cec5SDimitry Andric bool getNewBuffer() XRAY_NEVER_INSTRUMENT { 56*0b57cec5SDimitry Andric if (BQ->getBuffer(B) != BufferQueue::ErrorCode::Ok) 57*0b57cec5SDimitry Andric return false; 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric W.resetRecord(); 60*0b57cec5SDimitry Andric DCHECK_EQ(W.getNextRecord(), B.Data); 61*0b57cec5SDimitry Andric LatestTSC = 0; 62*0b57cec5SDimitry Andric LatestCPU = 0; 63*0b57cec5SDimitry Andric First = true; 64*0b57cec5SDimitry Andric UndoableFunctionEnters = 0; 65*0b57cec5SDimitry Andric UndoableTailExits = 0; 66*0b57cec5SDimitry Andric atomic_store(B.Extents, 0, memory_order_release); 67*0b57cec5SDimitry Andric return true; 68*0b57cec5SDimitry Andric } 69*0b57cec5SDimitry Andric setupNewBuffer()70*0b57cec5SDimitry Andric bool setupNewBuffer() XRAY_NEVER_INSTRUMENT { 71*0b57cec5SDimitry Andric if (finalized()) 72*0b57cec5SDimitry Andric return false; 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric DCHECK(hasSpace(sizeof(MetadataRecord) * 3)); 75*0b57cec5SDimitry Andric TId = GetTid(); 76*0b57cec5SDimitry Andric PId = internal_getpid(); 77*0b57cec5SDimitry Andric struct timespec TS { 78*0b57cec5SDimitry Andric 0, 0 79*0b57cec5SDimitry Andric }; 80*0b57cec5SDimitry Andric WallClockReader(CLOCK_MONOTONIC, &TS); 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric MetadataRecord Metadata[] = { 83*0b57cec5SDimitry Andric // Write out a MetadataRecord to signify that this is the start of a new 84*0b57cec5SDimitry Andric // buffer, associated with a particular thread, with a new CPU. For the 85*0b57cec5SDimitry Andric // data, we have 15 bytes to squeeze as much information as we can. At 86*0b57cec5SDimitry Andric // this point we only write down the following bytes: 87*0b57cec5SDimitry Andric // - Thread ID (tid_t, cast to 4 bytes type due to Darwin being 8 88*0b57cec5SDimitry Andric // bytes) 89*0b57cec5SDimitry Andric createMetadataRecord<MetadataRecord::RecordKinds::NewBuffer>( 90*0b57cec5SDimitry Andric static_cast<int32_t>(TId)), 91*0b57cec5SDimitry Andric 92*0b57cec5SDimitry Andric // Also write the WalltimeMarker record. We only really need microsecond 93*0b57cec5SDimitry Andric // precision here, and enforce across platforms that we need 64-bit 94*0b57cec5SDimitry Andric // seconds and 32-bit microseconds encoded in the Metadata record. 95*0b57cec5SDimitry Andric createMetadataRecord<MetadataRecord::RecordKinds::WalltimeMarker>( 96*0b57cec5SDimitry Andric static_cast<int64_t>(TS.tv_sec), 97*0b57cec5SDimitry Andric static_cast<int32_t>(TS.tv_nsec / 1000)), 98*0b57cec5SDimitry Andric 99*0b57cec5SDimitry Andric // Also write the Pid record. 100*0b57cec5SDimitry Andric createMetadataRecord<MetadataRecord::RecordKinds::Pid>( 101*0b57cec5SDimitry Andric static_cast<int32_t>(PId)), 102*0b57cec5SDimitry Andric }; 103*0b57cec5SDimitry Andric 104*0b57cec5SDimitry Andric if (finalized()) 105*0b57cec5SDimitry Andric return false; 106*0b57cec5SDimitry Andric return W.writeMetadataRecords(Metadata); 107*0b57cec5SDimitry Andric } 108*0b57cec5SDimitry Andric prepareBuffer(size_t S)109*0b57cec5SDimitry Andric bool prepareBuffer(size_t S) XRAY_NEVER_INSTRUMENT { 110*0b57cec5SDimitry Andric if (finalized()) 111*0b57cec5SDimitry Andric return returnBuffer(); 112*0b57cec5SDimitry Andric 113*0b57cec5SDimitry Andric if (UNLIKELY(!hasSpace(S))) { 114*0b57cec5SDimitry Andric if (!returnBuffer()) 115*0b57cec5SDimitry Andric return false; 116*0b57cec5SDimitry Andric if (!getNewBuffer()) 117*0b57cec5SDimitry Andric return false; 118*0b57cec5SDimitry Andric if (!setupNewBuffer()) 119*0b57cec5SDimitry Andric return false; 120*0b57cec5SDimitry Andric } 121*0b57cec5SDimitry Andric 122*0b57cec5SDimitry Andric if (First) { 123*0b57cec5SDimitry Andric First = false; 124*0b57cec5SDimitry Andric W.resetRecord(); 125*0b57cec5SDimitry Andric atomic_store(B.Extents, 0, memory_order_release); 126*0b57cec5SDimitry Andric return setupNewBuffer(); 127*0b57cec5SDimitry Andric } 128*0b57cec5SDimitry Andric 129*0b57cec5SDimitry Andric return true; 130*0b57cec5SDimitry Andric } 131*0b57cec5SDimitry Andric returnBuffer()132*0b57cec5SDimitry Andric bool returnBuffer() XRAY_NEVER_INSTRUMENT { 133*0b57cec5SDimitry Andric if (BQ == nullptr) 134*0b57cec5SDimitry Andric return false; 135*0b57cec5SDimitry Andric 136*0b57cec5SDimitry Andric First = true; 137*0b57cec5SDimitry Andric if (finalized()) { 138*0b57cec5SDimitry Andric BQ->releaseBuffer(B); // ignore result. 139*0b57cec5SDimitry Andric return false; 140*0b57cec5SDimitry Andric } 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric return BQ->releaseBuffer(B) == BufferQueue::ErrorCode::Ok; 143*0b57cec5SDimitry Andric } 144*0b57cec5SDimitry Andric 145*0b57cec5SDimitry Andric enum class PreambleResult { NoChange, WroteMetadata, InvalidBuffer }; recordPreamble(uint64_t TSC,uint16_t CPU)146*0b57cec5SDimitry Andric PreambleResult recordPreamble(uint64_t TSC, 147*0b57cec5SDimitry Andric uint16_t CPU) XRAY_NEVER_INSTRUMENT { 148*0b57cec5SDimitry Andric if (UNLIKELY(LatestCPU != CPU || LatestTSC == 0)) { 149*0b57cec5SDimitry Andric // We update our internal tracking state for the Latest TSC and CPU we've 150*0b57cec5SDimitry Andric // seen, then write out the appropriate metadata and function records. 151*0b57cec5SDimitry Andric LatestTSC = TSC; 152*0b57cec5SDimitry Andric LatestCPU = CPU; 153*0b57cec5SDimitry Andric 154*0b57cec5SDimitry Andric if (B.Generation != BQ->generation()) 155*0b57cec5SDimitry Andric return PreambleResult::InvalidBuffer; 156*0b57cec5SDimitry Andric 157*0b57cec5SDimitry Andric W.writeMetadata<MetadataRecord::RecordKinds::NewCPUId>(CPU, TSC); 158*0b57cec5SDimitry Andric return PreambleResult::WroteMetadata; 159*0b57cec5SDimitry Andric } 160*0b57cec5SDimitry Andric 161*0b57cec5SDimitry Andric DCHECK_EQ(LatestCPU, CPU); 162*0b57cec5SDimitry Andric 163*0b57cec5SDimitry Andric if (UNLIKELY(LatestTSC > TSC || 164*0b57cec5SDimitry Andric TSC - LatestTSC > 165*0b57cec5SDimitry Andric uint64_t{std::numeric_limits<int32_t>::max()})) { 166*0b57cec5SDimitry Andric // Either the TSC has wrapped around from the last TSC we've seen or the 167*0b57cec5SDimitry Andric // delta is too large to fit in a 32-bit signed integer, so we write a 168*0b57cec5SDimitry Andric // wrap-around record. 169*0b57cec5SDimitry Andric LatestTSC = TSC; 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric if (B.Generation != BQ->generation()) 172*0b57cec5SDimitry Andric return PreambleResult::InvalidBuffer; 173*0b57cec5SDimitry Andric 174*0b57cec5SDimitry Andric W.writeMetadata<MetadataRecord::RecordKinds::TSCWrap>(TSC); 175*0b57cec5SDimitry Andric return PreambleResult::WroteMetadata; 176*0b57cec5SDimitry Andric } 177*0b57cec5SDimitry Andric 178*0b57cec5SDimitry Andric return PreambleResult::NoChange; 179*0b57cec5SDimitry Andric } 180*0b57cec5SDimitry Andric rewindRecords(int32_t FuncId,uint64_t TSC,uint16_t CPU)181*0b57cec5SDimitry Andric bool rewindRecords(int32_t FuncId, uint64_t TSC, 182*0b57cec5SDimitry Andric uint16_t CPU) XRAY_NEVER_INSTRUMENT { 183*0b57cec5SDimitry Andric // Undo one enter record, because at this point we are either at the state 184*0b57cec5SDimitry Andric // of: 185*0b57cec5SDimitry Andric // - We are exiting a function that we recently entered. 186*0b57cec5SDimitry Andric // - We are exiting a function that was the result of a sequence of tail 187*0b57cec5SDimitry Andric // exits, and we can check whether the tail exits can be re-wound. 188*0b57cec5SDimitry Andric // 189*0b57cec5SDimitry Andric FunctionRecord F; 190*0b57cec5SDimitry Andric W.undoWrites(sizeof(FunctionRecord)); 191*0b57cec5SDimitry Andric if (B.Generation != BQ->generation()) 192*0b57cec5SDimitry Andric return false; 193*0b57cec5SDimitry Andric internal_memcpy(&F, W.getNextRecord(), sizeof(FunctionRecord)); 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric DCHECK(F.RecordKind == 196*0b57cec5SDimitry Andric uint8_t(FunctionRecord::RecordKinds::FunctionEnter) && 197*0b57cec5SDimitry Andric "Expected to find function entry recording when rewinding."); 198*0b57cec5SDimitry Andric DCHECK_EQ(F.FuncId, FuncId & ~(0x0F << 28)); 199*0b57cec5SDimitry Andric 200*0b57cec5SDimitry Andric LatestTSC -= F.TSCDelta; 201*0b57cec5SDimitry Andric if (--UndoableFunctionEnters != 0) { 202*0b57cec5SDimitry Andric LastFunctionEntryTSC -= F.TSCDelta; 203*0b57cec5SDimitry Andric return true; 204*0b57cec5SDimitry Andric } 205*0b57cec5SDimitry Andric 206*0b57cec5SDimitry Andric LastFunctionEntryTSC = 0; 207*0b57cec5SDimitry Andric auto RewindingTSC = LatestTSC; 208*0b57cec5SDimitry Andric auto RewindingRecordPtr = W.getNextRecord() - sizeof(FunctionRecord); 209*0b57cec5SDimitry Andric while (UndoableTailExits) { 210*0b57cec5SDimitry Andric if (B.Generation != BQ->generation()) 211*0b57cec5SDimitry Andric return false; 212*0b57cec5SDimitry Andric internal_memcpy(&F, RewindingRecordPtr, sizeof(FunctionRecord)); 213*0b57cec5SDimitry Andric DCHECK_EQ(F.RecordKind, 214*0b57cec5SDimitry Andric uint8_t(FunctionRecord::RecordKinds::FunctionTailExit)); 215*0b57cec5SDimitry Andric RewindingTSC -= F.TSCDelta; 216*0b57cec5SDimitry Andric RewindingRecordPtr -= sizeof(FunctionRecord); 217*0b57cec5SDimitry Andric if (B.Generation != BQ->generation()) 218*0b57cec5SDimitry Andric return false; 219*0b57cec5SDimitry Andric internal_memcpy(&F, RewindingRecordPtr, sizeof(FunctionRecord)); 220*0b57cec5SDimitry Andric 221*0b57cec5SDimitry Andric // This tail call exceeded the threshold duration. It will not be erased. 222*0b57cec5SDimitry Andric if ((TSC - RewindingTSC) >= CycleThreshold) { 223*0b57cec5SDimitry Andric UndoableTailExits = 0; 224*0b57cec5SDimitry Andric return true; 225*0b57cec5SDimitry Andric } 226*0b57cec5SDimitry Andric 227*0b57cec5SDimitry Andric --UndoableTailExits; 228*0b57cec5SDimitry Andric W.undoWrites(sizeof(FunctionRecord) * 2); 229*0b57cec5SDimitry Andric LatestTSC = RewindingTSC; 230*0b57cec5SDimitry Andric } 231*0b57cec5SDimitry Andric return true; 232*0b57cec5SDimitry Andric } 233*0b57cec5SDimitry Andric 234*0b57cec5SDimitry Andric public: 235*0b57cec5SDimitry Andric template <class WallClockFunc> FDRController(BufferQueue * BQ,BufferQueue::Buffer & B,FDRLogWriter & W,WallClockFunc R,uint64_t C)236*0b57cec5SDimitry Andric FDRController(BufferQueue *BQ, BufferQueue::Buffer &B, FDRLogWriter &W, 237*0b57cec5SDimitry Andric WallClockFunc R, uint64_t C) XRAY_NEVER_INSTRUMENT 238*0b57cec5SDimitry Andric : BQ(BQ), 239*0b57cec5SDimitry Andric B(B), 240*0b57cec5SDimitry Andric W(W), 241*0b57cec5SDimitry Andric WallClockReader(R), 242*0b57cec5SDimitry Andric CycleThreshold(C) {} 243*0b57cec5SDimitry Andric functionEnter(int32_t FuncId,uint64_t TSC,uint16_t CPU)244*0b57cec5SDimitry Andric bool functionEnter(int32_t FuncId, uint64_t TSC, 245*0b57cec5SDimitry Andric uint16_t CPU) XRAY_NEVER_INSTRUMENT { 246*0b57cec5SDimitry Andric if (finalized() || 247*0b57cec5SDimitry Andric !prepareBuffer(sizeof(MetadataRecord) + sizeof(FunctionRecord))) 248*0b57cec5SDimitry Andric return returnBuffer(); 249*0b57cec5SDimitry Andric 250*0b57cec5SDimitry Andric auto PreambleStatus = recordPreamble(TSC, CPU); 251*0b57cec5SDimitry Andric if (PreambleStatus == PreambleResult::InvalidBuffer) 252*0b57cec5SDimitry Andric return returnBuffer(); 253*0b57cec5SDimitry Andric 254*0b57cec5SDimitry Andric if (PreambleStatus == PreambleResult::WroteMetadata) { 255*0b57cec5SDimitry Andric UndoableFunctionEnters = 1; 256*0b57cec5SDimitry Andric UndoableTailExits = 0; 257*0b57cec5SDimitry Andric } else { 258*0b57cec5SDimitry Andric ++UndoableFunctionEnters; 259*0b57cec5SDimitry Andric } 260*0b57cec5SDimitry Andric 261*0b57cec5SDimitry Andric auto Delta = TSC - LatestTSC; 262*0b57cec5SDimitry Andric LastFunctionEntryTSC = TSC; 263*0b57cec5SDimitry Andric LatestTSC = TSC; 264*0b57cec5SDimitry Andric return W.writeFunction(FDRLogWriter::FunctionRecordKind::Enter, 265*0b57cec5SDimitry Andric mask(FuncId), Delta); 266*0b57cec5SDimitry Andric } 267*0b57cec5SDimitry Andric functionTailExit(int32_t FuncId,uint64_t TSC,uint16_t CPU)268*0b57cec5SDimitry Andric bool functionTailExit(int32_t FuncId, uint64_t TSC, 269*0b57cec5SDimitry Andric uint16_t CPU) XRAY_NEVER_INSTRUMENT { 270*0b57cec5SDimitry Andric if (finalized()) 271*0b57cec5SDimitry Andric return returnBuffer(); 272*0b57cec5SDimitry Andric 273*0b57cec5SDimitry Andric if (!prepareBuffer(sizeof(MetadataRecord) + sizeof(FunctionRecord))) 274*0b57cec5SDimitry Andric return returnBuffer(); 275*0b57cec5SDimitry Andric 276*0b57cec5SDimitry Andric auto PreambleStatus = recordPreamble(TSC, CPU); 277*0b57cec5SDimitry Andric if (PreambleStatus == PreambleResult::InvalidBuffer) 278*0b57cec5SDimitry Andric return returnBuffer(); 279*0b57cec5SDimitry Andric 280*0b57cec5SDimitry Andric if (PreambleStatus == PreambleResult::NoChange && 281*0b57cec5SDimitry Andric UndoableFunctionEnters != 0 && 282*0b57cec5SDimitry Andric TSC - LastFunctionEntryTSC < CycleThreshold) 283*0b57cec5SDimitry Andric return rewindRecords(FuncId, TSC, CPU); 284*0b57cec5SDimitry Andric 285*0b57cec5SDimitry Andric UndoableTailExits = UndoableFunctionEnters ? UndoableTailExits + 1 : 0; 286*0b57cec5SDimitry Andric UndoableFunctionEnters = 0; 287*0b57cec5SDimitry Andric auto Delta = TSC - LatestTSC; 288*0b57cec5SDimitry Andric LatestTSC = TSC; 289*0b57cec5SDimitry Andric return W.writeFunction(FDRLogWriter::FunctionRecordKind::TailExit, 290*0b57cec5SDimitry Andric mask(FuncId), Delta); 291*0b57cec5SDimitry Andric } 292*0b57cec5SDimitry Andric functionEnterArg(int32_t FuncId,uint64_t TSC,uint16_t CPU,uint64_t Arg)293*0b57cec5SDimitry Andric bool functionEnterArg(int32_t FuncId, uint64_t TSC, uint16_t CPU, 294*0b57cec5SDimitry Andric uint64_t Arg) XRAY_NEVER_INSTRUMENT { 295*0b57cec5SDimitry Andric if (finalized() || 296*0b57cec5SDimitry Andric !prepareBuffer((2 * sizeof(MetadataRecord)) + sizeof(FunctionRecord)) || 297*0b57cec5SDimitry Andric recordPreamble(TSC, CPU) == PreambleResult::InvalidBuffer) 298*0b57cec5SDimitry Andric return returnBuffer(); 299*0b57cec5SDimitry Andric 300*0b57cec5SDimitry Andric auto Delta = TSC - LatestTSC; 301*0b57cec5SDimitry Andric LatestTSC = TSC; 302*0b57cec5SDimitry Andric LastFunctionEntryTSC = 0; 303*0b57cec5SDimitry Andric UndoableFunctionEnters = 0; 304*0b57cec5SDimitry Andric UndoableTailExits = 0; 305*0b57cec5SDimitry Andric 306*0b57cec5SDimitry Andric return W.writeFunctionWithArg(FDRLogWriter::FunctionRecordKind::EnterArg, 307*0b57cec5SDimitry Andric mask(FuncId), Delta, Arg); 308*0b57cec5SDimitry Andric } 309*0b57cec5SDimitry Andric functionExit(int32_t FuncId,uint64_t TSC,uint16_t CPU)310*0b57cec5SDimitry Andric bool functionExit(int32_t FuncId, uint64_t TSC, 311*0b57cec5SDimitry Andric uint16_t CPU) XRAY_NEVER_INSTRUMENT { 312*0b57cec5SDimitry Andric if (finalized() || 313*0b57cec5SDimitry Andric !prepareBuffer(sizeof(MetadataRecord) + sizeof(FunctionRecord))) 314*0b57cec5SDimitry Andric return returnBuffer(); 315*0b57cec5SDimitry Andric 316*0b57cec5SDimitry Andric auto PreambleStatus = recordPreamble(TSC, CPU); 317*0b57cec5SDimitry Andric if (PreambleStatus == PreambleResult::InvalidBuffer) 318*0b57cec5SDimitry Andric return returnBuffer(); 319*0b57cec5SDimitry Andric 320*0b57cec5SDimitry Andric if (PreambleStatus == PreambleResult::NoChange && 321*0b57cec5SDimitry Andric UndoableFunctionEnters != 0 && 322*0b57cec5SDimitry Andric TSC - LastFunctionEntryTSC < CycleThreshold) 323*0b57cec5SDimitry Andric return rewindRecords(FuncId, TSC, CPU); 324*0b57cec5SDimitry Andric 325*0b57cec5SDimitry Andric auto Delta = TSC - LatestTSC; 326*0b57cec5SDimitry Andric LatestTSC = TSC; 327*0b57cec5SDimitry Andric UndoableFunctionEnters = 0; 328*0b57cec5SDimitry Andric UndoableTailExits = 0; 329*0b57cec5SDimitry Andric return W.writeFunction(FDRLogWriter::FunctionRecordKind::Exit, mask(FuncId), 330*0b57cec5SDimitry Andric Delta); 331*0b57cec5SDimitry Andric } 332*0b57cec5SDimitry Andric customEvent(uint64_t TSC,uint16_t CPU,const void * Event,int32_t EventSize)333*0b57cec5SDimitry Andric bool customEvent(uint64_t TSC, uint16_t CPU, const void *Event, 334*0b57cec5SDimitry Andric int32_t EventSize) XRAY_NEVER_INSTRUMENT { 335*0b57cec5SDimitry Andric if (finalized() || 336*0b57cec5SDimitry Andric !prepareBuffer((2 * sizeof(MetadataRecord)) + EventSize) || 337*0b57cec5SDimitry Andric recordPreamble(TSC, CPU) == PreambleResult::InvalidBuffer) 338*0b57cec5SDimitry Andric return returnBuffer(); 339*0b57cec5SDimitry Andric 340*0b57cec5SDimitry Andric auto Delta = TSC - LatestTSC; 341*0b57cec5SDimitry Andric LatestTSC = TSC; 342*0b57cec5SDimitry Andric UndoableFunctionEnters = 0; 343*0b57cec5SDimitry Andric UndoableTailExits = 0; 344*0b57cec5SDimitry Andric return W.writeCustomEvent(Delta, Event, EventSize); 345*0b57cec5SDimitry Andric } 346*0b57cec5SDimitry Andric typedEvent(uint64_t TSC,uint16_t CPU,uint16_t EventType,const void * Event,int32_t EventSize)347*0b57cec5SDimitry Andric bool typedEvent(uint64_t TSC, uint16_t CPU, uint16_t EventType, 348*0b57cec5SDimitry Andric const void *Event, int32_t EventSize) XRAY_NEVER_INSTRUMENT { 349*0b57cec5SDimitry Andric if (finalized() || 350*0b57cec5SDimitry Andric !prepareBuffer((2 * sizeof(MetadataRecord)) + EventSize) || 351*0b57cec5SDimitry Andric recordPreamble(TSC, CPU) == PreambleResult::InvalidBuffer) 352*0b57cec5SDimitry Andric return returnBuffer(); 353*0b57cec5SDimitry Andric 354*0b57cec5SDimitry Andric auto Delta = TSC - LatestTSC; 355*0b57cec5SDimitry Andric LatestTSC = TSC; 356*0b57cec5SDimitry Andric UndoableFunctionEnters = 0; 357*0b57cec5SDimitry Andric UndoableTailExits = 0; 358*0b57cec5SDimitry Andric return W.writeTypedEvent(Delta, EventType, Event, EventSize); 359*0b57cec5SDimitry Andric } 360*0b57cec5SDimitry Andric flush()361*0b57cec5SDimitry Andric bool flush() XRAY_NEVER_INSTRUMENT { 362*0b57cec5SDimitry Andric if (finalized()) { 363*0b57cec5SDimitry Andric returnBuffer(); // ignore result. 364*0b57cec5SDimitry Andric return true; 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric return returnBuffer(); 367*0b57cec5SDimitry Andric } 368*0b57cec5SDimitry Andric }; 369*0b57cec5SDimitry Andric 370*0b57cec5SDimitry Andric } // namespace __xray 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric #endif // COMPILER-RT_LIB_XRAY_XRAY_FDR_CONTROLLER_H_ 373