Skip to content

Commit 90b8b8d

Browse files
author
Zachary Turner
committed
[pdb] Add unit tests for PDB MappedBlockStream and zero copy
Differential Revision: http://reviews.llvm.org/D20837 Reviewed By: ruiu llvm-svn: 271346
1 parent f9acaca commit 90b8b8d

File tree

12 files changed

+186
-16
lines changed

12 files changed

+186
-16
lines changed

llvm/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,19 @@
1919
namespace llvm {
2020
namespace pdb {
2121

22-
struct IPDBFile {
22+
class IPDBFile {
2323
public:
2424
virtual ~IPDBFile() {}
2525

2626
virtual uint32_t getBlockSize() const = 0;
2727
virtual uint32_t getBlockCount() const = 0;
28-
virtual uint32_t getNumDirectoryBytes() const = 0;
29-
virtual uint32_t getBlockMapIndex() const = 0;
30-
virtual uint32_t getNumDirectoryBlocks() const = 0;
31-
virtual uint64_t getBlockMapOffset() const = 0;
3228

3329
virtual uint32_t getNumStreams() const = 0;
3430
virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const = 0;
3531
virtual ArrayRef<uint32_t> getStreamBlockList(uint32_t StreamIndex) const = 0;
3632

3733
virtual StringRef getBlockData(uint32_t BlockIndex,
3834
uint32_t NumBytes) const = 0;
39-
40-
virtual ArrayRef<support::ulittle32_t> getDirectoryBlockArray() = 0;
4135
};
4236
}
4337
}

llvm/include/llvm/DebugInfo/PDB/Raw/InfoStream.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
namespace llvm {
2323
namespace pdb {
24+
class PDBFile;
2425
class InfoStream {
2526
public:
2627
InfoStream(PDBFile &File);

llvm/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,19 @@
2121
namespace llvm {
2222
namespace pdb {
2323

24-
class PDBFile;
24+
class IPDBFile;
2525

2626
class MappedBlockStream : public codeview::StreamInterface {
2727
public:
28-
MappedBlockStream(uint32_t StreamIdx, const PDBFile &File);
28+
MappedBlockStream(uint32_t StreamIdx, const IPDBFile &File);
2929

3030
Error readBytes(uint32_t Offset, uint32_t Size,
3131
ArrayRef<uint8_t> &Buffer) const override;
3232

3333
uint32_t getLength() const override { return StreamLength; }
3434

35+
uint32_t getNumBytesCopied() const;
36+
3537
private:
3638
Error readBytes(uint32_t Offset, MutableArrayRef<uint8_t> Buffer) const;
3739
bool tryReadContiguously(uint32_t Offset, uint32_t Size,
@@ -41,7 +43,7 @@ class MappedBlockStream : public codeview::StreamInterface {
4143
std::vector<uint32_t> BlockList;
4244
mutable llvm::BumpPtrAllocator Pool;
4345
mutable DenseMap<uint32_t, uint8_t *> CacheMap;
44-
const PDBFile &Pdb;
46+
const IPDBFile &Pdb;
4547
};
4648

4749
} // end namespace pdb

llvm/include/llvm/DebugInfo/PDB/Raw/PDBFile.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,18 @@ class PDBFile : public IPDBFile {
3939

4040
uint32_t getBlockSize() const override;
4141
uint32_t getBlockCount() const override;
42-
uint32_t getNumDirectoryBytes() const override;
43-
uint32_t getBlockMapIndex() const override;
44-
uint32_t getNumDirectoryBlocks() const override;
45-
uint64_t getBlockMapOffset() const override;
42+
uint32_t getNumDirectoryBytes() const;
43+
uint32_t getBlockMapIndex() const;
44+
uint32_t getNumDirectoryBlocks() const;
45+
uint64_t getBlockMapOffset() const;
4646

4747
uint32_t getNumStreams() const override;
4848
uint32_t getStreamByteSize(uint32_t StreamIndex) const override;
4949
ArrayRef<uint32_t> getStreamBlockList(uint32_t StreamIndex) const override;
5050

5151
StringRef getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const override;
5252

53-
ArrayRef<support::ulittle32_t> getDirectoryBlockArray() override;
53+
ArrayRef<support::ulittle32_t> getDirectoryBlockArray();
5454

5555
Error parseFileHeaders();
5656
Error parseStreamData();

llvm/include/llvm/Support/Allocator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ class BumpPtrAllocatorImpl
278278
return TotalMemory;
279279
}
280280

281+
size_t getBytesAllocated() const { return BytesAllocated; }
282+
281283
void PrintStats() const {
282284
detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated,
283285
getTotalMemory());

llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "llvm/ADT/BitVector.h"
1212
#include "llvm/ADT/SmallVector.h"
1313
#include "llvm/DebugInfo/CodeView/StreamReader.h"
14+
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
1415
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
1516
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
1617

llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
using namespace llvm;
1515
using namespace llvm::pdb;
1616

17-
MappedBlockStream::MappedBlockStream(uint32_t StreamIdx, const PDBFile &File) : Pdb(File) {
17+
MappedBlockStream::MappedBlockStream(uint32_t StreamIdx, const IPDBFile &File)
18+
: Pdb(File) {
1819
if (StreamIdx >= Pdb.getNumStreams()) {
1920
StreamLength = 0;
2021
} else {
@@ -119,3 +120,7 @@ Error MappedBlockStream::readBytes(uint32_t Offset,
119120
return Error::success();
120121

121122
}
123+
124+
uint32_t MappedBlockStream::getNumBytesCopied() const {
125+
return static_cast<uint32_t>(Pool.getBytesAllocated());
126+
}

llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "llvm/DebugInfo/CodeView/StreamReader.h"
1313
#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
14+
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
1415
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
1516

1617
using namespace llvm;

llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/DebugInfo/CodeView/StreamReader.h"
1414
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
1515
#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
16+
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
1617
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
1718
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
1819

llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/DebugInfo/CodeView/StreamReader.h"
1414
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
1515
#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
16+
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
1617
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
1718
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
1819

llvm/unittests/DebugInfo/PDB/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
33
)
44

55
set(DebugInfoPDBSources
6+
MappedBlockStreamTest.cpp
67
PDBApiTest.cpp
78
)
89

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
//===- llvm/unittest/DebugInfo/PDB/MappedBlockStreamTest.cpp --------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include <unordered_map>
11+
12+
#include "llvm/DebugInfo/CodeView/StreamReader.h"
13+
#include "llvm/DebugInfo/CodeView/StreamRef.h"
14+
#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h"
15+
#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
16+
#include "gtest/gtest.h"
17+
18+
using namespace llvm;
19+
using namespace llvm::codeview;
20+
using namespace llvm::pdb;
21+
22+
namespace {
23+
24+
#define EXPECT_NO_ERROR(Err) \
25+
{ \
26+
auto E = std::move(Err); \
27+
EXPECT_FALSE(static_cast<bool>(E)); \
28+
if (E) \
29+
consumeError(std::move(E)); \
30+
}
31+
32+
#define EXPECT_ERROR(Err) \
33+
{ \
34+
auto E = std::move(Err); \
35+
EXPECT_TRUE(static_cast<bool>(E)); \
36+
if (E) \
37+
consumeError(std::move(E)); \
38+
}
39+
40+
class DiscontiguousFile : public IPDBFile {
41+
public:
42+
DiscontiguousFile()
43+
: Blocks{0, 1, 2, 5, 4, 3, 6, 7, 8, 9},
44+
Data{'A', 'B', 'C', 'F', 'E', 'D', 'G', 'H', 'I', 'J'} {}
45+
46+
virtual uint32_t getBlockSize() const override { return 1; }
47+
virtual uint32_t getBlockCount() const override { return 10; }
48+
virtual uint32_t getNumStreams() const override { return 1; }
49+
virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const override {
50+
return getBlockCount() * getBlockSize();
51+
}
52+
virtual ArrayRef<uint32_t>
53+
getStreamBlockList(uint32_t StreamIndex) const override {
54+
if (StreamIndex != 0)
55+
return ArrayRef<uint32_t>();
56+
return Blocks;
57+
}
58+
virtual StringRef getBlockData(uint32_t BlockIndex,
59+
uint32_t NumBytes) const override {
60+
return StringRef(&Data[BlockIndex], NumBytes);
61+
}
62+
63+
private:
64+
std::vector<uint32_t> Blocks;
65+
std::vector<char> Data;
66+
};
67+
68+
// Tests that a read which is entirely contained within a single block works
69+
// and does not allocate.
70+
TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) {
71+
DiscontiguousFile F;
72+
MappedBlockStream S(0, F);
73+
StreamReader R(S);
74+
StringRef Str;
75+
EXPECT_NO_ERROR(R.readFixedString(Str, 1));
76+
EXPECT_EQ(Str, StringRef("A"));
77+
EXPECT_EQ(0, S.getNumBytesCopied());
78+
}
79+
80+
// Tests that a read which outputs into a full destination buffer works and
81+
// does not fail due to the length of the output buffer.
82+
TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) {
83+
DiscontiguousFile F;
84+
MappedBlockStream S(0, F);
85+
StreamReader R(S);
86+
StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA";
87+
EXPECT_NO_ERROR(R.readFixedString(Str, 1));
88+
EXPECT_EQ(Str, StringRef("A"));
89+
EXPECT_EQ(0, S.getNumBytesCopied());
90+
}
91+
92+
// Tests that a read which crosses a block boundary, but where the subsequent
93+
// blocks are still contiguous in memory to the previous block works and does
94+
// not allocate memory.
95+
TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) {
96+
DiscontiguousFile F;
97+
MappedBlockStream S(0, F);
98+
StreamReader R(S);
99+
StringRef Str;
100+
EXPECT_NO_ERROR(R.readFixedString(Str, 2));
101+
EXPECT_EQ(Str, StringRef("AB"));
102+
EXPECT_EQ(0, S.getNumBytesCopied());
103+
104+
R.setOffset(6);
105+
EXPECT_NO_ERROR(R.readFixedString(Str, 4));
106+
EXPECT_EQ(Str, StringRef("GHIJ"));
107+
EXPECT_EQ(0, S.getNumBytesCopied());
108+
}
109+
110+
// Tests that a read which crosses a block boundary and cannot be referenced
111+
// contiguously works and allocates only the precise amount of bytes
112+
// requested.
113+
TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) {
114+
DiscontiguousFile F;
115+
MappedBlockStream S(0, F);
116+
StreamReader R(S);
117+
StringRef Str;
118+
EXPECT_NO_ERROR(R.readFixedString(Str, 10));
119+
EXPECT_EQ(Str, StringRef("ABCDEFGHIJ"));
120+
EXPECT_EQ(10, S.getNumBytesCopied());
121+
}
122+
123+
// Test that an out of bounds read which doesn't cross a block boundary
124+
// fails and allocates no memory.
125+
TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) {
126+
DiscontiguousFile F;
127+
MappedBlockStream S(0, F);
128+
StreamReader R(S);
129+
StringRef Str;
130+
131+
R.setOffset(10);
132+
EXPECT_ERROR(R.readFixedString(Str, 1));
133+
EXPECT_EQ(0, S.getNumBytesCopied());
134+
}
135+
136+
// Test that an out of bounds read which crosses a contiguous block boundary
137+
// fails and allocates no memory.
138+
TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) {
139+
DiscontiguousFile F;
140+
MappedBlockStream S(0, F);
141+
StreamReader R(S);
142+
StringRef Str;
143+
144+
R.setOffset(6);
145+
EXPECT_ERROR(R.readFixedString(Str, 5));
146+
EXPECT_EQ(0, S.getNumBytesCopied());
147+
}
148+
149+
// Test that an out of bounds read which crosses a discontiguous block
150+
// boundary fails and allocates no memory.
151+
TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) {
152+
DiscontiguousFile F;
153+
MappedBlockStream S(0, F);
154+
StreamReader R(S);
155+
StringRef Str;
156+
157+
EXPECT_ERROR(R.readFixedString(Str, 11));
158+
EXPECT_EQ(0, S.getNumBytesCopied());
159+
}
160+
161+
} // end anonymous namespace

0 commit comments

Comments
 (0)