[llvm] r341029 - [XRay] FDRTraceWriter and FDR Trace Loading

Dean Michael Berris via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 31 03:42:01 PDT 2018


This should now be fixed in r341194.

Thanks Doug!

> On 31 Aug 2018, at 20:01, Dean Michael Berris <dean.berris at gmail.com> wrote:
> 
> 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
> 

-- Dean



More information about the llvm-commits mailing list