summaryrefslogtreecommitdiff
path: root/lib/XRay/Trace.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
commiteb11fae6d08f479c0799db45860a98af528fa6e7 (patch)
tree44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/XRay/Trace.cpp
parentb8a2042aa938069e862750553db0e4d82d25822c (diff)
Notes
Diffstat (limited to 'lib/XRay/Trace.cpp')
-rw-r--r--lib/XRay/Trace.cpp78
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 {