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 @@ -23,7 +23,7 @@ namespace __xray { -template class FDRController { +template class FDRController { BufferQueue *BQ; BufferQueue::Buffer &B; FDRLogWriter &W; @@ -144,8 +144,8 @@ } enum class PreambleResult { NoChange, WroteMetadata, InvalidBuffer }; - PreambleResult functionPreamble(uint64_t TSC, - uint16_t CPU) XRAY_NEVER_INSTRUMENT { + PreambleResult recordPreamble(uint64_t TSC, + uint16_t CPU) XRAY_NEVER_INSTRUMENT { if (UNLIKELY(LatestCPU != CPU || LatestTSC == 0)) { // We update our internal tracking state for the Latest TSC and CPU we've // seen, then write out the appropriate metadata and function records. @@ -248,7 +248,7 @@ !prepareBuffer(sizeof(MetadataRecord) + sizeof(FunctionRecord))) return returnBuffer(); - auto PreambleStatus = functionPreamble(TSC, CPU); + auto PreambleStatus = recordPreamble(TSC, CPU); if (PreambleStatus == PreambleResult::InvalidBuffer) return returnBuffer(); @@ -270,7 +270,7 @@ if (!prepareBuffer(sizeof(MetadataRecord) + sizeof(FunctionRecord))) return returnBuffer(); - auto PreambleStatus = functionPreamble(TSC, CPU); + auto PreambleStatus = recordPreamble(TSC, CPU); if (PreambleStatus == PreambleResult::InvalidBuffer) return returnBuffer(); @@ -291,7 +291,7 @@ uint64_t Arg) XRAY_NEVER_INSTRUMENT { if (finalized() || !prepareBuffer((2 * sizeof(MetadataRecord)) + sizeof(FunctionRecord)) || - functionPreamble(TSC, CPU) == PreambleResult::InvalidBuffer) + recordPreamble(TSC, CPU) == PreambleResult::InvalidBuffer) return returnBuffer(); auto Delta = TSC - LatestTSC; @@ -311,7 +311,7 @@ !prepareBuffer(sizeof(MetadataRecord) + sizeof(FunctionRecord))) return returnBuffer(); - auto PreambleStatus = functionPreamble(TSC, CPU); + auto PreambleStatus = recordPreamble(TSC, CPU); if (PreambleStatus == PreambleResult::InvalidBuffer) return returnBuffer(); @@ -332,26 +332,28 @@ int32_t EventSize) XRAY_NEVER_INSTRUMENT { if (finalized() || !prepareBuffer((2 * sizeof(MetadataRecord)) + EventSize) || - functionPreamble(TSC, CPU) == PreambleResult::InvalidBuffer) + recordPreamble(TSC, CPU) == PreambleResult::InvalidBuffer) return returnBuffer(); - LatestTSC = 0; + auto Delta = TSC - LatestTSC; + LatestTSC = TSC; UndoableFunctionEnters = 0; UndoableTailExits = 0; - return W.writeCustomEvent(TSC, CPU, Event, EventSize); + return W.writeCustomEvent(Delta, Event, EventSize); } bool typedEvent(uint64_t TSC, uint16_t CPU, uint16_t EventType, const void *Event, int32_t EventSize) XRAY_NEVER_INSTRUMENT { if (finalized() || !prepareBuffer((2 * sizeof(MetadataRecord)) + EventSize) || - functionPreamble(TSC, CPU) == PreambleResult::InvalidBuffer) + recordPreamble(TSC, CPU) == PreambleResult::InvalidBuffer) return returnBuffer(); - LatestTSC = 0; + auto Delta = TSC - LatestTSC; + LatestTSC = TSC; UndoableFunctionEnters = 0; UndoableTailExits = 0; - return W.writeTypedEvent(TSC, EventType, Event, EventSize); + return W.writeTypedEvent(Delta, EventType, Event, EventSize); } bool flush() XRAY_NEVER_INSTRUMENT { Index: compiler-rt/trunk/lib/xray/xray_fdr_log_writer.h =================================================================== --- compiler-rt/trunk/lib/xray/xray_fdr_log_writer.h +++ compiler-rt/trunk/lib/xray/xray_fdr_log_writer.h @@ -110,8 +110,7 @@ return true; } - bool writeCustomEvent(uint64_t TSC, uint16_t CPU, const void *Event, - int32_t EventSize) { + bool writeCustomEvent(int32_t Delta, const void *Event, int32_t EventSize) { // We write the metadata record and the custom event data into the buffer // first, before we atomically update the extents for the buffer. This // allows us to ensure that any threads reading the extents of the buffer @@ -119,7 +118,7 @@ // (no partial writes accounted). MetadataRecord R = createMetadataRecord( - EventSize, TSC, CPU); + EventSize, Delta); NextRecord = reinterpret_cast(internal_memcpy( NextRecord, reinterpret_cast(&R), sizeof(R))) + sizeof(R); @@ -131,13 +130,13 @@ return true; } - bool writeTypedEvent(uint64_t TSC, uint16_t EventType, const void *Event, + bool writeTypedEvent(int32_t Delta, uint16_t EventType, const void *Event, int32_t EventSize) { // We do something similar when writing out typed events, see // writeCustomEvent(...) above for details. MetadataRecord R = createMetadataRecord( - EventSize, TSC, EventType); + EventSize, Delta, EventType); NextRecord = reinterpret_cast(internal_memcpy( NextRecord, reinterpret_cast(&R), sizeof(R))) + sizeof(R); Index: compiler-rt/trunk/lib/xray/xray_fdr_logging.cc =================================================================== --- compiler-rt/trunk/lib/xray/xray_fdr_logging.cc +++ compiler-rt/trunk/lib/xray/xray_fdr_logging.cc @@ -47,6 +47,7 @@ XRayLogInitStatus::XRAY_LOG_UNINITIALIZED}; namespace { + // Group together thread-local-data in a struct, then hide it behind a function // call so that it can be initialized on first use instead of as a global. We // force the alignment to 64-bytes for x86 cache line alignment, as this @@ -143,26 +144,31 @@ static pthread_once_t OnceInit = PTHREAD_ONCE_INIT; static bool TSCSupported = true; static uint64_t CycleFrequency = NanosecondsPerSecond; - pthread_once(&OnceInit, +[] { - XRayFileHeader &H = reinterpret_cast(HStorage); - // Version 2 of the log writes the extents of the buffer, instead of - // relying on an end-of-buffer record. - // Version 3 includes PID metadata record - // Version 4 includes CPU data in the custom event records - H.Version = 4; - H.Type = FileTypes::FDR_LOG; - - // Test for required CPU features and cache the cycle frequency - TSCSupported = probeRequiredCPUFeatures(); - if (TSCSupported) - CycleFrequency = getTSCFrequency(); - H.CycleFrequency = CycleFrequency; - - // FIXME: Actually check whether we have 'constant_tsc' and - // 'nonstop_tsc' before setting the values in the header. - H.ConstantTSC = 1; - H.NonstopTSC = 1; - }); + pthread_once( + &OnceInit, +[] { + XRayFileHeader &H = reinterpret_cast(HStorage); + // Version 2 of the log writes the extents of the buffer, instead of + // relying on an end-of-buffer record. + // Version 3 includes PID metadata record. + // Version 4 includes CPU data in the custom event records. + // Version 5 uses relative deltas for custom and typed event records, + // and removes the CPU data in custom event records (similar to how + // function records use deltas instead of full TSCs and rely on other + // metadata records for TSC wraparound and CPU migration). + H.Version = 5; + H.Type = FileTypes::FDR_LOG; + + // Test for required CPU features and cache the cycle frequency + TSCSupported = probeRequiredCPUFeatures(); + if (TSCSupported) + CycleFrequency = getTSCFrequency(); + H.CycleFrequency = CycleFrequency; + + // FIXME: Actually check whether we have 'constant_tsc' and + // 'nonstop_tsc' before setting the values in the header. + H.ConstantTSC = 1; + H.NonstopTSC = 1; + }); return reinterpret_cast(HStorage); } @@ -200,9 +206,11 @@ // buffers to expect). static std::aligned_storage::type HeaderStorage; static pthread_once_t HeaderOnce = PTHREAD_ONCE_INIT; - pthread_once(&HeaderOnce, +[] { - reinterpret_cast(HeaderStorage) = fdrCommonHeaderInfo(); - }); + pthread_once( + &HeaderOnce, +[] { + reinterpret_cast(HeaderStorage) = + fdrCommonHeaderInfo(); + }); // We use a convenience alias for code referring to Header from here on out. auto &Header = reinterpret_cast(HeaderStorage); @@ -407,7 +415,8 @@ // Test once for required CPU features static pthread_once_t OnceProbe = PTHREAD_ONCE_INIT; static bool TSCSupported = true; - pthread_once(&OnceProbe, +[] { TSCSupported = probeRequiredCPUFeatures(); }); + pthread_once( + &OnceProbe, +[] { TSCSupported = probeRequiredCPUFeatures(); }); if (TSCSupported) { Result.TSC = __xray::readTSC(Result.CPU); @@ -550,10 +559,11 @@ if (EventSize > static_cast(std::numeric_limits::max())) { static pthread_once_t Once = PTHREAD_ONCE_INIT; - pthread_once(&Once, +[] { - Report("Custom event size too large; truncating to %d.\n", - std::numeric_limits::max()); - }); + pthread_once( + &Once, +[] { + Report("Custom event size too large; truncating to %d.\n", + std::numeric_limits::max()); + }); } auto &TLD = getThreadLocalData(); @@ -579,10 +589,11 @@ if (EventSize > static_cast(std::numeric_limits::max())) { static pthread_once_t Once = PTHREAD_ONCE_INIT; - pthread_once(&Once, +[] { - Report("Typed event size too large; truncating to %d.\n", - std::numeric_limits::max()); - }); + pthread_once( + &Once, +[] { + Report("Typed event size too large; truncating to %d.\n", + std::numeric_limits::max()); + }); } auto &TLD = getThreadLocalData(); @@ -660,25 +671,28 @@ } static pthread_once_t OnceInit = PTHREAD_ONCE_INIT; - pthread_once(&OnceInit, +[] { - atomic_store(&TicksPerSec, - probeRequiredCPUFeatures() ? getTSCFrequency() - : __xray::NanosecondsPerSecond, - memory_order_release); - pthread_key_create(&Key, +[](void *TLDPtr) { - if (TLDPtr == nullptr) - return; - auto &TLD = *reinterpret_cast(TLDPtr); - if (TLD.BQ == nullptr) - return; - if (TLD.Buffer.Data == nullptr) - return; - auto EC = TLD.BQ->releaseBuffer(TLD.Buffer); - if (EC != BufferQueue::ErrorCode::Ok) - Report("At thread exit, failed to release buffer at %p; error=%s\n", - TLD.Buffer.Data, BufferQueue::getErrorString(EC)); - }); - }); + pthread_once( + &OnceInit, +[] { + atomic_store(&TicksPerSec, + probeRequiredCPUFeatures() ? getTSCFrequency() + : __xray::NanosecondsPerSecond, + memory_order_release); + pthread_key_create( + &Key, +[](void *TLDPtr) { + if (TLDPtr == nullptr) + return; + auto &TLD = *reinterpret_cast(TLDPtr); + if (TLD.BQ == nullptr) + return; + if (TLD.Buffer.Data == nullptr) + return; + auto EC = TLD.BQ->releaseBuffer(TLD.Buffer); + if (EC != BufferQueue::ErrorCode::Ok) + Report("At thread exit, failed to release buffer at %p; " + "error=%s\n", + TLD.Buffer.Data, BufferQueue::getErrorString(EC)); + }); + }); atomic_store(&ThresholdTicks, atomic_load_relaxed(&TicksPerSec) * Index: llvm/trunk/include/llvm/XRay/BlockIndexer.h =================================================================== --- llvm/trunk/include/llvm/XRay/BlockIndexer.h +++ llvm/trunk/include/llvm/XRay/BlockIndexer.h @@ -54,6 +54,8 @@ Error visit(NewBufferRecord &) override; Error visit(EndBufferRecord &) override; Error visit(FunctionRecord &) override; + Error visit(CustomEventRecordV5 &) override; + Error visit(TypedEventRecord &) override; /// The flush() function will clear out the current state of the visitor, to /// allow for explicitly flushing a block's records to the currently Index: llvm/trunk/include/llvm/XRay/BlockPrinter.h =================================================================== --- llvm/trunk/include/llvm/XRay/BlockPrinter.h +++ llvm/trunk/include/llvm/XRay/BlockPrinter.h @@ -50,6 +50,8 @@ Error visit(NewBufferRecord &) override; Error visit(EndBufferRecord &) override; Error visit(FunctionRecord &) override; + Error visit(CustomEventRecordV5 &) override; + Error visit(TypedEventRecord &) override; void reset() { CurrentState = State::Start; } }; Index: llvm/trunk/include/llvm/XRay/BlockVerifier.h =================================================================== --- llvm/trunk/include/llvm/XRay/BlockVerifier.h +++ llvm/trunk/include/llvm/XRay/BlockVerifier.h @@ -33,6 +33,7 @@ NewCPUId, TSCWrap, CustomEvent, + TypedEvent, Function, CallArg, EndOfBuffer, @@ -58,6 +59,8 @@ Error visit(NewBufferRecord &) override; Error visit(EndBufferRecord &) override; Error visit(FunctionRecord &) override; + Error visit(CustomEventRecordV5 &) override; + Error visit(TypedEventRecord &) override; Error verify(); void reset(); Index: llvm/trunk/include/llvm/XRay/FDRRecords.h =================================================================== --- llvm/trunk/include/llvm/XRay/FDRRecords.h +++ llvm/trunk/include/llvm/XRay/FDRRecords.h @@ -66,6 +66,7 @@ PIDEntry, NewBuffer, EndOfBuffer, + TypedEvent, }; Type type() const override { return Type::Metadata; } @@ -174,6 +175,52 @@ Error apply(RecordVisitor &V) override; }; +class CustomEventRecordV5 : public MetadataRecord { + int32_t Size = 0; + int32_t Delta = 0; + std::string Data{}; + friend class RecordInitializer; + +public: + CustomEventRecordV5() = default; + explicit CustomEventRecordV5(int32_t S, int32_t D, std::string P) + : MetadataRecord(), Size(S), Delta(D), Data(std::move(P)) {} + + MetadataType metadataType() const override { + return MetadataType::CustomEvent; + } + + int32_t size() const { return Size; } + int32_t delta() const { return Delta; } + StringRef data() const { return Data; } + + Error apply(RecordVisitor &V) override; +}; + +class TypedEventRecord : public MetadataRecord { + int32_t Size = 0; + int32_t Delta = 0; + uint16_t EventType = 0; + std::string Data{}; + friend class RecordInitializer; + +public: + TypedEventRecord() = default; + explicit TypedEventRecord(int32_t S, int32_t D, uint16_t E, std::string P) + : MetadataRecord(), Size(S), Delta(D), Data(std::move(P)) {} + + MetadataType metadataType() const override { + return MetadataType::TypedEvent; + } + + int32_t size() const { return Size; } + int32_t delta() const { return Delta; } + uint16_t eventType() const { return EventType; } + StringRef data() const { return Data; } + + Error apply(RecordVisitor &V) override; +}; + class CallArgRecord : public MetadataRecord { uint64_t Arg; friend class RecordInitializer; @@ -269,6 +316,8 @@ virtual Error visit(NewBufferRecord &) = 0; virtual Error visit(EndBufferRecord &) = 0; virtual Error visit(FunctionRecord &) = 0; + virtual Error visit(CustomEventRecordV5 &) = 0; + virtual Error visit(TypedEventRecord &) = 0; }; class RecordInitializer : public RecordVisitor { @@ -277,7 +326,7 @@ uint16_t Version; public: - static constexpr uint16_t DefaultVersion = 4u; + static constexpr uint16_t DefaultVersion = 5u; explicit RecordInitializer(DataExtractor &DE, uint32_t &OP, uint16_t V) : RecordVisitor(), E(DE), OffsetPtr(OP), Version(V) {} @@ -295,6 +344,8 @@ Error visit(NewBufferRecord &) override; Error visit(EndBufferRecord &) override; Error visit(FunctionRecord &) override; + Error visit(CustomEventRecordV5 &) override; + Error visit(TypedEventRecord &) override; }; } // namespace xray Index: llvm/trunk/include/llvm/XRay/FDRTraceExpander.h =================================================================== --- llvm/trunk/include/llvm/XRay/FDRTraceExpander.h +++ llvm/trunk/include/llvm/XRay/FDRTraceExpander.h @@ -49,6 +49,8 @@ Error visit(NewBufferRecord &) override; Error visit(EndBufferRecord &) override; Error visit(FunctionRecord &) override; + Error visit(CustomEventRecordV5 &) override; + Error visit(TypedEventRecord &) override; // Must be called after all the records have been processed, to handle the // most recent record generated. Index: llvm/trunk/include/llvm/XRay/FDRTraceWriter.h =================================================================== --- llvm/trunk/include/llvm/XRay/FDRTraceWriter.h +++ llvm/trunk/include/llvm/XRay/FDRTraceWriter.h @@ -43,6 +43,8 @@ Error visit(NewBufferRecord &) override; Error visit(EndBufferRecord &) override; Error visit(FunctionRecord &) override; + Error visit(CustomEventRecordV5 &) override; + Error visit(TypedEventRecord &) override; private: support::endian::Writer OS; Index: llvm/trunk/include/llvm/XRay/RecordPrinter.h =================================================================== --- llvm/trunk/include/llvm/XRay/RecordPrinter.h +++ llvm/trunk/include/llvm/XRay/RecordPrinter.h @@ -40,6 +40,8 @@ Error visit(NewBufferRecord &) override; Error visit(EndBufferRecord &) override; Error visit(FunctionRecord &) override; + Error visit(CustomEventRecordV5 &) override; + Error visit(TypedEventRecord &) override; }; } // namespace xray Index: llvm/trunk/lib/XRay/BlockIndexer.cpp =================================================================== --- llvm/trunk/lib/XRay/BlockIndexer.cpp +++ llvm/trunk/lib/XRay/BlockIndexer.cpp @@ -39,6 +39,16 @@ return Error::success(); } +Error BlockIndexer::visit(CustomEventRecordV5 &R) { + CurrentBlock.Records.push_back(&R); + return Error::success(); +} + +Error BlockIndexer::visit(TypedEventRecord &R) { + CurrentBlock.Records.push_back(&R); + return Error::success(); +} + Error BlockIndexer::visit(CallArgRecord &R) { CurrentBlock.Records.push_back(&R); return Error::success(); Index: llvm/trunk/lib/XRay/BlockPrinter.cpp =================================================================== --- llvm/trunk/lib/XRay/BlockPrinter.cpp +++ llvm/trunk/lib/XRay/BlockPrinter.cpp @@ -68,6 +68,24 @@ return E; } +Error BlockPrinter::visit(CustomEventRecordV5 &R) { + if (CurrentState == State::Metadata) + OS << "\n"; + CurrentState = State::CustomEvent; + OS << "* "; + auto E = RP.visit(R); + return E; +} + +Error BlockPrinter::visit(TypedEventRecord &R) { + if (CurrentState == State::Metadata) + OS << "\n"; + CurrentState = State::CustomEvent; + OS << "* "; + auto E = RP.visit(R); + return E; +} + // Function call printing. Error BlockPrinter::visit(FunctionRecord &R) { if (CurrentState == State::Metadata) Index: llvm/trunk/lib/XRay/BlockVerifier.cpp =================================================================== --- llvm/trunk/lib/XRay/BlockVerifier.cpp +++ llvm/trunk/lib/XRay/BlockVerifier.cpp @@ -43,6 +43,8 @@ return "CallArg"; case BlockVerifier::State::EndOfBuffer: return "EndOfBuffer"; + case BlockVerifier::State::TypedEvent: + return "TypedEvent"; case BlockVerifier::State::StateMax: case BlockVerifier::State::Unknown: return "Unknown"; @@ -75,27 +77,34 @@ {State::NewCPUId, {mask(State::NewCPUId) | mask(State::TSCWrap) | mask(State::CustomEvent) | mask(State::Function) | - mask(State::EndOfBuffer)}}, + mask(State::EndOfBuffer) | mask(State::TypedEvent)}}, {State::TSCWrap, {mask(State::TSCWrap) | mask(State::NewCPUId) | mask(State::CustomEvent) | mask(State::Function) | - mask(State::EndOfBuffer)}}, + mask(State::EndOfBuffer) | mask(State::TypedEvent)}}, {State::CustomEvent, {mask(State::CustomEvent) | mask(State::TSCWrap) | mask(State::NewCPUId) | mask(State::Function) | - mask(State::EndOfBuffer)}}, + mask(State::EndOfBuffer) | mask(State::TypedEvent)}}, + + {State::TypedEvent, + {mask(State::TypedEvent) | mask(State::TSCWrap) | + mask(State::NewCPUId) | mask(State::Function) | + mask(State::EndOfBuffer) | mask(State::CustomEvent)}}, {State::Function, {mask(State::Function) | mask(State::TSCWrap) | mask(State::NewCPUId) | mask(State::CustomEvent) | - mask(State::CallArg) | mask(State::EndOfBuffer)}}, + mask(State::CallArg) | mask(State::EndOfBuffer) | + mask(State::TypedEvent)}}, {State::CallArg, {mask(State::CallArg) | mask(State::Function) | mask(State::TSCWrap) | mask(State::NewCPUId) | - mask(State::CustomEvent) | mask(State::EndOfBuffer)}}, + mask(State::CustomEvent) | mask(State::EndOfBuffer) | + mask(State::TypedEvent)}}, {State::EndOfBuffer, {}}}}; @@ -145,6 +154,14 @@ return transition(State::CustomEvent); } +Error BlockVerifier::visit(CustomEventRecordV5 &) { + return transition(State::CustomEvent); +} + +Error BlockVerifier::visit(TypedEventRecord &) { + return transition(State::TypedEvent); +} + Error BlockVerifier::visit(CallArgRecord &) { return transition(State::CallArg); } @@ -169,6 +186,7 @@ case State::EndOfBuffer: case State::NewCPUId: case State::CustomEvent: + case State::TypedEvent: case State::Function: case State::CallArg: case State::TSCWrap: Index: llvm/trunk/lib/XRay/FDRRecordProducer.cpp =================================================================== --- llvm/trunk/lib/XRay/FDRRecordProducer.cpp +++ llvm/trunk/lib/XRay/FDRRecordProducer.cpp @@ -53,14 +53,15 @@ case MetadataRecordKinds::WalltimeMarkerKind: return make_unique(); case MetadataRecordKinds::CustomEventMarkerKind: + if (Header.Version >= 5) + return make_unique(); return make_unique(); case MetadataRecordKinds::CallArgumentKind: return make_unique(); case MetadataRecordKinds::BufferExtentsKind: return make_unique(); case MetadataRecordKinds::TypedEventMarkerKind: - return createStringError(std::make_error_code(std::errc::invalid_argument), - "Encountered an unsupported TypedEventMarker."); + return make_unique(); case MetadataRecordKinds::PidKind: return make_unique(); case MetadataRecordKinds::EnumEndMarker: Index: llvm/trunk/lib/XRay/FDRRecords.cpp =================================================================== --- llvm/trunk/lib/XRay/FDRRecords.cpp +++ llvm/trunk/lib/XRay/FDRRecords.cpp @@ -26,6 +26,8 @@ Error NewBufferRecord::apply(RecordVisitor &V) { return V.visit(*this); } Error EndBufferRecord::apply(RecordVisitor &V) { return V.visit(*this); } Error FunctionRecord::apply(RecordVisitor &V) { return V.visit(*this); } +Error CustomEventRecordV5::apply(RecordVisitor &V) { return V.visit(*this); } +Error TypedEventRecord::apply(RecordVisitor &V) { return V.visit(*this); } } // namespace xray } // namespace llvm Index: llvm/trunk/lib/XRay/FDRTraceExpander.cpp =================================================================== --- llvm/trunk/lib/XRay/FDRTraceExpander.cpp +++ llvm/trunk/lib/XRay/FDRTraceExpander.cpp @@ -52,6 +52,39 @@ return Error::success(); } +Error TraceExpander::visit(CustomEventRecordV5 &R) { + resetCurrentRecord(); + if (!IgnoringRecords) { + BaseTSC += R.delta(); + CurrentRecord.TSC = BaseTSC; + CurrentRecord.CPU = CPUId; + CurrentRecord.PId = PID; + CurrentRecord.TId = TID; + CurrentRecord.Type = RecordTypes::CUSTOM_EVENT; + std::copy(R.data().begin(), R.data().end(), + std::back_inserter(CurrentRecord.Data)); + BuildingRecord = true; + } + return Error::success(); +} + +Error TraceExpander::visit(TypedEventRecord &R) { + resetCurrentRecord(); + if (!IgnoringRecords) { + BaseTSC += R.delta(); + CurrentRecord.TSC = BaseTSC; + CurrentRecord.CPU = CPUId; + CurrentRecord.PId = PID; + CurrentRecord.TId = TID; + CurrentRecord.RecordType = R.eventType(); + CurrentRecord.Type = RecordTypes::TYPED_EVENT; + std::copy(R.data().begin(), R.data().end(), + std::back_inserter(CurrentRecord.Data)); + BuildingRecord = true; + } + return Error::success(); +} + Error TraceExpander::visit(CallArgRecord &R) { CurrentRecord.CallArgs.push_back(R.arg()); CurrentRecord.Type = RecordTypes::ENTER_ARG; Index: llvm/trunk/lib/XRay/FDRTraceWriter.cpp =================================================================== --- llvm/trunk/lib/XRay/FDRTraceWriter.cpp +++ llvm/trunk/lib/XRay/FDRTraceWriter.cpp @@ -102,6 +102,24 @@ return Error::success(); } +Error FDRTraceWriter::visit(CustomEventRecordV5 &R) { + if (auto E = writeMetadata<5u>(OS, R.size(), R.delta())) + return E; + auto D = R.data(); + ArrayRef Bytes(D.data(), D.size()); + OS.write(Bytes); + return Error::success(); +} + +Error FDRTraceWriter::visit(TypedEventRecord &R) { + if (auto E = writeMetadata<7u>(OS, R.size(), R.delta(), R.eventType())) + return E; + auto D = R.data(); + ArrayRef Bytes(D.data(), D.size()); + OS.write(Bytes); + return Error::success(); +} + Error FDRTraceWriter::visit(CallArgRecord &R) { return writeMetadata<6u>(OS, R.arg()); } Index: llvm/trunk/lib/XRay/FileHeaderReader.cpp =================================================================== --- llvm/trunk/lib/XRay/FileHeaderReader.cpp +++ llvm/trunk/lib/XRay/FileHeaderReader.cpp @@ -63,10 +63,6 @@ // Manually advance the offset pointer 16 bytes, after getting a raw memcpy // from the underlying data. OffsetPtr += 16; - if (FileHeader.Version < 1 || FileHeader.Version > 4) - return createStringError(std::make_error_code(std::errc::invalid_argument), - "Unsupported XRay file version: %d at offset %d", - FileHeader.Version, OffsetPtr); return std::move(FileHeader); } Index: llvm/trunk/lib/XRay/RecordInitializer.cpp =================================================================== --- llvm/trunk/lib/XRay/RecordInitializer.cpp +++ llvm/trunk/lib/XRay/RecordInitializer.cpp @@ -151,6 +151,105 @@ return Error::success(); } +Error RecordInitializer::visit(CustomEventRecordV5 &R) { + if (!E.isValidOffsetForDataOfSize(OffsetPtr, + MetadataRecord::kMetadataBodySize)) + return createStringError(std::make_error_code(std::errc::bad_address), + "Invalid offset for a custom event record (%d).", + OffsetPtr); + + auto BeginOffset = OffsetPtr; + auto PreReadOffset = OffsetPtr; + + R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t)); + if (PreReadOffset == OffsetPtr) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Cannot read a custom event record size field offset %d.", OffsetPtr); + + PreReadOffset = OffsetPtr; + R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t)); + if (PreReadOffset == OffsetPtr) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Cannot read a custom event record TSC delta field at offset %d.", + OffsetPtr); + + assert(OffsetPtr > BeginOffset && + OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize); + OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset); + + // Next we read in a fixed chunk of data from the given offset. + if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size)) + return createStringError( + std::make_error_code(std::errc::bad_address), + "Cannot read %d bytes of custom event data from offset %d.", R.Size, + OffsetPtr); + + std::vector Buffer; + Buffer.resize(R.Size); + if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data()) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Failed reading data into buffer of size %d at offset %d.", R.Size, + OffsetPtr); + R.Data.assign(Buffer.begin(), Buffer.end()); + return Error::success(); +} + +Error RecordInitializer::visit(TypedEventRecord &R) { + if (!E.isValidOffsetForDataOfSize(OffsetPtr, + MetadataRecord::kMetadataBodySize)) + return createStringError(std::make_error_code(std::errc::bad_address), + "Invalid offset for a typed event record (%d).", + OffsetPtr); + + auto BeginOffset = OffsetPtr; + auto PreReadOffset = OffsetPtr; + + R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t)); + if (PreReadOffset == OffsetPtr) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Cannot read a typed event record size field offset %d.", OffsetPtr); + + PreReadOffset = OffsetPtr; + R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t)); + if (PreReadOffset == OffsetPtr) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Cannot read a typed event record TSC delta field at offset %d.", + OffsetPtr); + + PreReadOffset = OffsetPtr; + R.EventType = E.getU16(&OffsetPtr); + if (PreReadOffset == OffsetPtr) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Cannot read a typed event record type field at offset %d.", OffsetPtr); + + assert(OffsetPtr > BeginOffset && + OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize); + OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset); + + // Next we read in a fixed chunk of data from the given offset. + if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size)) + return createStringError( + std::make_error_code(std::errc::bad_address), + "Cannot read %d bytes of custom event data from offset %d.", R.Size, + OffsetPtr); + + std::vector Buffer; + Buffer.resize(R.Size); + if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data()) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Failed reading data into buffer of size %d at offset %d.", R.Size, + OffsetPtr); + R.Data.assign(Buffer.begin(), Buffer.end()); + return Error::success(); +} + Error RecordInitializer::visit(CallArgRecord &R) { if (!E.isValidOffsetForDataOfSize(OffsetPtr, MetadataRecord::kMetadataBodySize)) Index: llvm/trunk/lib/XRay/RecordPrinter.cpp =================================================================== --- llvm/trunk/lib/XRay/RecordPrinter.cpp +++ llvm/trunk/lib/XRay/RecordPrinter.cpp @@ -42,6 +42,21 @@ return Error::success(); } +Error RecordPrinter::visit(CustomEventRecordV5 &R) { + OS << formatv("", + R.delta(), R.size(), R.data()) + << Delim; + return Error::success(); +} + +Error RecordPrinter::visit(TypedEventRecord &R) { + OS << formatv( + "", R.arg()) << Delim; return Error::success(); Index: llvm/trunk/lib/XRay/Trace.cpp =================================================================== --- llvm/trunk/lib/XRay/Trace.cpp +++ llvm/trunk/lib/XRay/Trace.cpp @@ -247,6 +247,17 @@ /// ThreadBuffer: BufferExtents NewBuffer WallClockTime Pid NewCPUId /// FunctionSequence /// EOB: *deprecated* +/// +/// In Version 4, we make the following changes: +/// +/// CustomEventRecord now includes the CPU data. +/// +/// In Version 5, we make the following changes: +/// +/// CustomEventRecord and TypedEventRecord now use TSC delta encoding similar to +/// what FunctionRecord instances use, and we no longer need to include the CPU +/// id in the CustomEventRecord. +/// Error loadFDRLog(StringRef Data, bool IsLittleEndian, XRayFileHeader &FileHeader, std::vector &Records) { @@ -435,7 +446,7 @@ } break; case FLIGHT_DATA_RECORDER_FORMAT: - if (Version >= 1 && Version <= 4) { + if (Version >= 1 && Version <= 5) { if (auto E = loadFDRLog(DE.getData(), DE.isLittleEndian(), T.FileHeader, T.Records)) return std::move(E); Index: llvm/trunk/unittests/XRay/FDRRecordsTest.cpp =================================================================== --- llvm/trunk/unittests/XRay/FDRRecordsTest.cpp +++ llvm/trunk/unittests/XRay/FDRRecordsTest.cpp @@ -34,6 +34,8 @@ .add(1) .add(RecordTypes::ENTER, 1, 1) .add(RecordTypes::EXIT, 1, 100) + .add(1, 4, "XRAY") + .add(1, 4, 2, "XRAY") .consume(); auto Block1 = LogBuilder() .add(100) @@ -42,6 +44,8 @@ .add(1) .add(RecordTypes::ENTER, 1, 1) .add(RecordTypes::EXIT, 1, 100) + .add(1, 4, "XRAY") + .add(1, 4, 2, "XRAY") .consume(); auto Block2 = LogBuilder() .add(100) @@ -50,6 +54,8 @@ .add(1) .add(RecordTypes::ENTER, 1, 1) .add(RecordTypes::EXIT, 1, 100) + .add(1, 4, "XRAY") + .add(1, 4, 2, "XRAY") .consume(); BlockIndexer::Index Index; BlockIndexer Indexer(Index); @@ -92,6 +98,8 @@ .add(1, 2) .add(RecordTypes::ENTER, 1, 1) .add(RecordTypes::EXIT, 1, 100) + .add(1, 4, "XRAY") + .add(1, 4, 2, "XRAY") .consume(); auto Block1 = LogBuilder() .add(64) @@ -101,6 +109,8 @@ .add(1, 2) .add(RecordTypes::ENTER, 1, 1) .add(RecordTypes::EXIT, 1, 100) + .add(1, 4, "XRAY") + .add(1, 4, 2, "XRAY") .consume(); auto Block2 = LogBuilder() .add(64) @@ -110,6 +120,8 @@ .add(1, 2) .add(RecordTypes::ENTER, 1, 1) .add(RecordTypes::EXIT, 1, 100) + .add(1, 4, "XRAY") + .add(1, 4, 2, "XRAY") .consume(); // First, index the records in different blocks.