diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/XRay/Trace.cpp | |
parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) |
Notes
Diffstat (limited to 'lib/XRay/Trace.cpp')
-rw-r--r-- | lib/XRay/Trace.cpp | 78 |
1 files changed, 64 insertions, 14 deletions
diff --git a/lib/XRay/Trace.cpp b/lib/XRay/Trace.cpp index d1fcf1c35b36..a8764b25483c 100644 --- a/lib/XRay/Trace.cpp +++ b/lib/XRay/Trace.cpp @@ -48,7 +48,8 @@ Error readBinaryFormatHeader(StringRef Data, XRayFileHeader &FileHeader) { FileHeader.NonstopTSC = Bitfield & 1uL << 1; FileHeader.CycleFrequency = HeaderExtractor.getU64(&OffsetPtr); std::memcpy(&FileHeader.FreeFormData, Data.bytes_begin() + OffsetPtr, 16); - if (FileHeader.Version != 1 && FileHeader.Version != 2) + if (FileHeader.Version != 1 && FileHeader.Version != 2 && + FileHeader.Version != 3) return make_error<StringError>( Twine("Unsupported XRay file version: ") + Twine(FileHeader.Version), std::make_error_code(std::errc::invalid_argument)); @@ -78,7 +79,8 @@ Error loadNaiveFormatLog(StringRef Data, XRayFileHeader &FileHeader, // (4) sint32 : function id // (8) uint64 : tsc // (4) uint32 : thread id - // (12) - : padding + // (4) uint32 : process id + // (8) - : padding for (auto S = Data.drop_front(32); !S.empty(); S = S.drop_front(32)) { DataExtractor RecordExtractor(S, true, 8); uint32_t OffsetPtr = 0; @@ -110,6 +112,7 @@ Error loadNaiveFormatLog(StringRef Data, XRayFileHeader &FileHeader, Record.FuncId = RecordExtractor.getSigned(&OffsetPtr, sizeof(int32_t)); Record.TSC = RecordExtractor.getU64(&OffsetPtr); Record.TId = RecordExtractor.getU32(&OffsetPtr); + Record.PId = RecordExtractor.getU32(&OffsetPtr); break; } case 1: { // Arg payload record. @@ -118,14 +121,18 @@ Error loadNaiveFormatLog(StringRef Data, XRayFileHeader &FileHeader, OffsetPtr += 2; int32_t FuncId = RecordExtractor.getSigned(&OffsetPtr, sizeof(int32_t)); auto TId = RecordExtractor.getU32(&OffsetPtr); - if (Record.FuncId != FuncId || Record.TId != TId) + auto PId = RecordExtractor.getU32(&OffsetPtr); + + // Make a check for versions above 3 for the Pid field + if (Record.FuncId != FuncId || Record.TId != TId || + (FileHeader.Version >= 3 ? Record.PId != PId : false)) return make_error<StringError>( - Twine("Corrupted log, found payload following non-matching " - "function + thread record. Record for ") + - Twine(Record.FuncId) + " != " + Twine(FuncId), + Twine("Corrupted log, found arg payload following non-matching " + "function + thread record. Record for function ") + + Twine(Record.FuncId) + " != " + Twine(FuncId) + "; offset: " + + Twine(S.data() - Data.data()), std::make_error_code(std::errc::executable_format_error)); - // Advance another four bytes to avoid padding. - OffsetPtr += 4; + auto Arg = RecordExtractor.getU64(&OffsetPtr); Record.CallArgs.push_back(Arg); break; @@ -147,6 +154,7 @@ Error loadNaiveFormatLog(StringRef Data, XRayFileHeader &FileHeader, struct FDRState { uint16_t CPUId; uint16_t ThreadId; + int32_t ProcessId; uint64_t BaseTSC; /// Encode some of the state transitions for the FDR log reader as explicit @@ -160,6 +168,7 @@ struct FDRState { CUSTOM_EVENT_DATA, CALL_ARGUMENT, BUFFER_EXTENTS, + PID_RECORD, }; Token Expects; @@ -187,6 +196,8 @@ const char *fdrStateToTwine(const FDRState::Token &state) { return "CALL_ARGUMENT"; case FDRState::Token::BUFFER_EXTENTS: return "BUFFER_EXTENTS"; + case FDRState::Token::PID_RECORD: + return "PID_RECORD"; } return "UNKNOWN"; } @@ -267,6 +278,23 @@ Error processFDRWallTimeRecord(FDRState &State, uint8_t RecordFirstByte, return Error::success(); } +/// State transition when a PidRecord is encountered. +Error processFDRPidRecord(FDRState &State, uint8_t RecordFirstByte, + DataExtractor &RecordExtractor) { + + if (State.Expects != FDRState::Token::PID_RECORD) + return make_error<StringError>( + Twine("Malformed log. Read Pid record kind out of sequence; " + "expected: ") + + fdrStateToTwine(State.Expects), + std::make_error_code(std::errc::executable_format_error)); + + uint32_t OffsetPtr = 1; // Read starting after the first byte. + State.ProcessId = RecordExtractor.getU32(&OffsetPtr); + State.Expects = FDRState::Token::NEW_CPU_ID_RECORD; + return Error::success(); +} + /// State transition when a CustomEventMarker is encountered. Error processCustomEventMarker(FDRState &State, uint8_t RecordFirstByte, DataExtractor &RecordExtractor, @@ -324,6 +352,9 @@ Error processFDRCallArgumentRecord(FDRState &State, uint8_t RecordFirstByte, /// Beginning with Version 2 of the FDR log, we do not depend on the size of the /// buffer, but rather use the extents to determine how far to read in the log /// for this particular buffer. +/// +/// In Version 3, FDR log now includes a pid metadata record after +/// WallTimeMarker Error processFDRMetadataRecord(FDRState &State, uint8_t RecordFirstByte, DataExtractor &RecordExtractor, size_t &RecordSize, @@ -360,6 +391,9 @@ Error processFDRMetadataRecord(FDRState &State, uint8_t RecordFirstByte, if (auto E = processFDRWallTimeRecord(State, RecordFirstByte, RecordExtractor)) return E; + // In Version 3 and and above, a PidRecord is expected after WallTimeRecord + if (Version >= 3) + State.Expects = FDRState::Token::PID_RECORD; break; case 5: // CustomEventMarker if (auto E = processCustomEventMarker(State, RecordFirstByte, @@ -375,6 +409,10 @@ Error processFDRMetadataRecord(FDRState &State, uint8_t RecordFirstByte, if (auto E = processBufferExtents(State, RecordFirstByte, RecordExtractor)) return E; break; + case 9: // Pid + if (auto E = processFDRPidRecord(State, RecordFirstByte, RecordExtractor)) + return E; + break; default: // Widen the record type to uint16_t to prevent conversion to char. return make_error<StringError>( @@ -404,6 +442,10 @@ Error processFDRFunctionRecord(FDRState &State, uint8_t RecordFirstByte, return make_error<StringError>( "Malformed log. Received Function Record when expecting wallclock.", std::make_error_code(std::errc::executable_format_error)); + case FDRState::Token::PID_RECORD: + return make_error<StringError>( + "Malformed log. Received Function Record when expecting pid.", + std::make_error_code(std::errc::executable_format_error)); case FDRState::Token::NEW_CPU_ID_RECORD: return make_error<StringError>( "Malformed log. Received Function Record before first CPU record.", @@ -433,6 +475,7 @@ Error processFDRFunctionRecord(FDRState &State, uint8_t RecordFirstByte, } Record.CPU = State.CPUId; Record.TId = State.ThreadId; + Record.PId = State.ProcessId; // Back up to read first 32 bits, including the 4 we pulled RecordType // and RecordKind out of. The remaining 28 are FunctionId. uint32_t OffsetPtr = 0; @@ -476,6 +519,7 @@ Error processFDRFunctionRecord(FDRState &State, uint8_t RecordFirstByte, /// BufSize: 8 byte unsigned integer indicating how large the buffer is. /// NewBuffer: 16 byte metadata record with Thread Id. /// WallClockTime: 16 byte metadata record with human readable time. +/// Pid: 16 byte metadata record with Pid /// NewCPUId: 16 byte metadata record with CPUId and a 64 bit TSC reading. /// EOB: 16 byte record in a thread buffer plus mem garbage to fill BufSize. /// FunctionSequence: NewCPUId | TSCWrap | FunctionRecord @@ -489,6 +533,11 @@ Error processFDRFunctionRecord(FDRState &State, uint8_t RecordFirstByte, /// BufferExtents: 16 byte metdata record describing how many usable bytes are /// in the buffer. This is measured from the start of the buffer /// and must always be at least 48 (bytes). +/// +/// In Version 3, we make the following changes: +/// +/// ThreadBuffer: BufferExtents NewBuffer WallClockTime Pid NewCPUId +/// FunctionSequence /// EOB: *deprecated* Error loadFDRLog(StringRef Data, XRayFileHeader &FileHeader, std::vector<XRayRecord> &Records) { @@ -522,6 +571,7 @@ Error loadFDRLog(StringRef Data, XRayFileHeader &FileHeader, InitialExpectation = FDRState::Token::NEW_BUFFER_RECORD_OR_EOF; break; case 2: + case 3: InitialExpectation = FDRState::Token::BUFFER_EXTENTS; break; default: @@ -529,7 +579,7 @@ Error loadFDRLog(StringRef Data, XRayFileHeader &FileHeader, Twine("Unsupported version '") + Twine(FileHeader.Version) + "'", std::make_error_code(std::errc::executable_format_error)); } - FDRState State{0, 0, 0, InitialExpectation, BufferSize, 0}; + FDRState State{0, 0, 0, 0, InitialExpectation, BufferSize, 0}; // RecordSize will tell the loop how far to seek ahead based on the record // type that we have just read. @@ -571,7 +621,7 @@ Error loadFDRLog(StringRef Data, XRayFileHeader &FileHeader, if (!isBufferExtents) State.CurrentBufferConsumed += RecordSize; assert(State.CurrentBufferConsumed <= State.CurrentBufferSize); - if (FileHeader.Version == 2 && + if ((FileHeader.Version == 2 || FileHeader.Version == 3) && State.CurrentBufferSize == State.CurrentBufferConsumed) { // In Version 2 of the log, we don't need to scan to the end of the thread // buffer if we've already consumed all the bytes we need to. @@ -620,8 +670,8 @@ Error loadYAMLLog(StringRef Data, XRayFileHeader &FileHeader, Records.clear(); std::transform(Trace.Records.begin(), Trace.Records.end(), std::back_inserter(Records), [&](const YAMLXRayRecord &R) { - return XRayRecord{R.RecordType, R.CPU, R.Type, R.FuncId, - R.TSC, R.TId, R.CallArgs}; + return XRayRecord{R.RecordType, R.CPU, R.Type, R.FuncId, + R.TSC, R.TId, R.PId, R.CallArgs}; }); return Error::success(); } @@ -680,7 +730,7 @@ Expected<Trace> llvm::xray::loadTraceFile(StringRef Filename, bool Sort) { Trace T; switch (Type) { case NAIVE_FORMAT: - if (Version == 1 || Version == 2) { + if (Version == 1 || Version == 2 || Version == 3) { if (auto E = loadNaiveFormatLog(Data, T.FileHeader, T.Records)) return std::move(E); } else { @@ -691,7 +741,7 @@ Expected<Trace> llvm::xray::loadTraceFile(StringRef Filename, bool Sort) { } break; case FLIGHT_DATA_RECORDER_FORMAT: - if (Version == 1 || Version == 2) { + if (Version == 1 || Version == 2 || Version == 3) { if (auto E = loadFDRLog(Data, T.FileHeader, T.Records)) return std::move(E); } else { |