<div dir="ltr">This is failing my build because the tuple constructor isn't constexpr in C++11. It's only C++14 and newer.<div><br></div><div>





<p class="gmail-p1" style="margin:0px;font-variant-numeric:normal;font-variant-east-asian:normal;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(43,102,201)"><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures"><b>lib/XRay/BlockVerifier.cpp:58:7: </b></span><span class="gmail-s2" style="font-variant-ligatures:no-common-ligatures;color:rgb(117,0,0)"><b>error: </b></span><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures"><b>constexpr variable 'TransitionTable' must be initialized by a constant expression</b></span></p>
<p class="gmail-p1" style="margin:0px;font-variant-numeric:normal;font-variant-east-asian:normal;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(43,102,201)"><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures"><span class="gmail-Apple-converted-space">      </span>TransitionTable{{{State::Unknown,</span></p>
<p class="gmail-p2" style="margin:0px;font-variant-numeric:normal;font-variant-east-asian:normal;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(101,229,81);background-color:rgb(43,102,201)"><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures"><b><span class="gmail-Apple-converted-space">      </span>^<span class="gmail-Apple-converted-space">              </span>~~~~~~~~~~~~~~~~~~</b></span></p>
<p class="gmail-p1" style="margin:0px;font-variant-numeric:normal;font-variant-east-asian:normal;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(43,102,201)"><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures"><b>lib/XRay/BlockVerifier.cpp:58:24: </b></span><span class="gmail-s3" style="font-variant-ligatures:no-common-ligatures;color:rgb(0,0,0)"><b>note: </b></span><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures">non-constexpr constructor 'tuple<true, false>' cannot be used in a constant expression</span></p>
<p class="gmail-p1" style="margin:0px;font-variant-numeric:normal;font-variant-east-asian:normal;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(43,102,201)"><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures"><span class="gmail-Apple-converted-space">      </span>TransitionTable{{{State::Unknown,</span></p><p class="gmail-p1" style="margin:0px;font-variant-numeric:normal;font-variant-east-asian:normal;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(43,102,201)"><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures"><br></span></p><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">~Craig</div></div><br></div></div><br><div class="gmail_quote"><div dir="ltr">On Thu, Sep 6, 2018 at 7:26 PM Dean Michael Berris via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: dberris<br>
Date: Thu Sep  6 19:25:06 2018<br>
New Revision: 341628<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=341628&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=341628&view=rev</a><br>
Log:<br>
[XRay] Add a BlockVerifier visitor for FDR Records<br>
<br>
Summary:<br>
This patch implements a `BlockVerifier` type which enforces the<br>
invariants of the log structure of FDR mode logs on a per-block basis.<br>
This ensures that the data we encounter from an FDR mode log<br>
semantically correct (i.e. that records follow the documented "grammar"<br>
for FDR mode log records).<br>
<br>
This is another part of the refactoring of D50441.<br>
<br>
Reviewers: mboerger, eizan<br>
<br>
Subscribers: mgorny, hiraditya, llvm-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D51723" rel="noreferrer" target="_blank">https://reviews.llvm.org/D51723</a><br>
<br>
Added:<br>
    llvm/trunk/include/llvm/XRay/BlockVerifier.h<br>
    llvm/trunk/lib/XRay/BlockVerifier.cpp<br>
    llvm/trunk/unittests/XRay/FDRBlockVerifierTest.cpp<br>
Modified:<br>
    llvm/trunk/lib/XRay/CMakeLists.txt<br>
    llvm/trunk/unittests/XRay/CMakeLists.txt<br>
<br>
Added: llvm/trunk/include/llvm/XRay/BlockVerifier.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/XRay/BlockVerifier.h?rev=341628&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/XRay/BlockVerifier.h?rev=341628&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/XRay/BlockVerifier.h (added)<br>
+++ llvm/trunk/include/llvm/XRay/BlockVerifier.h Thu Sep  6 19:25:06 2018<br>
@@ -0,0 +1,69 @@<br>
+//===- BlockVerifier.h - FDR Block Verifier -------------------------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// An implementation of the RecordVisitor which verifies a sequence of records<br>
+// associated with a block, following the FDR mode log format's specifications.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+#ifndef LLVM_INCLUDE_LLVM_XRAY_BLOCKVERIFIER_H_<br>
+#define LLVM_INCLUDE_LLVM_XRAY_BLOCKVERIFIER_H_<br>
+<br>
+#include "llvm/XRay/FDRRecords.h"<br>
+#include <array><br>
+#include <bitset><br>
+<br>
+namespace llvm {<br>
+namespace xray {<br>
+<br>
+class BlockVerifier : public RecordVisitor {<br>
+public:<br>
+  // We force State elements to be size_t, to be used as indices for containers.<br>
+  enum class State : std::size_t {<br>
+    Unknown,<br>
+    BufferExtents,<br>
+    NewBuffer,<br>
+    WallClockTime,<br>
+    PIDEntry,<br>
+    NewCPUId,<br>
+    TSCWrap,<br>
+    CustomEvent,<br>
+    Function,<br>
+    CallArg,<br>
+    EndOfBuffer,<br>
+    StateMax,<br>
+  };<br>
+<br>
+private:<br>
+  // We keep track of the current record seen by the verifier.<br>
+  State CurrentRecord = State::Unknown;<br>
+<br>
+  // Transitions the current record to the new record, records an error on<br>
+  // invalid transitions.<br>
+  Error transition(State To);<br>
+<br>
+public:<br>
+  Error visit(BufferExtents &) override;<br>
+  Error visit(WallclockRecord &) override;<br>
+  Error visit(NewCPUIDRecord &) override;<br>
+  Error visit(TSCWrapRecord &) override;<br>
+  Error visit(CustomEventRecord &) override;<br>
+  Error visit(CallArgRecord &) override;<br>
+  Error visit(PIDRecord &) override;<br>
+  Error visit(NewBufferRecord &) override;<br>
+  Error visit(EndBufferRecord &) override;<br>
+  Error visit(FunctionRecord &) override;<br>
+<br>
+  Error verify();<br>
+  void reset();<br>
+};<br>
+<br>
+} // namespace xray<br>
+} // namespace llvm<br>
+<br>
+#endif // LLVM_INCLUDE_LLVM_XRAY_BLOCKVERIFIER_H_<br>
<br>
Added: llvm/trunk/lib/XRay/BlockVerifier.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/XRay/BlockVerifier.cpp?rev=341628&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/XRay/BlockVerifier.cpp?rev=341628&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/lib/XRay/BlockVerifier.cpp (added)<br>
+++ llvm/trunk/lib/XRay/BlockVerifier.cpp Thu Sep  6 19:25:06 2018<br>
@@ -0,0 +1,182 @@<br>
+//===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+#include "llvm/XRay/BlockVerifier.h"<br>
+#include "llvm/Support/Error.h"<br>
+<br>
+namespace llvm {<br>
+namespace xray {<br>
+namespace {<br>
+<br>
+constexpr unsigned long long mask(BlockVerifier::State S) {<br>
+  return 1uLL << static_cast<std::size_t>(S);<br>
+}<br>
+<br>
+constexpr std::size_t number(BlockVerifier::State S) {<br>
+  return static_cast<std::size_t>(S);<br>
+}<br>
+<br>
+StringRef recordToString(BlockVerifier::State R) {<br>
+  switch (R) {<br>
+  case BlockVerifier::State::BufferExtents:<br>
+    return "BufferExtents";<br>
+  case BlockVerifier::State::NewBuffer:<br>
+    return "NewBuffer";<br>
+  case BlockVerifier::State::WallClockTime:<br>
+    return "WallClockTime";<br>
+  case BlockVerifier::State::PIDEntry:<br>
+    return "PIDEntry";<br>
+  case BlockVerifier::State::NewCPUId:<br>
+    return "NewCPUId";<br>
+  case BlockVerifier::State::TSCWrap:<br>
+    return "TSCWrap";<br>
+  case BlockVerifier::State::CustomEvent:<br>
+    return "CustomEvent";<br>
+  case BlockVerifier::State::Function:<br>
+    return "Function";<br>
+  case BlockVerifier::State::CallArg:<br>
+    return "CallArg";<br>
+  case BlockVerifier::State::EndOfBuffer:<br>
+    return "EndOfBuffer";<br>
+  case BlockVerifier::State::StateMax:<br>
+  case BlockVerifier::State::Unknown:<br>
+    return "Unknown";<br>
+  }<br>
+}<br>
+<br>
+} // namespace<br>
+<br>
+Error BlockVerifier::transition(State To) {<br>
+  using ToSet = std::bitset<number(State::StateMax)>;<br>
+  static constexpr std::array<const std::tuple<State, ToSet>,<br>
+                              number(State::StateMax)><br>
+      TransitionTable{{{State::Unknown,<br>
+                        {mask(State::BufferExtents) | mask(State::NewBuffer)}},<br>
+<br>
+                       {State::BufferExtents, {mask(State::NewBuffer)}},<br>
+<br>
+                       {State::NewBuffer, {mask(State::WallClockTime)}},<br>
+<br>
+                       {State::WallClockTime,<br>
+                        {mask(State::PIDEntry) | mask(State::NewCPUId)}},<br>
+<br>
+                       {State::PIDEntry, {mask(State::NewCPUId)}},<br>
+<br>
+                       {State::NewCPUId,<br>
+                        {mask(State::NewCPUId) | mask(State::TSCWrap) |<br>
+                         mask(State::CustomEvent) | mask(State::Function) |<br>
+                         mask(State::EndOfBuffer)}},<br>
+<br>
+                       {State::TSCWrap,<br>
+                        {mask(State::TSCWrap) | mask(State::NewCPUId) |<br>
+                         mask(State::CustomEvent) | mask(State::Function) |<br>
+                         mask(State::EndOfBuffer)}},<br>
+<br>
+                       {State::CustomEvent,<br>
+                        {mask(State::CustomEvent) | mask(State::TSCWrap) |<br>
+                         mask(State::NewCPUId) | mask(State::Function) |<br>
+                         mask(State::EndOfBuffer)}},<br>
+<br>
+                       {State::Function,<br>
+                        {mask(State::Function) | mask(State::TSCWrap) |<br>
+                         mask(State::NewCPUId) | mask(State::CustomEvent) |<br>
+                         mask(State::CallArg) | mask(State::EndOfBuffer)}},<br>
+<br>
+                       {State::CallArg,<br>
+                        {mask(State::CallArg) | mask(State::Function) |<br>
+                         mask(State::TSCWrap) | mask(State::NewCPUId) |<br>
+                         mask(State::CustomEvent) | mask(State::EndOfBuffer)}},<br>
+<br>
+                       {State::EndOfBuffer, {}}}};<br>
+<br>
+  if (CurrentRecord >= State::StateMax)<br>
+    return createStringError(<br>
+        std::make_error_code(std::errc::executable_format_error),<br>
+        "BUG (BlockVerifier): Cannot find transition table entry for %s, "<br>
+        "transitioning to %s.",<br>
+        recordToString(CurrentRecord).data(), recordToString(To).data());<br>
+<br>
+  // If we're at an EndOfBuffer record, we ignore anything that follows that<br>
+  // isn't a NewBuffer record.<br>
+  if (CurrentRecord == State::EndOfBuffer && To != State::NewBuffer)<br>
+    return Error::success();<br>
+<br>
+  auto &Mapping = TransitionTable[number(CurrentRecord)];<br>
+  auto &From = std::get<0>(Mapping);<br>
+  auto &Destinations = std::get<1>(Mapping);<br>
+  assert(From == CurrentRecord && "BUG: Wrong index for record mapping.");<br>
+  if ((Destinations & ToSet(mask(To))) == 0)<br>
+    return createStringError(<br>
+        std::make_error_code(std::errc::executable_format_error),<br>
+        "BlockVerifier: Invalid transition from %s to %s.",<br>
+        recordToString(CurrentRecord).data(), recordToString(To).data());<br>
+<br>
+  CurrentRecord = To;<br>
+  return Error::success();<br>
+} // namespace xray<br>
+<br>
+Error BlockVerifier::visit(BufferExtents &) {<br>
+  return transition(State::BufferExtents);<br>
+}<br>
+<br>
+Error BlockVerifier::visit(WallclockRecord &) {<br>
+  return transition(State::WallClockTime);<br>
+}<br>
+<br>
+Error BlockVerifier::visit(NewCPUIDRecord &) {<br>
+  return transition(State::NewCPUId);<br>
+}<br>
+<br>
+Error BlockVerifier::visit(TSCWrapRecord &) {<br>
+  return transition(State::TSCWrap);<br>
+}<br>
+<br>
+Error BlockVerifier::visit(CustomEventRecord &) {<br>
+  return transition(State::CustomEvent);<br>
+}<br>
+<br>
+Error BlockVerifier::visit(CallArgRecord &) {<br>
+  return transition(State::CallArg);<br>
+}<br>
+<br>
+Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); }<br>
+<br>
+Error BlockVerifier::visit(NewBufferRecord &) {<br>
+  return transition(State::NewBuffer);<br>
+}<br>
+<br>
+Error BlockVerifier::visit(EndBufferRecord &) {<br>
+  return transition(State::EndOfBuffer);<br>
+}<br>
+<br>
+Error BlockVerifier::visit(FunctionRecord &) {<br>
+  return transition(State::Function);<br>
+}<br>
+<br>
+Error BlockVerifier::verify() {<br>
+  // The known terminal conditions are the following:<br>
+  switch (CurrentRecord) {<br>
+  case State::EndOfBuffer:<br>
+  case State::NewCPUId:<br>
+  case State::CustomEvent:<br>
+  case State::Function:<br>
+  case State::CallArg:<br>
+  case State::TSCWrap:<br>
+    return Error::success();<br>
+  default:<br>
+    return createStringError(<br>
+        std::make_error_code(std::errc::executable_format_error),<br>
+        "BlockVerifier: Invalid terminal condition %s, malformed block.",<br>
+        recordToString(CurrentRecord).data());<br>
+  }<br>
+}<br>
+<br>
+void BlockVerifier::reset() { CurrentRecord = State::Unknown; }<br>
+<br>
+} // namespace xray<br>
+} // namespace llvm<br>
<br>
Modified: llvm/trunk/lib/XRay/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/XRay/CMakeLists.txt?rev=341628&r1=341627&r2=341628&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/XRay/CMakeLists.txt?rev=341628&r1=341627&r2=341628&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/XRay/CMakeLists.txt (original)<br>
+++ llvm/trunk/lib/XRay/CMakeLists.txt Thu Sep  6 19:25:06 2018<br>
@@ -1,5 +1,6 @@<br>
 add_llvm_library(LLVMXRay<br>
   BlockIndexer.cpp<br>
+  BlockVerifier.cpp<br>
   FDRRecordProducer.cpp<br>
   FDRRecords.cpp<br>
   FDRTraceWriter.cpp<br>
<br>
Modified: llvm/trunk/unittests/XRay/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/XRay/CMakeLists.txt?rev=341628&r1=341627&r2=341628&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/XRay/CMakeLists.txt?rev=341628&r1=341627&r2=341628&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/XRay/CMakeLists.txt (original)<br>
+++ llvm/trunk/unittests/XRay/CMakeLists.txt Thu Sep  6 19:25:06 2018<br>
@@ -1,11 +1,13 @@<br>
 set(LLVM_LINK_COMPONENTS<br>
   Support<br>
   XRay<br>
+  TestingSupport<br>
   )<br>
<br>
 add_llvm_unittest(XRayTests<br>
   ProfileTest.cpp<br>
   FDRBlockIndexerTest.cpp<br>
+  FDRBlockVerifierTest.cpp<br>
   FDRProducerConsumerTest.cpp<br>
   FDRRecordPrinterTest.cpp<br>
   FDRTraceWriterTest.cpp<br>
<br>
Added: llvm/trunk/unittests/XRay/FDRBlockVerifierTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/XRay/FDRBlockVerifierTest.cpp?rev=341628&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/XRay/FDRBlockVerifierTest.cpp?rev=341628&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/XRay/FDRBlockVerifierTest.cpp (added)<br>
+++ llvm/trunk/unittests/XRay/FDRBlockVerifierTest.cpp Thu Sep  6 19:25:06 2018<br>
@@ -0,0 +1,139 @@<br>
+//===- llvm/unittest/XRay/FDRBlockVerifierTest.cpp --------------*- C++ -*-===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+#include "llvm/Testing/Support/Error.h"<br>
+#include "llvm/XRay/BlockIndexer.h"<br>
+#include "llvm/XRay/BlockVerifier.h"<br>
+#include "llvm/XRay/FDRLogBuilder.h"<br>
+#include "llvm/XRay/FDRRecords.h"<br>
+#include "gmock/gmock.h"<br>
+#include "gtest/gtest.h"<br>
+<br>
+namespace llvm {<br>
+namespace xray {<br>
+namespace {<br>
+<br>
+using ::testing::ElementsAre;<br>
+using ::testing::Not;<br>
+using ::testing::SizeIs;<br>
+<br>
+TEST(FDRBlockVerifierTest, ValidBlocksV3) {<br>
+  auto Block0 = LogBuilder()<br>
+                    .add<BufferExtents>(80)<br>
+                    .add<NewBufferRecord>(1)<br>
+                    .add<WallclockRecord>(1, 2)<br>
+                    .add<PIDRecord>(1)<br>
+                    .add<NewCPUIDRecord>(1)<br>
+                    .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)<br>
+                    .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)<br>
+                    .consume();<br>
+  auto Block1 = LogBuilder()<br>
+                    .add<BufferExtents>(80)<br>
+                    .add<NewBufferRecord>(1)<br>
+                    .add<WallclockRecord>(1, 2)<br>
+                    .add<PIDRecord>(1)<br>
+                    .add<NewCPUIDRecord>(1)<br>
+                    .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)<br>
+                    .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)<br>
+                    .consume();<br>
+  auto Block2 = LogBuilder()<br>
+                    .add<BufferExtents>(80)<br>
+                    .add<NewBufferRecord>(2)<br>
+                    .add<WallclockRecord>(1, 2)<br>
+                    .add<PIDRecord>(1)<br>
+                    .add<NewCPUIDRecord>(2)<br>
+                    .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)<br>
+                    .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)<br>
+                    .consume();<br>
+  BlockIndexer::Index Index;<br>
+  BlockIndexer Indexer(Index);<br>
+  for (auto B : {std::ref(Block0), std::ref(Block1), std::ref(Block2)}) {<br>
+    for (auto &R : B.get())<br>
+      ASSERT_FALSE(errorToBool(R->apply(Indexer)));<br>
+    ASSERT_FALSE(errorToBool(Indexer.flush()));<br>
+  }<br>
+<br>
+  BlockVerifier Verifier;<br>
+  for (auto &ProcessThreadBlocks : Index) {<br>
+    auto &Blocks = ProcessThreadBlocks.second;<br>
+    for (auto &B : Blocks) {<br>
+      for (auto *R : B.Records)<br>
+        ASSERT_FALSE(errorToBool(R->apply(Verifier)));<br>
+      ASSERT_FALSE(errorToBool(Verifier.verify()));<br>
+      Verifier.reset();<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+TEST(FDRBlockVerifierTest, MissingPIDRecord) {<br>
+  auto Block = LogBuilder()<br>
+                   .add<BufferExtents>(20)<br>
+                   .add<NewBufferRecord>(1)<br>
+                   .add<WallclockRecord>(1, 2)<br>
+                   .add<NewCPUIDRecord>(1)<br>
+                   .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)<br>
+                   .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)<br>
+                   .consume();<br>
+  BlockVerifier Verifier;<br>
+  for (auto &R : Block)<br>
+    ASSERT_FALSE(errorToBool(R->apply(Verifier)));<br>
+  ASSERT_FALSE(errorToBool(Verifier.verify()));<br>
+}<br>
+<br>
+TEST(FDRBlockVerifierTest, MissingBufferExtents) {<br>
+  auto Block = LogBuilder()<br>
+                   .add<NewBufferRecord>(1)<br>
+                   .add<WallclockRecord>(1, 2)<br>
+                   .add<NewCPUIDRecord>(1)<br>
+                   .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)<br>
+                   .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)<br>
+                   .consume();<br>
+  BlockVerifier Verifier;<br>
+  for (auto &R : Block)<br>
+    ASSERT_FALSE(errorToBool(R->apply(Verifier)));<br>
+  ASSERT_FALSE(errorToBool(Verifier.verify()));<br>
+}<br>
+<br>
+TEST(FDRBlockVerifierTest, IgnoreRecordsAfterEOB) {<br>
+  auto Block = LogBuilder()<br>
+                   .add<NewBufferRecord>(1)<br>
+                   .add<WallclockRecord>(1, 2)<br>
+                   .add<NewCPUIDRecord>(1)<br>
+                   .add<EndBufferRecord>()<br>
+                   .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)<br>
+                   .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)<br>
+                   .consume();<br>
+  BlockVerifier Verifier;<br>
+  for (auto &R : Block)<br>
+    ASSERT_FALSE(errorToBool(R->apply(Verifier)));<br>
+  ASSERT_FALSE(errorToBool(Verifier.verify()));<br>
+}<br>
+<br>
+TEST(FDRBlockVerifierTest, MalformedV2) {<br>
+  auto Block = LogBuilder()<br>
+                   .add<NewBufferRecord>(1)<br>
+                   .add<WallclockRecord>(1, 2)<br>
+                   .add<NewCPUIDRecord>(1)<br>
+                   .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)<br>
+                   .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)<br>
+                   .add<NewBufferRecord>(2)<br>
+                   .consume();<br>
+  BlockVerifier Verifier;<br>
+<br>
+  ASSERT_THAT(Block, SizeIs(6u));<br>
+  EXPECT_THAT_ERROR(Block[0]->apply(Verifier), Succeeded());<br>
+  EXPECT_THAT_ERROR(Block[1]->apply(Verifier), Succeeded());<br>
+  EXPECT_THAT_ERROR(Block[2]->apply(Verifier), Succeeded());<br>
+  EXPECT_THAT_ERROR(Block[3]->apply(Verifier), Succeeded());<br>
+  EXPECT_THAT_ERROR(Block[4]->apply(Verifier), Succeeded());<br>
+  EXPECT_THAT_ERROR(Block[5]->apply(Verifier), Failed());<br>
+}<br>
+<br>
+} // namespace<br>
+} // namespace xray<br>
+} // namespace llvm<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>