Index: compiler-rt/trunk/lib/xray/tests/unit/fdr_controller_test.cc =================================================================== --- compiler-rt/trunk/lib/xray/tests/unit/fdr_controller_test.cc +++ compiler-rt/trunk/lib/xray/tests/unit/fdr_controller_test.cc @@ -137,6 +137,30 @@ TSCIs(Gt(1000uL)))))); } +TEST_F(FunctionSequenceTest, PreservedCallsSupportLargeDeltas) { + C = llvm::make_unique>(BQ.get(), B, *W, clock_gettime, 1000); + uint64_t TSC = 1; + uint16_t CPU = 0; + const auto LargeDelta = uint64_t{std::numeric_limits::max()}; + ASSERT_TRUE(C->functionEnter(1, TSC++, CPU)); + ASSERT_TRUE(C->functionExit(1, TSC += LargeDelta, CPU)); + ASSERT_TRUE(C->flush()); + ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok); + + // Serialize the buffer then test to see if we find the right TSC with a large + // delta. + std::string Serialized = serialize(*BQ, 3); + llvm::DataExtractor DE(Serialized, true, 8); + auto TraceOrErr = llvm::xray::loadTrace(DE); + EXPECT_THAT_EXPECTED( + TraceOrErr, + HasValue(ElementsAre( + AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER), + TSCIs(Eq(1uL))), + AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT), + TSCIs(Gt(LargeDelta)))))); +} + TEST_F(FunctionSequenceTest, RewindingMultipleCalls) { C = llvm::make_unique>(BQ.get(), B, *W, clock_gettime, 1000); Index: compiler-rt/trunk/lib/xray/xray_fdr_controller.h =================================================================== --- compiler-rt/trunk/lib/xray/xray_fdr_controller.h +++ compiler-rt/trunk/lib/xray/xray_fdr_controller.h @@ -13,6 +13,7 @@ #ifndef COMPILER_RT_LIB_XRAY_XRAY_FDR_CONTROLLER_H_ #define COMPILER_RT_LIB_XRAY_XRAY_FDR_CONTROLLER_H_ +#include #include #include "xray/xray_interface.h" @@ -158,8 +159,14 @@ return PreambleResult::WroteMetadata; } - if (UNLIKELY(LatestCPU == LatestCPU && LatestTSC > TSC)) { - // The TSC has wrapped around, from the last TSC we've seen. + DCHECK_EQ(LatestCPU, CPU); + + if (UNLIKELY(LatestTSC > TSC || + TSC - LatestTSC > + uint64_t{std::numeric_limits::max()})) { + // Either the TSC has wrapped around from the last TSC we've seen or the + // delta is too large to fit in a 32-bit signed integer, so we write a + // wrap-around record. LatestTSC = TSC; if (B.Generation != BQ->generation()) @@ -248,10 +255,11 @@ UndoableFunctionEnters = (PreambleStatus == PreambleResult::WroteMetadata) ? 1 : UndoableFunctionEnters + 1; + auto Delta = TSC - LatestTSC; LastFunctionEntryTSC = TSC; LatestTSC = TSC; return W.writeFunction(FDRLogWriter::FunctionRecordKind::Enter, - mask(FuncId), TSC - LatestTSC); + mask(FuncId), Delta); } bool functionTailExit(int32_t FuncId, uint64_t TSC, @@ -273,9 +281,10 @@ UndoableTailExits = UndoableFunctionEnters ? UndoableTailExits + 1 : 0; UndoableFunctionEnters = 0; + auto Delta = TSC - LatestTSC; LatestTSC = TSC; return W.writeFunction(FDRLogWriter::FunctionRecordKind::TailExit, - mask(FuncId), TSC - LatestTSC); + mask(FuncId), Delta); } bool functionEnterArg(int32_t FuncId, uint64_t TSC, uint16_t CPU, @@ -285,13 +294,14 @@ functionPreamble(TSC, CPU) == PreambleResult::InvalidBuffer) return returnBuffer(); + auto Delta = TSC - LatestTSC; LatestTSC = TSC; LastFunctionEntryTSC = 0; UndoableFunctionEnters = 0; UndoableTailExits = 0; W.writeFunction(FDRLogWriter::FunctionRecordKind::EnterArg, mask(FuncId), - TSC - LatestTSC); + Delta); return W.writeMetadata(Arg); } Index: llvm/trunk/lib/XRay/RecordPrinter.cpp =================================================================== --- llvm/trunk/lib/XRay/RecordPrinter.cpp +++ llvm/trunk/lib/XRay/RecordPrinter.cpp @@ -66,19 +66,19 @@ // FIXME: Support symbolization here? switch (R.recordType()) { case RecordTypes::ENTER: - OS << formatv("", R.functionId(), + OS << formatv("", R.functionId(), R.delta()); break; case RecordTypes::ENTER_ARG: - OS << formatv("", + OS << formatv("", R.functionId(), R.delta()); break; case RecordTypes::EXIT: - OS << formatv("", R.functionId(), + OS << formatv("", R.functionId(), R.delta()); break; case RecordTypes::TAIL_EXIT: - OS << formatv("", R.functionId(), + OS << formatv("", R.functionId(), R.delta()); break; }