Skip to content

Commit 258ae54

Browse files
committed
Load most of the source manager's information lazily from the PCH
file. In particular, only eagerly load source location entries for files and for the predefines buffer. Other buffers and macro-instantiation source location entries are loaded lazily. With the Cocoa-prefixed "Hello, World", we only load 815/26555 source location entities. This halves the amount of user time we spend in this "Hello, World" program with -fsyntax-only (down to .007s). This optimization is part 1 of 2 for the source manager. This eliminates most of the user time in loading a PCH file. We still spend too much time initialize File structures (especially in the calls to stat), so we need to either make the loading of source location entries for files lazy or import the stat cache from the PTH implementation. llvm-svn: 70196
1 parent 1f55182 commit 258ae54

File tree

6 files changed

+373
-142
lines changed

6 files changed

+373
-142
lines changed

clang/include/clang/Basic/SourceManager.h

+53-12
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,16 @@ namespace SrcMgr {
249249
}
250250
};
251251
} // end SrcMgr namespace.
252-
252+
253+
/// \brief External source of source location entries.
254+
class ExternalSLocEntrySource {
255+
public:
256+
virtual ~ExternalSLocEntrySource();
257+
258+
/// \brief Read the source location entry with index ID.
259+
virtual void ReadSLocEntry(unsigned ID) = 0;
260+
};
261+
253262
/// SourceManager - This file handles loading and caching of source files into
254263
/// memory. This object owns the MemoryBuffer objects for all of the loaded
255264
/// files and assigns unique FileID's for each unique #include chain.
@@ -281,7 +290,15 @@ class SourceManager {
281290
/// NextOffset - This is the next available offset that a new SLocEntry can
282291
/// start at. It is SLocEntryTable.back().getOffset()+size of back() entry.
283292
unsigned NextOffset;
284-
293+
294+
/// \brief If source location entries are being lazily loaded from
295+
/// an external source, this vector indicates whether the Ith source
296+
/// location entry has already been loaded from the external storage.
297+
std::vector<bool> SLocEntryLoaded;
298+
299+
/// \brief An external source for source location entries.
300+
ExternalSLocEntrySource *ExternalSLocEntries;
301+
285302
/// LastFileIDLookup - This is a one-entry cache to speed up getFileID.
286303
/// LastFileIDLookup records the last FileID looked up or created, because it
287304
/// is very common to look up many tokens from the same file.
@@ -308,7 +325,9 @@ class SourceManager {
308325
explicit SourceManager(const SourceManager&);
309326
void operator=(const SourceManager&);
310327
public:
311-
SourceManager() : LineTable(0), NumLinearScans(0), NumBinaryProbes(0) {
328+
SourceManager()
329+
: ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
330+
NumBinaryProbes(0) {
312331
clearIDTables();
313332
}
314333
~SourceManager();
@@ -337,19 +356,25 @@ class SourceManager {
337356
/// createFileID - Create a new FileID that represents the specified file
338357
/// being #included from the specified IncludePosition. This returns 0 on
339358
/// error and translates NULL into standard input.
359+
/// PreallocateID should be non-zero to specify which a pre-allocated,
360+
/// lazily computed source location is being filled in by this operation.
340361
FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos,
341-
SrcMgr::CharacteristicKind FileCharacter) {
362+
SrcMgr::CharacteristicKind FileCharacter,
363+
unsigned PreallocatedID = 0,
364+
unsigned Offset = 0) {
342365
const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
343366
if (IR == 0) return FileID(); // Error opening file?
344-
return createFileID(IR, IncludePos, FileCharacter);
367+
return createFileID(IR, IncludePos, FileCharacter, PreallocatedID, Offset);
345368
}
346369

347370
/// createFileIDForMemBuffer - Create a new FileID that represents the
348371
/// specified memory buffer. This does no caching of the buffer and takes
349372
/// ownership of the MemoryBuffer, so only pass a MemoryBuffer to this once.
350-
FileID createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) {
373+
FileID createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer,
374+
unsigned PreallocatedID = 0,
375+
unsigned Offset = 0) {
351376
return createFileID(createMemBufferContentCache(Buffer), SourceLocation(),
352-
SrcMgr::C_User);
377+
SrcMgr::C_User, PreallocatedID, Offset);
353378
}
354379

355380
/// createMainFileIDForMembuffer - Create the FileID for a memory buffer
@@ -367,7 +392,9 @@ class SourceManager {
367392
SourceLocation createInstantiationLoc(SourceLocation Loc,
368393
SourceLocation InstantiationLocStart,
369394
SourceLocation InstantiationLocEnd,
370-
unsigned TokLength);
395+
unsigned TokLength,
396+
unsigned PreallocatedID = 0,
397+
unsigned Offset = 0);
371398

372399
//===--------------------------------------------------------------------===//
373400
// FileID manipulation methods.
@@ -411,8 +438,9 @@ class SourceManager {
411438
/// getLocForStartOfFile - Return the source location corresponding to the
412439
/// first byte of the specified file.
413440
SourceLocation getLocForStartOfFile(FileID FID) const {
414-
assert(FID.ID < SLocEntryTable.size() && SLocEntryTable[FID.ID].isFile());
415-
unsigned FileOffset = SLocEntryTable[FID.ID].getOffset();
441+
assert(FID.ID < SLocEntryTable.size() && "FileID out of range");
442+
assert(getSLocEntry(FID).isFile() && "FileID is not a file");
443+
unsigned FileOffset = getSLocEntry(FID).getOffset();
416444
return SourceLocation::getFileLoc(FileOffset);
417445
}
418446

@@ -616,11 +644,21 @@ class SourceManager {
616644

617645
const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const {
618646
assert(FID.ID < SLocEntryTable.size() && "Invalid id");
647+
if (ExternalSLocEntries &&
648+
FID.ID < SLocEntryLoaded.size() &&
649+
!SLocEntryLoaded[FID.ID])
650+
ExternalSLocEntries->ReadSLocEntry(FID.ID);
619651
return SLocEntryTable[FID.ID];
620652
}
621653

622654
unsigned getNextOffset() const { return NextOffset; }
623655

656+
/// \brief Preallocate some number of source location entries, which
657+
/// will be loaded as needed from the given external source.
658+
void PreallocateSLocEntries(ExternalSLocEntrySource *Source,
659+
unsigned NumSLocEntries,
660+
unsigned NextOffset);
661+
624662
private:
625663
/// isOffsetInFileID - Return true if the specified FileID contains the
626664
/// specified SourceLocation offset. This is a very hot method.
@@ -632,15 +670,18 @@ class SourceManager {
632670
// If this is the last entry than it does. Otherwise, the entry after it
633671
// has to not include it.
634672
if (FID.ID+1 == SLocEntryTable.size()) return true;
635-
return SLocOffset < SLocEntryTable[FID.ID+1].getOffset();
673+
674+
return SLocOffset < getSLocEntry(FileID::get(FID.ID+1)).getOffset();
636675
}
637676

638677
/// createFileID - Create a new fileID for the specified ContentCache and
639678
/// include position. This works regardless of whether the ContentCache
640679
/// corresponds to a file or some other input source.
641680
FileID createFileID(const SrcMgr::ContentCache* File,
642681
SourceLocation IncludePos,
643-
SrcMgr::CharacteristicKind DirCharacter);
682+
SrcMgr::CharacteristicKind DirCharacter,
683+
unsigned PreallocatedID = 0,
684+
unsigned Offset = 0);
644685

645686
const SrcMgr::ContentCache *
646687
getOrCreateContentCache(const FileEntry *SourceFile);

clang/include/clang/Frontend/PCHBitCodes.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,19 @@ namespace clang {
173173

174174
/// \brief The value of the next __COUNTER__ to dispense.
175175
/// [PP_COUNTER_VALUE, Val]
176-
PP_COUNTER_VALUE = 14
176+
PP_COUNTER_VALUE = 14,
177+
178+
/// \brief Record code for the table of offsets into the block
179+
/// of source-location information.
180+
SOURCE_LOCATION_OFFSETS = 15,
181+
182+
/// \brief Record code for the set of source location entries
183+
/// that need to be preloaded by the PCH reader.
184+
///
185+
/// This set contains the source location entry for the
186+
/// predefines buffer and for any file entries that need to be
187+
/// preloaded.
188+
SOURCE_LOCATION_PRELOADS = 16
177189
};
178190

179191
/// \brief Record types used within a source manager block.

clang/include/clang/Frontend/PCHReader.h

+21-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "clang/AST/Type.h"
2222
#include "clang/Basic/Diagnostic.h"
2323
#include "clang/Basic/IdentifierTable.h"
24+
#include "clang/Basic/SourceManager.h"
2425
#include "llvm/ADT/APFloat.h"
2526
#include "llvm/ADT/APInt.h"
2627
#include "llvm/ADT/APSInt.h"
@@ -68,7 +69,8 @@ class SwitchCase;
6869
class PCHReader
6970
: public ExternalSemaSource,
7071
public IdentifierInfoLookup,
71-
public ExternalIdentifierLookup {
72+
public ExternalIdentifierLookup,
73+
public ExternalSLocEntrySource {
7274
public:
7375
enum PCHReadResult { Success, Failure, IgnorePCH };
7476

@@ -102,6 +104,16 @@ class PCHReader
102104
/// this PCH file.
103105
llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
104106

107+
/// \brief Offset type for all of the source location entries in the
108+
/// PCH file.
109+
const uint64_t *SLocOffsets;
110+
111+
/// \brief The number of source location entries in the PCH file.
112+
unsigned TotalNumSLocEntries;
113+
114+
/// \brief Cursor used to read source location entries.
115+
llvm::BitstreamCursor SLocEntryCursor;
116+
105117
/// \brief Offset of each type within the bitstream, indexed by the
106118
/// type ID, or the representation of a Type*.
107119
const uint64_t *TypeOffsets;
@@ -214,6 +226,10 @@ class PCHReader
214226
/// been de-serialized.
215227
std::multimap<unsigned, AddrLabelExpr *> UnresolvedAddrLabelExprs;
216228

229+
/// \brief The number of source location entries de-serialized from
230+
/// the PCH file.
231+
unsigned NumSLocEntriesRead;
232+
217233
/// \brief The number of statements (and expressions) de-serialized
218234
/// from the PCH file.
219235
unsigned NumStatementsRead;
@@ -257,6 +273,7 @@ class PCHReader
257273
unsigned PCHPredefLen,
258274
FileID PCHBufferID);
259275
PCHReadResult ReadSourceManagerBlock();
276+
PCHReadResult ReadSLocEntryRecord(unsigned ID);
260277

261278
bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record);
262279
QualType ReadTypeRecord(uint64_t Offset);
@@ -380,6 +397,9 @@ class PCHReader
380397
return DecodeIdentifierInfo(ID);
381398
}
382399

400+
/// \brief Read the source location entry with index ID.
401+
virtual void ReadSLocEntry(unsigned ID);
402+
383403
Selector DecodeSelector(unsigned Idx);
384404

385405
Selector GetSelector(const RecordData &Record, unsigned &Idx) {

clang/lib/Basic/SourceManager.cpp

+52-4
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,17 @@ SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) {
308308
return Entry;
309309
}
310310

311+
void SourceManager::PreallocateSLocEntries(ExternalSLocEntrySource *Source,
312+
unsigned NumSLocEntries,
313+
unsigned NextOffset) {
314+
ExternalSLocEntries = Source;
315+
this->NextOffset = NextOffset;
316+
SLocEntryLoaded.resize(NumSLocEntries + 1);
317+
SLocEntryLoaded[0] = true;
318+
SLocEntryTable.resize(SLocEntryTable.size() + NumSLocEntries);
319+
}
320+
321+
311322
//===----------------------------------------------------------------------===//
312323
// Methods to create new FileID's and instantiations.
313324
//===----------------------------------------------------------------------===//
@@ -317,7 +328,26 @@ SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) {
317328
/// corresponds to a file or some other input source.
318329
FileID SourceManager::createFileID(const ContentCache *File,
319330
SourceLocation IncludePos,
320-
SrcMgr::CharacteristicKind FileCharacter) {
331+
SrcMgr::CharacteristicKind FileCharacter,
332+
unsigned PreallocatedID,
333+
unsigned Offset) {
334+
SLocEntry NewEntry = SLocEntry::get(NextOffset,
335+
FileInfo::get(IncludePos, File,
336+
FileCharacter));
337+
if (PreallocatedID) {
338+
// If we're filling in a preallocated ID, just load in the file
339+
// entry and return.
340+
assert(PreallocatedID < SLocEntryLoaded.size() &&
341+
"Preallocate ID out-of-range");
342+
assert(!SLocEntryLoaded[PreallocatedID] &&
343+
"Source location entry already loaded");
344+
assert(Offset && "Preallocate source location cannot have zero offset");
345+
SLocEntryTable[PreallocatedID]
346+
= SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter));
347+
SLocEntryLoaded[PreallocatedID] = true;
348+
return LastFileIDLookup = FileID::get(PreallocatedID);
349+
}
350+
321351
SLocEntryTable.push_back(SLocEntry::get(NextOffset,
322352
FileInfo::get(IncludePos, File,
323353
FileCharacter)));
@@ -336,8 +366,22 @@ FileID SourceManager::createFileID(const ContentCache *File,
336366
SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc,
337367
SourceLocation ILocStart,
338368
SourceLocation ILocEnd,
339-
unsigned TokLength) {
369+
unsigned TokLength,
370+
unsigned PreallocatedID,
371+
unsigned Offset) {
340372
InstantiationInfo II = InstantiationInfo::get(ILocStart,ILocEnd, SpellingLoc);
373+
if (PreallocatedID) {
374+
// If we're filling in a preallocated ID, just load in the
375+
// instantiation entry and return.
376+
assert(PreallocatedID < SLocEntryLoaded.size() &&
377+
"Preallocate ID out-of-range");
378+
assert(!SLocEntryLoaded[PreallocatedID] &&
379+
"Source location entry already loaded");
380+
assert(Offset && "Preallocate source location cannot have zero offset");
381+
SLocEntryTable[PreallocatedID] = SLocEntry::get(Offset, II);
382+
SLocEntryLoaded[PreallocatedID] = true;
383+
return SourceLocation::getMacroLoc(Offset);
384+
}
341385
SLocEntryTable.push_back(SLocEntry::get(NextOffset, II));
342386
assert(NextOffset+TokLength+1 > NextOffset && "Ran out of source locations!");
343387
NextOffset += TokLength+1;
@@ -391,6 +435,8 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
391435
unsigned NumProbes = 0;
392436
while (1) {
393437
--I;
438+
if (ExternalSLocEntries)
439+
getSLocEntry(FileID::get(I - SLocEntryTable.begin()));
394440
if (I->getOffset() <= SLocOffset) {
395441
#if 0
396442
printf("lin %d -> %d [%s] %d %d\n", SLocOffset,
@@ -399,7 +445,7 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
399445
LastFileIDLookup.ID, int(SLocEntryTable.end()-I));
400446
#endif
401447
FileID Res = FileID::get(I-SLocEntryTable.begin());
402-
448+
403449
// If this isn't an instantiation, remember it. We have good locality
404450
// across FileID lookups.
405451
if (!I->isInstantiation())
@@ -421,7 +467,7 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
421467
NumProbes = 0;
422468
while (1) {
423469
unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
424-
unsigned MidOffset = SLocEntryTable[MiddleIndex].getOffset();
470+
unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex)).getOffset();
425471

426472
++NumProbes;
427473

@@ -865,3 +911,5 @@ void SourceManager::PrintStats() const {
865911
llvm::cerr << "FileID scans: " << NumLinearScans << " linear, "
866912
<< NumBinaryProbes << " binary.\n";
867913
}
914+
915+
ExternalSLocEntrySource::~ExternalSLocEntrySource() { }

0 commit comments

Comments
 (0)