1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 04:32:44 +01:00
llvm-mirror/unittests/Support/SourceMgrTest.cpp
Graydon Hoare cded1d3751 [Support] Make line-number cache robust against access patterns.
Summary:
The LLVM SourceMgr class (which is used indirectly by Swift, though not Clang)
has a routine for looking up line numbers of SMLocs. This routine uses a
shared, special-purpose cache that handles exactly one access pattern
efficiently: looking up the line number of an SMLoc that points into the same
buffer as the last query made to the SourceMgr, at a location in the buffer at
or ahead of the last query.

When this works it's fine, but when it fails it's catastrophic for performancer:
one recent out-of-order access from a Swift utility routine ran for tens of
seconds, spending 99% of its time repeatedly scanning buffers for '\n'.

This change removes the shared cache from the SourceMgr and installs a new
cache in each SrcBuffer. The per-SrcBuffer caches are also "full", in the sense
that rather than caching a single last-query pointer, they cache _all_ the
line-ending offsets, in a binary-searchable array, such that once it's
populated (on first access), all subsequent access patterns run at the same
speed.

Performance measurements I've done show this is actually a little bit faster on
real codebases (though only a couple fractions of a percent). Memory usage is
up by a few tens to hundreds of bytes per SrcBuffer that has a line lookup done
on it; I've attempted to minimize this by using dynamic selection of integer
sized when storing offset arrays. But the main motive here is to
make-impossible the cases we don't always see, that show up by surprise when
there is an out-of-order access pattern.

Reviewers: jordan_rose

Reviewed By: jordan_rose

Subscribers: probinson, llvm-commits

Differential Revision: https://reviews.llvm.org/D45003

llvm-svn: 329470
2018-04-07 00:44:02 +00:00

500 lines
16 KiB
C++

//===- unittests/Support/SourceMgrTest.cpp - SourceMgr tests --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
class SourceMgrTest : public testing::Test {
public:
SourceMgr SM;
unsigned MainBufferID;
std::string Output;
void setMainBuffer(StringRef Text, StringRef BufferName) {
std::unique_ptr<MemoryBuffer> MainBuffer =
MemoryBuffer::getMemBuffer(Text, BufferName);
MainBufferID = SM.AddNewSourceBuffer(std::move(MainBuffer), llvm::SMLoc());
}
SMLoc getLoc(unsigned Offset) {
return SMLoc::getFromPointer(
SM.getMemoryBuffer(MainBufferID)->getBufferStart() + Offset);
}
SMRange getRange(unsigned Offset, unsigned Length) {
return SMRange(getLoc(Offset), getLoc(Offset + Length));
}
void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
const Twine &Msg, ArrayRef<SMRange> Ranges,
ArrayRef<SMFixIt> FixIts) {
raw_string_ostream OS(Output);
SM.PrintMessage(OS, Loc, Kind, Msg, Ranges, FixIts);
}
};
} // unnamed namespace
TEST_F(SourceMgrTest, BasicError) {
setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
printMessage(getLoc(4), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:1:5: error: message\n"
"aaa bbb\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, BasicWarning) {
setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
printMessage(getLoc(4), SourceMgr::DK_Warning, "message", None, None);
EXPECT_EQ("file.in:1:5: warning: message\n"
"aaa bbb\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, BasicRemark) {
setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
printMessage(getLoc(4), SourceMgr::DK_Remark, "message", None, None);
EXPECT_EQ("file.in:1:5: remark: message\n"
"aaa bbb\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, BasicNote) {
setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
printMessage(getLoc(4), SourceMgr::DK_Note, "message", None, None);
EXPECT_EQ("file.in:1:5: note: message\n"
"aaa bbb\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationAtEndOfLine) {
setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
printMessage(getLoc(6), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:1:7: error: message\n"
"aaa bbb\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationAtNewline) {
setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
printMessage(getLoc(7), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:1:8: error: message\n"
"aaa bbb\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationAtEmptyBuffer) {
setMainBuffer("", "file.in");
printMessage(getLoc(0), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:1:1: error: message\n"
"\n"
"^\n",
Output);
}
TEST_F(SourceMgrTest, LocationJustOnSoleNewline) {
setMainBuffer("\n", "file.in");
printMessage(getLoc(0), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:1:1: error: message\n"
"\n"
"^\n",
Output);
}
TEST_F(SourceMgrTest, LocationJustAfterSoleNewline) {
setMainBuffer("\n", "file.in");
printMessage(getLoc(1), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:2:1: error: message\n"
"\n"
"^\n",
Output);
}
TEST_F(SourceMgrTest, LocationJustAfterNonNewline) {
setMainBuffer("123", "file.in");
printMessage(getLoc(3), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:1:4: error: message\n"
"123\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationOnFirstLineOfMultiline) {
setMainBuffer("1234\n6789\n", "file.in");
printMessage(getLoc(3), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:1:4: error: message\n"
"1234\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationOnEOLOfFirstLineOfMultiline) {
setMainBuffer("1234\n6789\n", "file.in");
printMessage(getLoc(4), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:1:5: error: message\n"
"1234\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationOnSecondLineOfMultiline) {
setMainBuffer("1234\n6789\n", "file.in");
printMessage(getLoc(5), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:2:1: error: message\n"
"6789\n"
"^\n",
Output);
}
TEST_F(SourceMgrTest, LocationOnSecondLineOfMultilineNoSecondEOL) {
setMainBuffer("1234\n6789", "file.in");
printMessage(getLoc(5), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:2:1: error: message\n"
"6789\n"
"^\n",
Output);
}
TEST_F(SourceMgrTest, LocationOnEOLOfSecondSecondLineOfMultiline) {
setMainBuffer("1234\n6789\n", "file.in");
printMessage(getLoc(9), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:2:5: error: message\n"
"6789\n"
" ^\n",
Output);
}
#define STRING_LITERAL_253_BYTES \
"1234567890\n1234567890\n" \
"1234567890\n1234567890\n" \
"1234567890\n1234567890\n" \
"1234567890\n1234567890\n" \
"1234567890\n1234567890\n" \
"1234567890\n1234567890\n" \
"1234567890\n1234567890\n" \
"1234567890\n1234567890\n" \
"1234567890\n1234567890\n" \
"1234567890\n1234567890\n" \
"1234567890\n1234567890\n" \
"1234567890\n"
//===----------------------------------------------------------------------===//
// 255-byte buffer tests
//===----------------------------------------------------------------------===//
TEST_F(SourceMgrTest, LocationBeforeEndOf255ByteBuffer) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"12" // + 2 = 255 bytes
, "file.in");
printMessage(getLoc(253), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:1: error: message\n"
"12\n"
"^\n",
Output);
}
TEST_F(SourceMgrTest, LocationAtEndOf255ByteBuffer) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"12" // + 2 = 255 bytes
, "file.in");
printMessage(getLoc(254), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:2: error: message\n"
"12\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationPastEndOf255ByteBuffer) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"12" // + 2 = 255 bytes
, "file.in");
printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:3: error: message\n"
"12\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationBeforeEndOf255ByteBufferEndingInNewline) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"1\n" // + 2 = 255 bytes
, "file.in");
printMessage(getLoc(253), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:1: error: message\n"
"1\n"
"^\n",
Output);
}
TEST_F(SourceMgrTest, LocationAtEndOf255ByteBufferEndingInNewline) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"1\n" // + 2 = 255 bytes
, "file.in");
printMessage(getLoc(254), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:2: error: message\n"
"1\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationPastEndOf255ByteBufferEndingInNewline) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"1\n" // + 2 = 255 bytes
, "file.in");
printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:25:1: error: message\n"
"\n"
"^\n",
Output);
}
//===----------------------------------------------------------------------===//
// 256-byte buffer tests
//===----------------------------------------------------------------------===//
TEST_F(SourceMgrTest, LocationBeforeEndOf256ByteBuffer) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"123" // + 3 = 256 bytes
, "file.in");
printMessage(getLoc(254), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:2: error: message\n"
"123\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationAtEndOf256ByteBuffer) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"123" // + 3 = 256 bytes
, "file.in");
printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:3: error: message\n"
"123\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationPastEndOf256ByteBuffer) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"123" // + 3 = 256 bytes
, "file.in");
printMessage(getLoc(256), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:4: error: message\n"
"123\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationBeforeEndOf256ByteBufferEndingInNewline) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"12\n" // + 3 = 256 bytes
, "file.in");
printMessage(getLoc(254), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:2: error: message\n"
"12\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationAtEndOf256ByteBufferEndingInNewline) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"12\n" // + 3 = 256 bytes
, "file.in");
printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:3: error: message\n"
"12\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationPastEndOf256ByteBufferEndingInNewline) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"12\n" // + 3 = 256 bytes
, "file.in");
printMessage(getLoc(256), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:25:1: error: message\n"
"\n"
"^\n",
Output);
}
//===----------------------------------------------------------------------===//
// 257-byte buffer tests
//===----------------------------------------------------------------------===//
TEST_F(SourceMgrTest, LocationBeforeEndOf257ByteBuffer) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"1234" // + 4 = 257 bytes
, "file.in");
printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:3: error: message\n"
"1234\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationAtEndOf257ByteBuffer) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"1234" // + 4 = 257 bytes
, "file.in");
printMessage(getLoc(256), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:4: error: message\n"
"1234\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationPastEndOf257ByteBuffer) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"1234" // + 4 = 257 bytes
, "file.in");
printMessage(getLoc(257), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:5: error: message\n"
"1234\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationBeforeEndOf257ByteBufferEndingInNewline) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"123\n" // + 4 = 257 bytes
, "file.in");
printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:3: error: message\n"
"123\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationAtEndOf257ByteBufferEndingInNewline) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"123\n" // + 4 = 257 bytes
, "file.in");
printMessage(getLoc(256), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:24:4: error: message\n"
"123\n"
" ^\n",
Output);
}
TEST_F(SourceMgrTest, LocationPastEndOf257ByteBufferEndingInNewline) {
setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
"123\n" // + 4 = 257 bytes
, "file.in");
printMessage(getLoc(257), SourceMgr::DK_Error, "message", None, None);
EXPECT_EQ("file.in:25:1: error: message\n"
"\n"
"^\n",
Output);
}
TEST_F(SourceMgrTest, BasicRange) {
setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
printMessage(getLoc(4), SourceMgr::DK_Error, "message", getRange(4, 3), None);
EXPECT_EQ("file.in:1:5: error: message\n"
"aaa bbb\n"
" ^~~\n",
Output);
}
TEST_F(SourceMgrTest, RangeWithTab) {
setMainBuffer("aaa\tbbb\nccc ddd\n", "file.in");
printMessage(getLoc(4), SourceMgr::DK_Error, "message", getRange(3, 3), None);
EXPECT_EQ("file.in:1:5: error: message\n"
"aaa bbb\n"
" ~~~~~^~\n",
Output);
}
TEST_F(SourceMgrTest, MultiLineRange) {
setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
printMessage(getLoc(4), SourceMgr::DK_Error, "message", getRange(4, 7), None);
EXPECT_EQ("file.in:1:5: error: message\n"
"aaa bbb\n"
" ^~~\n",
Output);
}
TEST_F(SourceMgrTest, MultipleRanges) {
setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
SMRange Ranges[] = { getRange(0, 3), getRange(4, 3) };
printMessage(getLoc(4), SourceMgr::DK_Error, "message", Ranges, None);
EXPECT_EQ("file.in:1:5: error: message\n"
"aaa bbb\n"
"~~~ ^~~\n",
Output);
}
TEST_F(SourceMgrTest, OverlappingRanges) {
setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
SMRange Ranges[] = { getRange(0, 3), getRange(2, 4) };
printMessage(getLoc(4), SourceMgr::DK_Error, "message", Ranges, None);
EXPECT_EQ("file.in:1:5: error: message\n"
"aaa bbb\n"
"~~~~^~\n",
Output);
}
TEST_F(SourceMgrTest, BasicFixit) {
setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
printMessage(getLoc(4), SourceMgr::DK_Error, "message", None,
makeArrayRef(SMFixIt(getRange(4, 3), "zzz")));
EXPECT_EQ("file.in:1:5: error: message\n"
"aaa bbb\n"
" ^~~\n"
" zzz\n",
Output);
}
TEST_F(SourceMgrTest, FixitForTab) {
setMainBuffer("aaa\tbbb\nccc ddd\n", "file.in");
printMessage(getLoc(3), SourceMgr::DK_Error, "message", None,
makeArrayRef(SMFixIt(getRange(3, 1), "zzz")));
EXPECT_EQ("file.in:1:4: error: message\n"
"aaa bbb\n"
" ^^^^^\n"
" zzz\n",
Output);
}