Index: llvm/trunk/include/llvm/XRay/XRayRecord.h =================================================================== --- llvm/trunk/include/llvm/XRay/XRayRecord.h +++ llvm/trunk/include/llvm/XRay/XRayRecord.h @@ -53,7 +53,7 @@ /// This may or may not correspond to actual record types in the raw trace (as /// the loader implementation may synthesize this information in the process of /// of loading). -enum class RecordTypes { ENTER, EXIT, TAIL_EXIT }; +enum class RecordTypes { ENTER, EXIT, TAIL_EXIT, ENTER_ARG }; struct XRayRecord { /// The type of record. @@ -73,6 +73,9 @@ /// The thread ID for the currently running thread. uint32_t TId; + + /// The function call arguments. + std::vector CallArgs; }; } // namespace xray Index: llvm/trunk/include/llvm/XRay/YAMLXRayRecord.h =================================================================== --- llvm/trunk/include/llvm/XRay/YAMLXRayRecord.h +++ llvm/trunk/include/llvm/XRay/YAMLXRayRecord.h @@ -37,6 +37,7 @@ std::string Function; uint64_t TSC; uint32_t TId; + std::vector CallArgs; }; struct YAMLXRayTrace { @@ -55,6 +56,7 @@ IO.enumCase(Type, "function-enter", xray::RecordTypes::ENTER); IO.enumCase(Type, "function-exit", xray::RecordTypes::EXIT); IO.enumCase(Type, "function-tail-exit", xray::RecordTypes::TAIL_EXIT); + IO.enumCase(Type, "function-enter-arg", xray::RecordTypes::ENTER_ARG); } }; @@ -74,6 +76,7 @@ IO.mapRequired("type", Record.RecordType); IO.mapRequired("func-id", Record.FuncId); IO.mapOptional("function", Record.Function); + IO.mapOptional("args", Record.CallArgs); IO.mapRequired("cpu", Record.CPU); IO.mapRequired("thread", Record.TId); IO.mapRequired("kind", Record.Type); @@ -83,6 +86,16 @@ static constexpr bool flow = true; }; +template <> struct SequenceTraits> { + static constexpr bool flow = true; + static size_t size(IO &IO, std::vector &V) { return V.size(); } + static uint64_t &element(IO &IO, std::vector &V, size_t Index) { + if (Index >= V.size()) + V.resize(Index + 1); + return V[Index]; + } +}; + template <> struct MappingTraits { static void mapping(IO &IO, xray::YAMLXRayTrace &Trace) { // A trace file contains two parts, the header and the list of all the Index: llvm/trunk/lib/XRay/Trace.cpp =================================================================== --- llvm/trunk/lib/XRay/Trace.cpp +++ llvm/trunk/lib/XRay/Trace.cpp @@ -128,6 +128,7 @@ FUNCTION_SEQUENCE, SCAN_TO_END_OF_THREAD_BUF, CUSTOM_EVENT_DATA, + CALL_ARGUMENT, }; Token Expects; @@ -151,6 +152,8 @@ return "SCAN_TO_END_OF_THREAD_BUF"; case FDRState::Token::CUSTOM_EVENT_DATA: return "CUSTOM_EVENT_DATA"; + case FDRState::Token::CALL_ARGUMENT: + return "CALL_ARGUMENT"; } return "UNKNOWN"; } @@ -238,6 +241,22 @@ return Error::success(); } +/// State transition when a CallArgumentRecord is encountered. +Error processFDRCallArgumentRecord(FDRState &State, uint8_t RecordFirstByte, + DataExtractor &RecordExtractor, + std::vector &Records) { + uint32_t OffsetPtr = 1; // Read starting after the first byte. + auto &Enter = Records.back(); + + if (Enter.Type != RecordTypes::ENTER) + return make_error( + "CallArgument needs to be right after a function entry", + std::make_error_code(std::errc::executable_format_error)); + Enter.Type = RecordTypes::ENTER_ARG; + Enter.CallArgs.emplace_back(RecordExtractor.getU64(&OffsetPtr)); + return Error::success(); +} + /// Advances the state machine for reading the FDR record type by reading one /// Metadata Record and updating the State appropriately based on the kind of /// record encountered. The RecordKind is encoded in the first byte of the @@ -245,7 +264,8 @@ /// to determine that this is a metadata record as opposed to a function record. Error processFDRMetadataRecord(FDRState &State, uint8_t RecordFirstByte, DataExtractor &RecordExtractor, - size_t &RecordSize) { + size_t &RecordSize, + std::vector &Records) { // The remaining 7 bits are the RecordKind enum. uint8_t RecordKind = RecordFirstByte >> 1; switch (RecordKind) { @@ -279,6 +299,11 @@ RecordExtractor, RecordSize)) return E; break; + case 6: // CallArgument + if (auto E = processFDRCallArgumentRecord(State, RecordFirstByte, + RecordExtractor, Records)) + return E; + break; default: // Widen the record type to uint16_t to prevent conversion to char. return make_error( @@ -434,7 +459,7 @@ if (isMetadataRecord) { RecordSize = 16; if (auto E = processFDRMetadataRecord(State, BitField, RecordExtractor, - RecordSize)) + RecordSize, Records)) return E; } else { // Process Function Record RecordSize = 8; Index: llvm/trunk/test/tools/llvm-xray/X86/convert-fdr-arg1-to-yaml.txt =================================================================== --- llvm/trunk/test/tools/llvm-xray/X86/convert-fdr-arg1-to-yaml.txt +++ llvm/trunk/test/tools/llvm-xray/X86/convert-fdr-arg1-to-yaml.txt @@ -0,0 +1,13 @@ +; RUN: llvm-xray convert %S/Inputs/fdr-log-arg1.xray -f=yaml -o - | FileCheck %s + +; CHECK: --- +; CHECK-NEXT: header: +; CHECK-NEXT: version: 1 +; CHECK-NEXT: type: 1 +; CHECK-NEXT: constant-tsc: true +; CHECK-NEXT: nonstop-tsc: true +; CHECK-NEXT: cycle-frequency: 3500000000 +; CHECK-NEXT: records: +; CHECK-NEXT: - { type: 0, func-id: 1, function: '1', args: [ 1 ], cpu: 49, thread: 14648, kind: function-enter-arg, tsc: 18828908666543318 } +; CHECK-NEXT: - { type: 0, func-id: 1, function: '1', cpu: 49, thread: 14648, kind: function-exit, tsc: 18828908666595604 } +; CHECK-NEXT: ... Index: llvm/trunk/tools/llvm-xray/xray-account.cc =================================================================== --- llvm/trunk/tools/llvm-xray/xray-account.cc +++ llvm/trunk/tools/llvm-xray/xray-account.cc @@ -146,7 +146,8 @@ auto &ThreadStack = PerThreadFunctionStack[Record.TId]; switch (Record.Type) { - case RecordTypes::ENTER: { + case RecordTypes::ENTER: + case RecordTypes::ENTER_ARG: { ThreadStack.emplace_back(Record.FuncId, Record.TSC); break; } Index: llvm/trunk/tools/llvm-xray/xray-converter.cc =================================================================== --- llvm/trunk/tools/llvm-xray/xray-converter.cc +++ llvm/trunk/tools/llvm-xray/xray-converter.cc @@ -86,7 +86,7 @@ Trace.Records.push_back({R.RecordType, R.CPU, R.Type, R.FuncId, Symbolize ? FuncIdHelper.SymbolOrNumber(R.FuncId) : llvm::to_string(R.FuncId), - R.TSC, R.TId}); + R.TSC, R.TId, R.CallArgs}); } Output Out(OS, nullptr, 0); Out << Trace; @@ -123,6 +123,7 @@ Writer.write(static_cast(R.CPU)); switch (R.Type) { case RecordTypes::ENTER: + case RecordTypes::ENTER_ARG: Writer.write(uint8_t{0}); break; case RecordTypes::EXIT: Index: llvm/trunk/tools/llvm-xray/xray-graph.cc =================================================================== --- llvm/trunk/tools/llvm-xray/xray-graph.cc +++ llvm/trunk/tools/llvm-xray/xray-graph.cc @@ -208,7 +208,8 @@ auto &ThreadStack = PerThreadFunctionStack[Record.TId]; switch (Record.Type) { - case RecordTypes::ENTER: { + case RecordTypes::ENTER: + case RecordTypes::ENTER_ARG: { if (Record.FuncId != 0 && G.count(Record.FuncId) == 0) G[Record.FuncId].SymbolName = FuncIdHelper.SymbolOrNumber(Record.FuncId); ThreadStack.push_back({Record.FuncId, Record.TSC});