[llvm] r341029 - [XRay] FDRTraceWriter and FDR Trace Loading
Dean Michael Berris via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 31 03:01:57 PDT 2018
Actually, I think I found it — it seems that I’m relying on bitfield order being portable, but it isn’t. I’m working on a fix now.
> On 31 Aug 2018, at 19:37, Dean Michael Berris <dean.berris at gmail.com> wrote:
>
> Oops, thanks for pointing it out.
>
> Is there a way to make this XFAIL on Windows?
>
> This is really bizarre, since I don’t have a way of reproducing this.
>
>> On 31 Aug 2018, at 18:37, via llvm-commits <llvm-commits at lists.llvm.org> wrote:
>>
>> Hi Dean,
>>
>> The unit test you added in this commit, FDRTraceWriterTest is causing 3 failures on the PS4 Windows bot, can you take a look?
>>
>> http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/19491/steps/test/logs/stdio
>>
>> Failing Tests (3):
>> LLVM-Unit :: XRay/./XRayTests.exe/FDRTraceWriterTest.WriteToStringBufferVersion1
>> LLVM-Unit :: XRay/./XRayTests.exe/FDRTraceWriterTest.WriteToStringBufferVersion2
>> LLVM-Unit :: XRay/./XRayTests.exe/FDRTraceWriterTest.WriteToStringBufferVersion3
>>
>> Sample failure output:
>>
>> FAIL: LLVM-Unit :: XRay/./XRayTests.exe/FDRTraceWriterTest.WriteToStringBufferVersion1 (3227 of 43541)
>> ******************** TEST 'LLVM-Unit :: XRay/./XRayTests.exe/FDRTraceWriterTest.WriteToStringBufferVersion1' FAILED ********************
>> Note: Google Test filter = FDRTraceWriterTest.WriteToStringBufferVersion1
>>
>> [==========] Running 1 test from 1 test case.
>>
>> [----------] Global test environment set-up.
>>
>> [----------] 1 test from FDRTraceWriterTest
>>
>> [ RUN ] FDRTraceWriterTest.WriteToStringBufferVersion1
>>
>> C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\unittests\XRay\FDRTraceWriterTest.cpp(157): error: Failed
>>
>> Malformed log: Read New Buffer record kind out of sequence; expected: FUNCTION_SEQUENCE at offset 89.
>>
>> Program aborted due to an unhandled Error:
>>
>> Malformed log: Read New Buffer record kind out of sequence; expected: FUNCTION_SEQUENCE at offset 89.LLVMSymbolizer: error reading file: PDB Error: Unable to load PDB. Make sure the file exists and is readable. Calling loadDataForExe
>>
>>
>>
>> LLVMSymbolizer: error reading file: PDB Error: Unable to load PDB. Make sure the file exists and is readable. Calling loadDataForExe
>>
>>
>>
>> #0 0x0003e887 (C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.obj\unittests\XRay\XRayTests.exe+0x2e887)
>>
>> #1 0x759e2722 (C:\WINDOWS\System32\ucrtbase.dll+0xa2722)
>>
>> #2 0x0003b918 (C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.obj\unittests\XRay\XRayTests.exe+0x2b918)
>>
>> #3 0x00064880 (C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.obj\unittests\XRay\XRayTests.exe+0x54880)
>>
>> #4 0x00076b54 (C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.obj\unittests\XRay\XRayTests.exe+0x66b54)
>>
>> #5 0x01b10518
>>
>> #6 0x65636172
>>
>> #7 0x74697257 (C:\WINDOWS\System32\msvcp_win.dll+0x37257)
>>
>> #8 0x65547265
>>
>>
>> ********************
>>
>> Douglas Yung
>>
>>> -----Original Message-----
>>> From: llvm-commits [mailto:llvm-commits-bounces at lists.llvm.org] On
>>> Behalf Of Dean Michael Berris via llvm-commits
>>> Sent: Thursday, August 30, 2018 0:22
>>> To: llvm-commits at lists.llvm.org
>>> Subject: [llvm] r341029 - [XRay] FDRTraceWriter and FDR Trace Loading
>>>
>>> Author: dberris
>>> Date: Thu Aug 30 00:22:21 2018
>>> New Revision: 341029
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=341029&view=rev
>>> Log:
>>> [XRay] FDRTraceWriter and FDR Trace Loading
>>>
>>> Summary:
>>> This is the first step in the larger refactoring and reduction of
>>> D50441.
>>>
>>> This step in the process does the following:
>>>
>>> - Introduces more granular types of `Record`s representing the many
>>> kinds of records written/read by the Flight Data Recorder (FDR) mode
>>> `Trace` loading function(s).
>>>
>>> - Introduces an abstract `RecordVisitor` type meant to handle the
>>> processing of the various `Record` derived types. This
>>> `RecordVisitor`
>>> has two implementations in this patch: `RecordInitializer` and
>>> `FDRTraceWriter`.
>>>
>>> - We also introduce a convenience interface for building a collection
>>> of
>>> `Record` instances called a `LogBuilder`. This allows us to generate
>>> sequences of `Record` instances manually (used in unit tests but
>>> useful otherwise).
>>>
>>> - The`FDRTraceWriter` class implements the `RecordVisitor` interface
>>> and
>>> handles the writing of metadata records to a `raw_ostream`. We
>>> demonstrate that in the unit test, we can generate in-memory FDR mode
>>> traces using the specific `Record` derived types, which we load
>>> through the `loadTrace(...)` function yielding valid `Trace` objects.
>>>
>>> This patch introduces the required types and concepts for us to start
>>> replacing the logic implemented in the `loadFDRLog` function to use the
>>> more granular types. In subsequent patches, we will introduce more
>>> visitor implementations which isolate the verification, printing,
>>> indexing, production/consumption, and finally the conversion of the FDR
>>> mode logs.
>>>
>>> The overarching goal of these changes is to make handling FDR mode logs
>>> better tested, more understandable, more extensible, and more
>>> systematic. This will also allow us to better represent the execution
>>> trace, as we improve the fidelity of the events we represent in an XRay
>>> `Trace` object, which we intend to do after FDR mode log processing is
>>> in better shape.
>>>
>>> Reviewers: eizan
>>>
>>> Reviewed By: eizan
>>>
>>> Subscribers: mgorny, hiraditya, llvm-commits
>>>
>>> Differential Revision: https://reviews.llvm.org/D51210
>>>
>>> Added:
>>> llvm/trunk/include/llvm/XRay/FDRLogBuilder.h
>>> llvm/trunk/include/llvm/XRay/FDRRecords.h
>>> llvm/trunk/include/llvm/XRay/FDRTraceWriter.h
>>> llvm/trunk/lib/XRay/FDRRecords.cpp
>>> llvm/trunk/lib/XRay/FDRTraceWriter.cpp
>>> llvm/trunk/lib/XRay/RecordInitializer.cpp
>>> llvm/trunk/unittests/XRay/FDRTraceWriterTest.cpp
>>> Modified:
>>> llvm/trunk/lib/XRay/CMakeLists.txt
>>> llvm/trunk/unittests/XRay/CMakeLists.txt
>>>
>>> Added: llvm/trunk/include/llvm/XRay/FDRLogBuilder.h
>>> URL: http://llvm.org/viewvc/llvm-
>>> project/llvm/trunk/include/llvm/XRay/FDRLogBuilder.h?rev=341029&view=au
>>> to
>>> =======================================================================
>>> =======
>>> --- llvm/trunk/include/llvm/XRay/FDRLogBuilder.h (added)
>>> +++ llvm/trunk/include/llvm/XRay/FDRLogBuilder.h Thu Aug 30 00:22:21
>>> 2018
>>> @@ -0,0 +1,41 @@
>>> +//===- FDRLogBuilder.h - XRay FDR Log Building Utility ---------------
>>> -----===//
>>> +//
>>> +// The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open
>>> Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +#ifndef LLVM_INCLUDE_LLVM_XRAY_FDRLOGBUILDER_H_
>>> +#define LLVM_INCLUDE_LLVM_XRAY_FDRLOGBUILDER_H_
>>> +
>>> +#include "llvm/XRay/FDRRecords.h"
>>> +
>>> +namespace llvm {
>>> +namespace xray {
>>> +
>>> +/// The LogBuilder class allows for creating ad-hoc collections of
>>> records
>>> +/// through the `add<...>(...)` function. An example use of this API
>>> is in
>>> +/// crafting arbitrary sequences of records:
>>> +///
>>> +/// auto Records = LogBuilder()
>>> +/// .add<BufferExtents>(256)
>>> +/// .add<NewBufferRecord>(1)
>>> +/// .consume();
>>> +///
>>> +class LogBuilder {
>>> + std::vector<std::unique_ptr<Record>> Records;
>>> +
>>> +public:
>>> + template <class R, class... T> LogBuilder &add(T &&... A) {
>>> + Records.emplace_back(new R(std::forward<T>(A)...));
>>> + return *this;
>>> + }
>>> +
>>> + std::vector<std::unique_ptr<Record>> consume() { return
>>> std::move(Records); }
>>> +};
>>> +
>>> +} // namespace xray
>>> +} // namespace llvm
>>> +
>>> +#endif // LLVM_INCLUDE_LLVM_XRAY_FDRLOGBUILDER_H_
>>>
>>> Added: llvm/trunk/include/llvm/XRay/FDRRecords.h
>>> URL: http://llvm.org/viewvc/llvm-
>>> project/llvm/trunk/include/llvm/XRay/FDRRecords.h?rev=341029&view=auto
>>> =======================================================================
>>> =======
>>> --- llvm/trunk/include/llvm/XRay/FDRRecords.h (added)
>>> +++ llvm/trunk/include/llvm/XRay/FDRRecords.h Thu Aug 30 00:22:21 2018
>>> @@ -0,0 +1,292 @@
>>> +//===- FDRRecords.h - XRay Flight Data Recorder Mode Records ---------
>>> -----===//
>>> +//
>>> +// The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open
>>> Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +//
>>> +// Define types and operations on these types that represent the
>>> different kinds
>>> +// of records we encounter in XRay flight data recorder mode traces.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +#ifndef LLVM_LIB_XRAY_FDRRECORDS_H_
>>> +#define LLVM_LIB_XRAY_FDRRECORDS_H_
>>> +
>>> +#include "llvm/Support/DataExtractor.h"
>>> +#include "llvm/Support/Error.h"
>>> +#include "llvm/XRay/XRayRecord.h"
>>> +#include <cstdint>
>>> +
>>> +namespace llvm {
>>> +namespace xray {
>>> +
>>> +class RecordVisitor;
>>> +class RecordInitializer;
>>> +
>>> +class Record {
>>> +protected:
>>> + enum class Type {
>>> + Unknown,
>>> + Function,
>>> + Metadata,
>>> + };
>>> +
>>> +public:
>>> + Record(const Record &) = delete;
>>> + Record(Record &&) = delete;
>>> + Record &operator=(const Record &) = delete;
>>> + Record &operator=(Record &&) = delete;
>>> + Record() = default;
>>> +
>>> + virtual Type type() const = 0;
>>> +
>>> + // Each Record should be able to apply an abstract visitor, and
>>> choose the
>>> + // appropriate function in the visitor to invoke, given its own
>>> type.
>>> + virtual Error apply(RecordVisitor &V) = 0;
>>> +
>>> + virtual ~Record() = default;
>>> +};
>>> +
>>> +class MetadataRecord : public Record {
>>> +protected:
>>> + static constexpr int kMetadataBodySize = 15;
>>> + friend class RecordInitializer;
>>> +
>>> +public:
>>> + enum class MetadataType : unsigned {
>>> + Unknown,
>>> + BufferExtents,
>>> + WallClockTime,
>>> + NewCPUId,
>>> + TSCWrap,
>>> + CustomEvent,
>>> + CallArg,
>>> + PIDEntry,
>>> + NewBuffer,
>>> + EndOfBuffer,
>>> + };
>>> +
>>> + Type type() const override { return Type::Metadata; }
>>> +
>>> + // All metadata records must know to provide the type of their open
>>> + // metadata record.
>>> + virtual MetadataType metadataType() const = 0;
>>> +
>>> + virtual ~MetadataRecord() = default;
>>> +};
>>> +
>>> +// What follows are specific Metadata record types which encapsulate
>>> the
>>> +// information associated with specific metadata record types in an
>>> FDR mode
>>> +// log.
>>> +class BufferExtents : public MetadataRecord {
>>> + uint64_t Size = 0;
>>> + friend class RecordInitializer;
>>> +
>>> +public:
>>> + BufferExtents() = default;
>>> + explicit BufferExtents(uint64_t S) : MetadataRecord(), Size(S) {}
>>> +
>>> + MetadataType metadataType() const override {
>>> + return MetadataType::BufferExtents;
>>> + }
>>> +
>>> + uint64_t size() const { return Size; }
>>> +
>>> + Error apply(RecordVisitor &V) override;
>>> +};
>>> +
>>> +class WallclockRecord : public MetadataRecord {
>>> + uint64_t Seconds = 0;
>>> + uint32_t Nanos = 0;
>>> + friend class RecordInitializer;
>>> +
>>> +public:
>>> + WallclockRecord() = default;
>>> + explicit WallclockRecord(uint64_t S, uint32_t N)
>>> + : MetadataRecord(), Seconds(S), Nanos(N) {}
>>> +
>>> + MetadataType metadataType() const override {
>>> + return MetadataType::WallClockTime;
>>> + }
>>> +
>>> + uint64_t seconds() const { return Seconds; }
>>> + uint32_t nanos() const { return Nanos; }
>>> +
>>> + Error apply(RecordVisitor &V) override;
>>> +};
>>> +
>>> +class NewCPUIDRecord : public MetadataRecord {
>>> + uint16_t CPUId = 0;
>>> + friend class RecordInitializer;
>>> +
>>> +public:
>>> + NewCPUIDRecord() = default;
>>> + explicit NewCPUIDRecord(uint16_t C) : MetadataRecord(), CPUId(C) {}
>>> +
>>> + MetadataType metadataType() const override { return
>>> MetadataType::NewCPUId; }
>>> +
>>> + uint16_t cpuid() const { return CPUId; }
>>> +
>>> + Error apply(RecordVisitor &V) override;
>>> +};
>>> +
>>> +class TSCWrapRecord : public MetadataRecord {
>>> + uint64_t BaseTSC = 0;
>>> + friend class RecordInitializer;
>>> +
>>> +public:
>>> + TSCWrapRecord() = default;
>>> + explicit TSCWrapRecord(uint64_t B) : MetadataRecord(), BaseTSC(B) {}
>>> +
>>> + MetadataType metadataType() const override { return
>>> MetadataType::TSCWrap; }
>>> +
>>> + uint64_t tsc() const { return BaseTSC; }
>>> +
>>> + Error apply(RecordVisitor &V) override;
>>> +};
>>> +
>>> +class CustomEventRecord : public MetadataRecord {
>>> + int32_t Size = 0;
>>> + uint64_t TSC = 0;
>>> + std::string Data{};
>>> + friend class RecordInitializer;
>>> +
>>> +public:
>>> + CustomEventRecord() = default;
>>> + explicit CustomEventRecord(uint64_t S, uint64_t T, std::string D)
>>> + : MetadataRecord(), Size(S), TSC(T), Data(std::move(D)) {}
>>> +
>>> + MetadataType metadataType() const override {
>>> + return MetadataType::CustomEvent;
>>> + }
>>> +
>>> + int32_t size() const { return Size; }
>>> + uint64_t tsc() const { return TSC; }
>>> + StringRef data() const { return Data; }
>>> +
>>> + Error apply(RecordVisitor &V) override;
>>> +};
>>> +
>>> +class CallArgRecord : public MetadataRecord {
>>> + uint64_t Arg;
>>> + friend class RecordInitializer;
>>> +
>>> +public:
>>> + CallArgRecord() = default;
>>> + explicit CallArgRecord(uint64_t A) : MetadataRecord(), Arg(A) {}
>>> +
>>> + MetadataType metadataType() const override { return
>>> MetadataType::CallArg; }
>>> +
>>> + uint64_t arg() const { return Arg; }
>>> +
>>> + Error apply(RecordVisitor &V) override;
>>> +};
>>> +
>>> +class PIDRecord : public MetadataRecord {
>>> + uint64_t PID = 0;
>>> + friend class RecordInitializer;
>>> +
>>> +public:
>>> + PIDRecord() = default;
>>> + explicit PIDRecord(uint64_t P) : MetadataRecord(), PID(P) {}
>>> +
>>> + MetadataType metadataType() const override { return
>>> MetadataType::PIDEntry; }
>>> +
>>> + uint64_t pid() const { return PID; }
>>> +
>>> + Error apply(RecordVisitor &V) override;
>>> +};
>>> +
>>> +class NewBufferRecord : public MetadataRecord {
>>> + int32_t TID = 0;
>>> + friend class RecordInitializer;
>>> +
>>> +public:
>>> + NewBufferRecord() = default;
>>> + explicit NewBufferRecord(int32_t T) : MetadataRecord(), TID(T) {}
>>> +
>>> + MetadataType metadataType() const override { return
>>> MetadataType::NewBuffer; }
>>> +
>>> + int32_t tid() const { return TID; }
>>> +
>>> + Error apply(RecordVisitor &V) override;
>>> +};
>>> +
>>> +class EndBufferRecord : public MetadataRecord {
>>> +public:
>>> + EndBufferRecord() = default;
>>> +
>>> + MetadataType metadataType() const override {
>>> + return MetadataType::EndOfBuffer;
>>> + }
>>> +
>>> + Error apply(RecordVisitor &V) override;
>>> +};
>>> +
>>> +class FunctionRecord : public Record {
>>> + RecordTypes Kind;
>>> + int32_t FuncId;
>>> + uint32_t Delta;
>>> + friend class RecordInitializer;
>>> +
>>> + static constexpr unsigned kFunctionRecordSize = 8;
>>> +
>>> +public:
>>> + FunctionRecord() = default;
>>> + explicit FunctionRecord(RecordTypes K, int32_t F, uint32_t D)
>>> + : Record(), Kind(K), FuncId(F), Delta(D) {}
>>> +
>>> + Type type() const override { return Type::Function; }
>>> +
>>> + // A function record is a concrete record type which has a number of
>>> common
>>> + // properties.
>>> + RecordTypes recordType() const { return Kind; }
>>> + int32_t functionId() const { return FuncId; }
>>> + uint64_t delta() const { return Delta; }
>>> +
>>> + Error apply(RecordVisitor &V) override;
>>> +};
>>> +
>>> +class RecordVisitor {
>>> +public:
>>> + virtual ~RecordVisitor() = default;
>>> +
>>> + // Support all specific kinds of records:
>>> + virtual Error visit(BufferExtents &) = 0;
>>> + virtual Error visit(WallclockRecord &) = 0;
>>> + virtual Error visit(NewCPUIDRecord &) = 0;
>>> + virtual Error visit(TSCWrapRecord &) = 0;
>>> + virtual Error visit(CustomEventRecord &) = 0;
>>> + virtual Error visit(CallArgRecord &) = 0;
>>> + virtual Error visit(PIDRecord &) = 0;
>>> + virtual Error visit(NewBufferRecord &) = 0;
>>> + virtual Error visit(EndBufferRecord &) = 0;
>>> + virtual Error visit(FunctionRecord &) = 0;
>>> +};
>>> +
>>> +class RecordInitializer : public RecordVisitor {
>>> + DataExtractor &E;
>>> + uint32_t &OffsetPtr;
>>> +
>>> +public:
>>> + explicit RecordInitializer(DataExtractor &DE, uint32_t &OP)
>>> + : RecordVisitor(), E(DE), OffsetPtr(OP) {}
>>> +
>>> + Error visit(BufferExtents &) override;
>>> + Error visit(WallclockRecord &) override;
>>> + Error visit(NewCPUIDRecord &) override;
>>> + Error visit(TSCWrapRecord &) override;
>>> + Error visit(CustomEventRecord &) override;
>>> + Error visit(CallArgRecord &) override;
>>> + Error visit(PIDRecord &) override;
>>> + Error visit(NewBufferRecord &) override;
>>> + Error visit(EndBufferRecord &) override;
>>> + Error visit(FunctionRecord &) override;
>>> +};
>>> +
>>> +} // namespace xray
>>> +} // namespace llvm
>>> +
>>> +#endif // LLVM_LIB_XRAY_FDRRECORDS_H_
>>>
>>> Added: llvm/trunk/include/llvm/XRay/FDRTraceWriter.h
>>> URL: http://llvm.org/viewvc/llvm-
>>> project/llvm/trunk/include/llvm/XRay/FDRTraceWriter.h?rev=341029&view=a
>>> uto
>>> =======================================================================
>>> =======
>>> --- llvm/trunk/include/llvm/XRay/FDRTraceWriter.h (added)
>>> +++ llvm/trunk/include/llvm/XRay/FDRTraceWriter.h Thu Aug 30 00:22:21
>>> 2018
>>> @@ -0,0 +1,53 @@
>>> +//===- FDRTraceWriter.h - XRay FDR Trace Writer -----------------*-
>>> C++ -*-===//
>>> +//
>>> +// The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open
>>> Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +//
>>> +// Test a utility that can write out XRay FDR Mode formatted trace
>>> files.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +#ifndef LLVM_INCLUDE_LLVM_XRAY_FDRTRACEWRITER_H_
>>> +#define LLVM_INCLUDE_LLVM_XRAY_FDRTRACEWRITER_H_
>>> +
>>> +#include "llvm/Support/raw_ostream.h"
>>> +#include "llvm/XRay/FDRRecords.h"
>>> +#include "llvm/XRay/XRayRecord.h"
>>> +
>>> +namespace llvm {
>>> +namespace xray {
>>> +
>>> +/// The FDRTraceWriter allows us to hand-craft an XRay Flight Data
>>> Recorder
>>> +/// (FDR) mode log file. This is used primarily for testing,
>>> generating
>>> +/// sequences of FDR records that can be read/processed. It can also
>>> be used to
>>> +/// generate various kinds of execution traces without using the XRay
>>> runtime.
>>> +/// Note that this writer does not do any validation, but uses the
>>> types of
>>> +/// records defined in the FDRRecords.h file.
>>> +class FDRTraceWriter : public RecordVisitor {
>>> +public:
>>> + // Construct an FDRTraceWriter associated with an output stream.
>>> + explicit FDRTraceWriter(raw_ostream &O, const XRayFileHeader &H);
>>> + ~FDRTraceWriter();
>>> +
>>> + Error visit(BufferExtents &) override;
>>> + Error visit(WallclockRecord &) override;
>>> + Error visit(NewCPUIDRecord &) override;
>>> + Error visit(TSCWrapRecord &) override;
>>> + Error visit(CustomEventRecord &) override;
>>> + Error visit(CallArgRecord &) override;
>>> + Error visit(PIDRecord &) override;
>>> + Error visit(NewBufferRecord &) override;
>>> + Error visit(EndBufferRecord &) override;
>>> + Error visit(FunctionRecord &) override;
>>> +
>>> +private:
>>> + raw_ostream &OS;
>>> +};
>>> +
>>> +} // namespace xray
>>> +} // namespace llvm
>>> +
>>> +#endif // LLVM_INCLUDE_LLVM_XRAY_FDRTRACEWRITER_H_
>>>
>>> Modified: llvm/trunk/lib/XRay/CMakeLists.txt
>>> URL: http://llvm.org/viewvc/llvm-
>>> project/llvm/trunk/lib/XRay/CMakeLists.txt?rev=341029&r1=341028&r2=3410
>>> 29&view=diff
>>> =======================================================================
>>> =======
>>> --- llvm/trunk/lib/XRay/CMakeLists.txt (original)
>>> +++ llvm/trunk/lib/XRay/CMakeLists.txt Thu Aug 30 00:22:21 2018
>>> @@ -1,7 +1,10 @@
>>> add_llvm_library(LLVMXRay
>>> + FDRRecords.cpp
>>> + FDRTraceWriter.cpp
>>> FileHeaderReader.cpp
>>> InstrumentationMap.cpp
>>> - Profile.cpp
>>> + Profile.cpp
>>> + RecordInitializer.cpp
>>> Trace.cpp
>>>
>>> ADDITIONAL_HEADER_DIRS
>>>
>>> Added: llvm/trunk/lib/XRay/FDRRecords.cpp
>>> URL: http://llvm.org/viewvc/llvm-
>>> project/llvm/trunk/lib/XRay/FDRRecords.cpp?rev=341029&view=auto
>>> =======================================================================
>>> =======
>>> --- llvm/trunk/lib/XRay/FDRRecords.cpp (added)
>>> +++ llvm/trunk/lib/XRay/FDRRecords.cpp Thu Aug 30 00:22:21 2018
>>> @@ -0,0 +1,31 @@
>>> +//===- FDRRecords.cpp - XRay Flight Data Recorder Mode Records ------
>>> -----===//
>>> +//
>>> +// The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open
>>> Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +//
>>> +// Define types and operations on these types that represent the
>>> different kinds
>>> +// of records we encounter in XRay flight data recorder mode traces.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +#include "llvm/XRay/FDRRecords.h"
>>> +
>>> +namespace llvm {
>>> +namespace xray {
>>> +
>>> +Error BufferExtents::apply(RecordVisitor &V) { return V.visit(*this);
>>> }
>>> +Error WallclockRecord::apply(RecordVisitor &V) { return
>>> V.visit(*this); }
>>> +Error NewCPUIDRecord::apply(RecordVisitor &V) { return V.visit(*this);
>>> }
>>> +Error TSCWrapRecord::apply(RecordVisitor &V) { return V.visit(*this);
>>> }
>>> +Error CustomEventRecord::apply(RecordVisitor &V) { return
>>> V.visit(*this); }
>>> +Error CallArgRecord::apply(RecordVisitor &V) { return V.visit(*this);
>>> }
>>> +Error PIDRecord::apply(RecordVisitor &V) { return V.visit(*this); }
>>> +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);
>>> }
>>> +
>>> +} // namespace xray
>>> +} // namespace llvm
>>>
>>> Added: llvm/trunk/lib/XRay/FDRTraceWriter.cpp
>>> URL: http://llvm.org/viewvc/llvm-
>>> project/llvm/trunk/lib/XRay/FDRTraceWriter.cpp?rev=341029&view=auto
>>> =======================================================================
>>> =======
>>> --- llvm/trunk/lib/XRay/FDRTraceWriter.cpp (added)
>>> +++ llvm/trunk/lib/XRay/FDRTraceWriter.cpp Thu Aug 30 00:22:21 2018
>>> @@ -0,0 +1,145 @@
>>> +//===- FDRTraceWriter.cpp - XRay FDR Trace Writer ---------------*-
>>> C++ -*-===//
>>> +//
>>> +// The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open
>>> Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +//
>>> +// Test a utility that can write out XRay FDR Mode formatted trace
>>> files.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +#include "llvm/XRay/FDRTraceWriter.h"
>>> +#include <tuple>
>>> +
>>> +namespace llvm {
>>> +namespace xray {
>>> +
>>> +namespace {
>>> +
>>> +struct alignas(32) FileHeader {
>>> + uint16_t Version;
>>> + uint16_t Type;
>>> + bool ConstantTSC : 1;
>>> + bool NonstopTSC : 1;
>>> + alignas(8) uint64_t CycleFrequency;
>>> + char FreeForm[16];
>>> +};
>>> +
>>> +struct MetadataBlob {
>>> + uint8_t Type : 1;
>>> + uint8_t RecordKind : 7;
>>> + char Data[15];
>>> +} __attribute__((packed));
>>> +
>>> +struct FunctionDeltaBlob {
>>> + uint8_t Type : 1;
>>> + uint8_t RecordKind : 3;
>>> + int FuncId : 28;
>>> + uint32_t TSCDelta;
>>> +} __attribute__((packed));
>>> +
>>> +template <size_t Index> struct IndexedMemcpy {
>>> + template <
>>> + class Tuple,
>>> + typename std::enable_if<
>>> + (Index <
>>> + std::tuple_size<typename
>>> std::remove_reference<Tuple>::type>::value),
>>> + int>::type = 0>
>>> + static void Copy(char *Dest, Tuple &&T) {
>>> + auto Next = static_cast<char *>(std::memcpy(
>>> + Dest, reinterpret_cast<const char
>>> *>(&std::get<Index>(T)),
>>> + sizeof(std::get<Index>(T)))) +
>>> + sizeof(std::get<Index>(T));
>>> + IndexedMemcpy<Index + 1>::Copy(Next, T);
>>> + }
>>> +
>>> + template <
>>> + class Tuple,
>>> + typename std::enable_if<
>>> + (Index >=
>>> + std::tuple_size<typename
>>> std::remove_reference<Tuple>::type>::value),
>>> + int>::type = 0>
>>> + static void Copy(char *, Tuple &&) {}
>>> +};
>>> +
>>> +template <uint8_t Kind, class... Data>
>>> +Error writeMetadata(raw_ostream &OS, Data... Ds) {
>>> + MetadataBlob B;
>>> + B.Type = 1;
>>> + B.RecordKind = Kind;
>>> + IndexedMemcpy<0>::Copy(B.Data, std::make_tuple(Ds...));
>>> + OS.write(reinterpret_cast<const char *>(&B), sizeof(MetadataBlob));
>>> + return Error::success();
>>> +}
>>> +
>>> +} // namespace
>>> +
>>> +FDRTraceWriter::FDRTraceWriter(raw_ostream &O, const XRayFileHeader
>>> &H)
>>> + : OS(O) {
>>> + // We need to re-construct a header, by writing the fields we care
>>> about for
>>> + // traces, in the format that the runtime would have written.
>>> + FileHeader Raw;
>>> + Raw.Version = H.Version;
>>> + Raw.Type = H.Type;
>>> + Raw.ConstantTSC = H.ConstantTSC;
>>> + Raw.NonstopTSC = H.NonstopTSC;
>>> + Raw.CycleFrequency = H.CycleFrequency;
>>> + memcpy(&Raw.FreeForm, H.FreeFormData, 16);
>>> + OS.write(reinterpret_cast<const char *>(&Raw),
>>> sizeof(XRayFileHeader));
>>> +}
>>> +
>>> +FDRTraceWriter::~FDRTraceWriter() {}
>>> +
>>> +Error FDRTraceWriter::visit(BufferExtents &R) {
>>> + return writeMetadata<7u>(OS, R.size());
>>> +}
>>> +
>>> +Error FDRTraceWriter::visit(WallclockRecord &R) {
>>> + return writeMetadata<4u>(OS, R.seconds(), R.nanos());
>>> +}
>>> +
>>> +Error FDRTraceWriter::visit(NewCPUIDRecord &R) {
>>> + return writeMetadata<2u>(OS, R.cpuid());
>>> +}
>>> +
>>> +Error FDRTraceWriter::visit(TSCWrapRecord &R) {
>>> + return writeMetadata<3u>(OS, R.tsc());
>>> +}
>>> +
>>> +Error FDRTraceWriter::visit(CustomEventRecord &R) {
>>> + if (auto E = writeMetadata<5u>(OS, R.size(), R.tsc()))
>>> + return E;
>>> + OS.write(R.data().data(), R.data().size());
>>> + return Error::success();
>>> +}
>>> +
>>> +Error FDRTraceWriter::visit(CallArgRecord &R) {
>>> + return writeMetadata<6u>(OS, R.arg());
>>> +}
>>> +
>>> +Error FDRTraceWriter::visit(PIDRecord &R) {
>>> + return writeMetadata<9u>(OS, R.pid());
>>> +}
>>> +
>>> +Error FDRTraceWriter::visit(NewBufferRecord &R) {
>>> + return writeMetadata<0u>(OS, R.tid());
>>> +}
>>> +
>>> +Error FDRTraceWriter::visit(EndBufferRecord &R) {
>>> + return writeMetadata<1u>(OS, 0);
>>> +}
>>> +
>>> +Error FDRTraceWriter::visit(FunctionRecord &R) {
>>> + FunctionDeltaBlob B;
>>> + B.Type = 0;
>>> + B.RecordKind = static_cast<uint8_t>(R.recordType());
>>> + B.FuncId = R.functionId();
>>> + B.TSCDelta = R.delta();
>>> + OS.write(reinterpret_cast<const char *>(&B),
>>> sizeof(FunctionDeltaBlob));
>>> + return Error::success();
>>> +}
>>> +
>>> +} // namespace xray
>>> +} // namespace llvm
>>>
>>> Added: llvm/trunk/lib/XRay/RecordInitializer.cpp
>>> URL: http://llvm.org/viewvc/llvm-
>>> project/llvm/trunk/lib/XRay/RecordInitializer.cpp?rev=341029&view=auto
>>> =======================================================================
>>> =======
>>> --- llvm/trunk/lib/XRay/RecordInitializer.cpp (added)
>>> +++ llvm/trunk/lib/XRay/RecordInitializer.cpp Thu Aug 30 00:22:21 2018
>>> @@ -0,0 +1,247 @@
>>> +//===- FDRRecordProducer.cpp - XRay FDR Mode Record Producer ---------
>>> -----===//
>>> +//
>>> +// The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open
>>> Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +#include "llvm/XRay/FDRRecords.h"
>>> +
>>> +namespace llvm {
>>> +namespace xray {
>>> +
>>> +Error RecordInitializer::visit(BufferExtents &R) {
>>> + if (!E.isValidOffsetForDataOfSize(OffsetPtr, sizeof(uint64_t)))
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_address),
>>> + "Invalid offset for a buffer extent
>>> (%d).",
>>> + OffsetPtr);
>>> +
>>> + auto PreReadOffset = OffsetPtr;
>>> + R.Size = E.getU64(&OffsetPtr);
>>> + if (PreReadOffset == OffsetPtr)
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_message),
>>> + "Cannot read buffer extent at offset
>>> %d.",
>>> + OffsetPtr);
>>> +
>>> + OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr -
>>> PreReadOffset);
>>> + return Error::success();
>>> +}
>>> +
>>> +Error RecordInitializer::visit(WallclockRecord &R) {
>>> + if (!E.isValidOffsetForDataOfSize(OffsetPtr,
>>> +
>>> MetadataRecord::kMetadataBodySize))
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_address),
>>> + "Invalid offset for a wallclock record
>>> (%d).",
>>> + OffsetPtr);
>>> + auto BeginOffset = OffsetPtr;
>>> + auto PreReadOffset = OffsetPtr;
>>> + R.Seconds = E.getU64(&OffsetPtr);
>>> + if (OffsetPtr == PreReadOffset)
>>> + return createStringError(
>>> + std::make_error_code(std::errc::bad_message),
>>> + "Cannot read wall clock 'seconds' field at offset %d.",
>>> OffsetPtr);
>>> +
>>> + PreReadOffset = OffsetPtr;
>>> + R.Nanos = E.getU32(&OffsetPtr);
>>> + if (OffsetPtr == PreReadOffset)
>>> + return createStringError(
>>> + std::make_error_code(std::errc::bad_message),
>>> + "Cannot read wall clock 'nanos' field at offset %d.",
>>> OffsetPtr);
>>> +
>>> + // Align to metadata record size boundary.
>>> + assert(OffsetPtr - BeginOffset <=
>>> MetadataRecord::kMetadataBodySize);
>>> + OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr -
>>> BeginOffset);
>>> + return Error::success();
>>> +}
>>> +
>>> +Error RecordInitializer::visit(NewCPUIDRecord &R) {
>>> + if (!E.isValidOffsetForDataOfSize(OffsetPtr,
>>> +
>>> MetadataRecord::kMetadataBodySize))
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_address),
>>> + "Invalid offset for a new cpu id record
>>> (%d).",
>>> + OffsetPtr);
>>> + auto PreReadOffset = OffsetPtr;
>>> + R.CPUId = E.getU16(&OffsetPtr);
>>> + if (OffsetPtr == PreReadOffset)
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_message),
>>> + "Cannot read CPU id at offset %d.",
>>> OffsetPtr);
>>> +
>>> + OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr -
>>> PreReadOffset);
>>> + return Error::success();
>>> +}
>>> +
>>> +Error RecordInitializer::visit(TSCWrapRecord &R) {
>>> + if (!E.isValidOffsetForDataOfSize(OffsetPtr,
>>> +
>>> MetadataRecord::kMetadataBodySize))
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_address),
>>> + "Invalid offset for a new TSC wrap record
>>> (%d).",
>>> + OffsetPtr);
>>> +
>>> + auto PreReadOffset = OffsetPtr;
>>> + R.BaseTSC = E.getU64(&OffsetPtr);
>>> + if (PreReadOffset == OffsetPtr)
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_message),
>>> + "Cannot read TSC wrap record at offset
>>> %d.",
>>> + OffsetPtr);
>>> +
>>> + OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr -
>>> PreReadOffset);
>>> + return Error::success();
>>> +}
>>> +
>>> +Error RecordInitializer::visit(CustomEventRecord &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::bad_message),
>>> + "Cannot read a custom event record size field offset %d.",
>>> OffsetPtr);
>>> +
>>> + PreReadOffset = OffsetPtr;
>>> + R.TSC = E.getU64(&OffsetPtr);
>>> + if (PreReadOffset == OffsetPtr)
>>> + return createStringError(
>>> + std::make_error_code(std::errc::bad_message),
>>> + "Cannot read a custom event TSC field at offset %d.",
>>> OffsetPtr);
>>> +
>>> + 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<uint8_t> Buffer;
>>> + Buffer.resize(R.Size);
>>> + if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
>>> + return createStringError(
>>> + std::make_error_code(std::errc::bad_message),
>>> + "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))
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_address),
>>> + "Invalid offset for a call argument
>>> record (%d).",
>>> + OffsetPtr);
>>> +
>>> + auto PreReadOffset = OffsetPtr;
>>> + R.Arg = E.getU64(&OffsetPtr);
>>> + if (PreReadOffset == OffsetPtr)
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_message),
>>> + "Cannot read a call arg record at offset
>>> %d.",
>>> + OffsetPtr);
>>> +
>>> + OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr -
>>> PreReadOffset);
>>> + return Error::success();
>>> +}
>>> +
>>> +Error RecordInitializer::visit(PIDRecord &R) {
>>> + if (!E.isValidOffsetForDataOfSize(OffsetPtr,
>>> +
>>> MetadataRecord::kMetadataBodySize))
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_address),
>>> + "Invalid offset for a process ID record
>>> (%d).",
>>> + OffsetPtr);
>>> +
>>> + auto PreReadOffset = OffsetPtr;
>>> + R.PID = E.getU64(&OffsetPtr);
>>> + if (PreReadOffset == OffsetPtr)
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_message),
>>> + "Cannot read a process ID record at
>>> offset %d.",
>>> + OffsetPtr);
>>> +
>>> + OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr -
>>> PreReadOffset);
>>> + return Error::success();
>>> +}
>>> +
>>> +Error RecordInitializer::visit(NewBufferRecord &R) {
>>> + if (!E.isValidOffsetForDataOfSize(OffsetPtr,
>>> +
>>> MetadataRecord::kMetadataBodySize))
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_address),
>>> + "Invalid offset for a new buffer record
>>> (%d).",
>>> + OffsetPtr);
>>> +
>>> + auto PreReadOffset = OffsetPtr;
>>> + R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));
>>> + if (PreReadOffset == OffsetPtr)
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_message),
>>> + "Cannot read a new buffer record at
>>> offset %d.",
>>> + OffsetPtr);
>>> +
>>> + OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr -
>>> PreReadOffset);
>>> + return Error::success();
>>> +}
>>> +
>>> +Error RecordInitializer::visit(EndBufferRecord &R) {
>>> + if (!E.isValidOffsetForDataOfSize(OffsetPtr,
>>> +
>>> MetadataRecord::kMetadataBodySize))
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_address),
>>> + "Invalid offset for an end-of-buffer
>>> record (%d).",
>>> + OffsetPtr);
>>> +
>>> + OffsetPtr += MetadataRecord::kMetadataBodySize;
>>> + return Error::success();
>>> +}
>>> +
>>> +Error RecordInitializer::visit(FunctionRecord &R) {
>>> + // For function records, we need to retreat one byte back to read a
>>> full
>>> + // unsigned 32-bit value. The first four bytes will have the
>>> following
>>> + // layout:
>>> + //
>>> + // bit 0 : function record indicator (must be 0)
>>> + // bits 1..3 : function record type
>>> + // bits 4..32 : function id
>>> + //
>>> + if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize(
>>> + --OffsetPtr,
>>> FunctionRecord::kFunctionRecordSize))
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_address),
>>> + "Invalid offset for a function record
>>> (%d).",
>>> + OffsetPtr);
>>> +
>>> + auto BeginOffset = OffsetPtr;
>>> + auto PreReadOffset = BeginOffset;
>>> + uint32_t Buffer = E.getU32(&OffsetPtr);
>>> + if (PreReadOffset == OffsetPtr)
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_address),
>>> + "Cannot read function id field from
>>> offset %d.",
>>> + OffsetPtr);
>>> + unsigned FunctionType = (Buffer >> 1) & 0x07;
>>> + switch (FunctionType) {
>>> + case static_cast<unsigned>(RecordTypes::ENTER):
>>> + case static_cast<unsigned>(RecordTypes::ENTER_ARG):
>>> + case static_cast<unsigned>(RecordTypes::EXIT):
>>> + case static_cast<unsigned>(RecordTypes::TAIL_EXIT):
>>> + R.Kind = static_cast<RecordTypes>(FunctionType);
>>> + break;
>>> + default:
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_message),
>>> + "Unknown function record type '%d' at
>>> offset %d.",
>>> + FunctionType, BeginOffset);
>>> + }
>>> +
>>> + R.FuncId = Buffer >> 4;
>>> + PreReadOffset = OffsetPtr;
>>> + R.Delta = E.getU32(&OffsetPtr);
>>> + if (OffsetPtr == PreReadOffset)
>>> + return
>>> createStringError(std::make_error_code(std::errc::bad_message),
>>> + "Failed reading TSC delta from offset
>>> %d.",
>>> + OffsetPtr);
>>> + assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr -
>>> BeginOffset));
>>> + return Error::success();
>>> +}
>>> +
>>> +} // namespace xray
>>> +} // namespace llvm
>>>
>>> Modified: llvm/trunk/unittests/XRay/CMakeLists.txt
>>> URL: http://llvm.org/viewvc/llvm-
>>> project/llvm/trunk/unittests/XRay/CMakeLists.txt?rev=341029&r1=341028&r
>>> 2=341029&view=diff
>>> =======================================================================
>>> =======
>>> --- llvm/trunk/unittests/XRay/CMakeLists.txt (original)
>>> +++ llvm/trunk/unittests/XRay/CMakeLists.txt Thu Aug 30 00:22:21 2018
>>> @@ -1,9 +1,10 @@
>>> set(LLVM_LINK_COMPONENTS
>>> Support
>>> - XRay
>>> + XRay
>>> )
>>>
>>> add_llvm_unittest(XRayTests
>>> + FDRTraceWriterTest.cpp
>>> GraphTest.cpp
>>> ProfileTest.cpp
>>> )
>>>
>>> Added: llvm/trunk/unittests/XRay/FDRTraceWriterTest.cpp
>>> URL: http://llvm.org/viewvc/llvm-
>>> project/llvm/trunk/unittests/XRay/FDRTraceWriterTest.cpp?rev=341029&vie
>>> w=auto
>>> =======================================================================
>>> =======
>>> --- llvm/trunk/unittests/XRay/FDRTraceWriterTest.cpp (added)
>>> +++ llvm/trunk/unittests/XRay/FDRTraceWriterTest.cpp Thu Aug 30
>>> 00:22:21 2018
>>> @@ -0,0 +1,175 @@
>>> +//===- llvm/unittest/XRay/FDRTraceWriterTest.cpp ----------------*-
>>> C++ -*-===//
>>> +//
>>> +// The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open
>>> Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +//
>>> +// Test a utility that can write out XRay FDR Mode formatted trace
>>> files.
>>> +//
>>> +//===-----------------------------------------------------------------
>>> -----===//
>>> +#include "llvm/XRay/FDRTraceWriter.h"
>>> +#include "llvm/Support/raw_ostream.h"
>>> +#include "llvm/XRay/FDRLogBuilder.h"
>>> +#include "llvm/XRay/FDRRecords.h"
>>> +#include "llvm/XRay/Trace.h"
>>> +#include "gmock/gmock.h"
>>> +#include "gtest/gtest.h"
>>> +#include <string>
>>> +
>>> +namespace llvm {
>>> +namespace xray {
>>> +namespace {
>>> +
>>> +using testing::ElementsAre;
>>> +using testing::Eq;
>>> +using testing::Field;
>>> +using testing::IsEmpty;
>>> +using testing::Not;
>>> +
>>> +// We want to be able to create an instance of an FDRTraceWriter and
>>> associate
>>> +// it with a stream, which could be loaded and turned into a Trace
>>> instance.
>>> +// This test writes out version 3 trace logs.
>>> +TEST(FDRTraceWriterTest, WriteToStringBufferVersion3) {
>>> + std::string Data;
>>> + raw_string_ostream OS(Data);
>>> + XRayFileHeader H;
>>> + H.Version = 3;
>>> + H.Type = 1;
>>> + H.ConstantTSC = true;
>>> + H.NonstopTSC = true;
>>> + H.CycleFrequency = 3e9;
>>> + FDRTraceWriter Writer(OS, H);
>>> + auto L = LogBuilder()
>>> + .add<BufferExtents>(80)
>>> + .add<NewBufferRecord>(1)
>>> + .add<WallclockRecord>(1, 1)
>>> + .add<PIDRecord>(1)
>>> + .add<NewCPUIDRecord>(1)
>>> + .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)
>>> + .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)
>>> + .consume();
>>> + for (auto &P : L)
>>> + ASSERT_FALSE(errorToBool(P->apply(Writer)));
>>> + OS.flush();
>>> +
>>> + // Then from here we load the Trace file.
>>> + DataExtractor DE(Data, true, 8);
>>> + auto TraceOrErr = loadTrace(DE, true);
>>> + if (!TraceOrErr)
>>> + FAIL() << TraceOrErr.takeError();
>>> + auto &Trace = TraceOrErr.get();
>>> +
>>> + ASSERT_THAT(Trace, Not(IsEmpty()));
>>> + ASSERT_THAT(
>>> + Trace,
>>> + ElementsAre(AllOf(Field(&XRayRecord::FuncId, Eq(1)),
>>> + Field(&XRayRecord::TId, Eq(1u)),
>>> + Field(&XRayRecord::CPU, Eq(1u)),
>>> + Field(&XRayRecord::Type,
>>> Eq(RecordTypes::ENTER))),
>>> + AllOf(Field(&XRayRecord::FuncId, Eq(1)),
>>> + Field(&XRayRecord::TId, Eq(1u)),
>>> + Field(&XRayRecord::CPU, Eq(1u)),
>>> + Field(&XRayRecord::Type,
>>> Eq(RecordTypes::EXIT)))));
>>> +}
>>> +
>>> +// This version is almost exactly the same as above, except writing
>>> version 2
>>> +// logs, without the PID records.
>>> +TEST(FDRTraceWriterTest, WriteToStringBufferVersion2) {
>>> + std::string Data;
>>> + raw_string_ostream OS(Data);
>>> + XRayFileHeader H;
>>> + H.Version = 2;
>>> + H.Type = 1;
>>> + H.ConstantTSC = true;
>>> + H.NonstopTSC = true;
>>> + H.CycleFrequency = 3e9;
>>> + FDRTraceWriter Writer(OS, H);
>>> + auto L = LogBuilder()
>>> + .add<BufferExtents>(64)
>>> + .add<NewBufferRecord>(1)
>>> + .add<WallclockRecord>(1, 1)
>>> + .add<NewCPUIDRecord>(1)
>>> + .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)
>>> + .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)
>>> + .consume();
>>> + for (auto &P : L)
>>> + ASSERT_FALSE(errorToBool(P->apply(Writer)));
>>> + OS.flush();
>>> +
>>> + // Then from here we load the Trace file.
>>> + DataExtractor DE(Data, true, 8);
>>> + auto TraceOrErr = loadTrace(DE, true);
>>> + if (!TraceOrErr)
>>> + FAIL() << TraceOrErr.takeError();
>>> + auto &Trace = TraceOrErr.get();
>>> +
>>> + ASSERT_THAT(Trace, Not(IsEmpty()));
>>> + ASSERT_THAT(
>>> + Trace,
>>> + ElementsAre(AllOf(Field(&XRayRecord::FuncId, Eq(1)),
>>> + Field(&XRayRecord::TId, Eq(1u)),
>>> + Field(&XRayRecord::CPU, Eq(1u)),
>>> + Field(&XRayRecord::Type,
>>> Eq(RecordTypes::ENTER))),
>>> + AllOf(Field(&XRayRecord::FuncId, Eq(1)),
>>> + Field(&XRayRecord::TId, Eq(1u)),
>>> + Field(&XRayRecord::CPU, Eq(1u)),
>>> + Field(&XRayRecord::Type,
>>> Eq(RecordTypes::EXIT)))));
>>> +}
>>> +
>>> +// This covers version 1 of the log, without a BufferExtents record
>>> but has an
>>> +// explicit EndOfBuffer record.
>>> +TEST(FDRTraceWriterTest, WriteToStringBufferVersion1) {
>>> + std::string Data;
>>> + raw_string_ostream OS(Data);
>>> + XRayFileHeader H;
>>> + H.Version = 1;
>>> + H.Type = 1;
>>> + H.ConstantTSC = true;
>>> + H.NonstopTSC = true;
>>> + H.CycleFrequency = 3e9;
>>> + // Write the size of buffers out, arbitrarily it's 4k.
>>> + constexpr uint64_t BufferSize = 4096;
>>> + std::memcpy(H.FreeFormData, reinterpret_cast<const char
>>> *>(&BufferSize),
>>> + sizeof(BufferSize));
>>> + FDRTraceWriter Writer(OS, H);
>>> + auto L = LogBuilder()
>>> + .add<NewBufferRecord>(1)
>>> + .add<WallclockRecord>(1, 1)
>>> + .add<NewCPUIDRecord>(1)
>>> + .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)
>>> + .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)
>>> + .add<EndBufferRecord>()
>>> + .consume();
>>> + for (auto &P : L)
>>> + ASSERT_FALSE(errorToBool(P->apply(Writer)));
>>> +
>>> + // We need to pad the buffer with 4016 (4096 - 80) bytes of zeros.
>>> + OS.write_zeros(4016);
>>> + OS.flush();
>>> +
>>> + // Then from here we load the Trace file.
>>> + DataExtractor DE(Data, true, 8);
>>> + auto TraceOrErr = loadTrace(DE, true);
>>> + if (!TraceOrErr)
>>> + FAIL() << TraceOrErr.takeError();
>>> + auto &Trace = TraceOrErr.get();
>>> +
>>> + ASSERT_THAT(Trace, Not(IsEmpty()));
>>> + ASSERT_THAT(
>>> + Trace,
>>> + ElementsAre(AllOf(Field(&XRayRecord::FuncId, Eq(1)),
>>> + Field(&XRayRecord::TId, Eq(1u)),
>>> + Field(&XRayRecord::CPU, Eq(1u)),
>>> + Field(&XRayRecord::Type,
>>> Eq(RecordTypes::ENTER))),
>>> + AllOf(Field(&XRayRecord::FuncId, Eq(1)),
>>> + Field(&XRayRecord::TId, Eq(1u)),
>>> + Field(&XRayRecord::CPU, Eq(1u)),
>>> + Field(&XRayRecord::Type,
>>> Eq(RecordTypes::EXIT)))));
>>> +}
>>> +
>>> +} // namespace
>>> +} // namespace xray
>>> +} // namespace llvm
>>>
>>>
>>> _______________________________________________
>>> llvm-commits mailing list
>>> llvm-commits at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
> -- Dean
>
-- Dean
More information about the llvm-commits
mailing list