Skip to content

Commit 42eb382

Browse files
committed
[clangd] [C++20] [Modules] Introduce cache for scanning modules
1 parent 8c222c1 commit 42eb382

File tree

3 files changed

+112
-24
lines changed

3 files changed

+112
-24
lines changed

clang-tools-extra/clangd/ModulesBuilder.cpp

Lines changed: 98 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -360,16 +360,17 @@ void ModuleFileCache::remove(StringRef ModuleName) {
360360
/// Collect the directly and indirectly required module names for \param
361361
/// ModuleName in topological order. The \param ModuleName is guaranteed to
362362
/// be the last element in \param ModuleNames.
363-
llvm::SmallVector<StringRef> getAllRequiredModules(ProjectModules &MDB,
363+
llvm::SmallVector<StringRef> getAllRequiredModules(PathRef RequiredSource,
364+
ProjectModules &MDB,
364365
StringRef ModuleName) {
365366
llvm::SmallVector<llvm::StringRef> ModuleNames;
366367
llvm::StringSet<> ModuleNamesSet;
367368

368369
auto VisitDeps = [&](StringRef ModuleName, auto Visitor) -> void {
369370
ModuleNamesSet.insert(ModuleName);
370371

371-
for (StringRef RequiredModuleName :
372-
MDB.getRequiredModules(MDB.getSourceForModuleName(ModuleName)))
372+
for (StringRef RequiredModuleName : MDB.getRequiredModules(
373+
MDB.getSourceForModuleName(ModuleName, RequiredSource)))
373374
if (ModuleNamesSet.insert(RequiredModuleName).second)
374375
Visitor(RequiredModuleName, Visitor);
375376

@@ -380,30 +381,114 @@ llvm::SmallVector<StringRef> getAllRequiredModules(ProjectModules &MDB,
380381
return ModuleNames;
381382
}
382383

384+
class CachingProjectModules : public ProjectModules {
385+
public:
386+
CachingProjectModules(const GlobalCompilationDatabase &CDB) : CDB(CDB) {}
387+
388+
std::vector<std::string> getRequiredModules(PathRef File) override {
389+
std::unique_ptr<ProjectModules> MDB = CDB.getProjectModules(File);
390+
if (!MDB) {
391+
elog("Failed to get Project Modules information for {0}", File);
392+
return {};
393+
}
394+
return MDB->getRequiredModules(File);
395+
}
396+
397+
std::string getModuleNameForSource(PathRef File) override {
398+
std::unique_ptr<ProjectModules> MDB = CDB.getProjectModules(File);
399+
if (!MDB) {
400+
elog("Failed to get Project Modules information for {0}", File);
401+
return {};
402+
}
403+
return MDB->getModuleNameForSource(File);
404+
}
405+
406+
void setCommandMangler(CommandMangler M) override {
407+
// GlobalCompilationDatabase::getProjectModules() will set mangler
408+
// for the underlying ProjectModules.
409+
}
410+
411+
std::string getSourceForModuleName(llvm::StringRef ModuleName,
412+
PathRef RequiredSrcFile) override {
413+
std::string CachedResult;
414+
{
415+
std::lock_guard<std::mutex> Lock(CacheMutex);
416+
auto Iter = ModuleNameToSourceCache.find(ModuleName);
417+
if (Iter != ModuleNameToSourceCache.end())
418+
CachedResult = Iter->second;
419+
}
420+
421+
std::unique_ptr<ProjectModules> MDB =
422+
CDB.getProjectModules(RequiredSrcFile);
423+
if (!MDB) {
424+
elog("Failed to get Project Modules information for {0}",
425+
RequiredSrcFile);
426+
return {};
427+
}
428+
429+
// Verify Cached Result by seeing if the source declaring the same module
430+
// as we query.
431+
if (!CachedResult.empty()) {
432+
std::string ModuleNameOfCachedSource =
433+
MDB->getModuleNameForSource(CachedResult);
434+
if (ModuleNameOfCachedSource == ModuleName)
435+
return CachedResult;
436+
else {
437+
// Cached Result is invalid. Clear it.
438+
439+
std::lock_guard<std::mutex> Lock(CacheMutex);
440+
ModuleNameToSourceCache.erase(ModuleName);
441+
}
442+
}
443+
444+
auto Result = MDB->getSourceForModuleName(ModuleName, RequiredSrcFile);
445+
446+
{
447+
std::lock_guard<std::mutex> Lock(CacheMutex);
448+
ModuleNameToSourceCache.insert({ModuleName, Result});
449+
}
450+
451+
return Result;
452+
}
453+
454+
private:
455+
const GlobalCompilationDatabase &CDB;
456+
457+
std::mutex CacheMutex;
458+
llvm::StringMap<std::string> ModuleNameToSourceCache;
459+
};
460+
383461
} // namespace
384462

385463
class ModulesBuilder::ModulesBuilderImpl {
386464
public:
387-
ModulesBuilderImpl(const GlobalCompilationDatabase &CDB) : Cache(CDB) {}
465+
ModulesBuilderImpl(const GlobalCompilationDatabase &CDB)
466+
: CachedProjectModules(CDB), Cache(CDB) {}
467+
468+
CachingProjectModules &getCachedProjectModules() {
469+
return CachedProjectModules;
470+
}
388471

389472
const GlobalCompilationDatabase &getCDB() const { return Cache.getCDB(); }
390473

391474
llvm::Error
392-
getOrBuildModuleFile(StringRef ModuleName, const ThreadsafeFS &TFS,
393-
ProjectModules &MDB,
475+
getOrBuildModuleFile(PathRef RequiredSource, StringRef ModuleName,
476+
const ThreadsafeFS &TFS, ProjectModules &MDB,
394477
ReusablePrerequisiteModules &BuiltModuleFiles);
395478

396479
private:
480+
CachingProjectModules CachedProjectModules;
397481
ModuleFileCache Cache;
398482
};
399483

400484
llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile(
401-
StringRef ModuleName, const ThreadsafeFS &TFS, ProjectModules &MDB,
402-
ReusablePrerequisiteModules &BuiltModuleFiles) {
485+
PathRef RequiredSource, StringRef ModuleName, const ThreadsafeFS &TFS,
486+
ProjectModules &MDB, ReusablePrerequisiteModules &BuiltModuleFiles) {
403487
if (BuiltModuleFiles.isModuleUnitBuilt(ModuleName))
404488
return llvm::Error::success();
405489

406-
PathRef ModuleUnitFileName = MDB.getSourceForModuleName(ModuleName);
490+
std::string ModuleUnitFileName =
491+
MDB.getSourceForModuleName(ModuleName, RequiredSource);
407492
/// It is possible that we're meeting third party modules (modules whose
408493
/// source are not in the project. e.g, the std module may be a third-party
409494
/// module for most project) or something wrong with the implementation of
@@ -416,7 +501,7 @@ llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile(
416501
llvm::formatv("Don't get the module unit for module {0}", ModuleName));
417502

418503
// Get Required modules in topological order.
419-
auto ReqModuleNames = getAllRequiredModules(MDB, ModuleName);
504+
auto ReqModuleNames = getAllRequiredModules(RequiredSource, MDB, ModuleName);
420505
for (llvm::StringRef ReqModuleName : ReqModuleNames) {
421506
if (BuiltModuleFiles.isModuleUnitBuilt(ModuleName))
422507
continue;
@@ -449,21 +534,17 @@ llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile(
449534
std::unique_ptr<PrerequisiteModules>
450535
ModulesBuilder::buildPrerequisiteModulesFor(PathRef File,
451536
const ThreadsafeFS &TFS) {
452-
std::unique_ptr<ProjectModules> MDB = Impl->getCDB().getProjectModules(File);
453-
if (!MDB) {
454-
elog("Failed to get Project Modules information for {0}", File);
455-
return std::make_unique<FailedPrerequisiteModules>();
456-
}
537+
ProjectModules &MDB = Impl->getCachedProjectModules();
457538

458-
std::vector<std::string> RequiredModuleNames = MDB->getRequiredModules(File);
539+
std::vector<std::string> RequiredModuleNames = MDB.getRequiredModules(File);
459540
if (RequiredModuleNames.empty())
460541
return std::make_unique<ReusablePrerequisiteModules>();
461542

462543
auto RequiredModules = std::make_unique<ReusablePrerequisiteModules>();
463544
for (llvm::StringRef RequiredModuleName : RequiredModuleNames) {
464545
// Return early if there is any error.
465546
if (llvm::Error Err = Impl->getOrBuildModuleFile(
466-
RequiredModuleName, TFS, *MDB.get(), *RequiredModules.get())) {
547+
File, RequiredModuleName, TFS, MDB, *RequiredModules.get())) {
467548
elog("Failed to build module {0}; due to {1}", RequiredModuleName,
468549
toString(std::move(Err)));
469550
return std::make_unique<FailedPrerequisiteModules>();

clang-tools-extra/clangd/ProjectModules.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ class ProjectModules {
4242
llvm::unique_function<void(tooling::CompileCommand &, PathRef) const>;
4343

4444
virtual std::vector<std::string> getRequiredModules(PathRef File) = 0;
45-
virtual PathRef
46-
getSourceForModuleName(llvm::StringRef ModuleName,
47-
PathRef RequiredSrcFile = PathRef()) = 0;
45+
virtual std::string getModuleNameForSource(PathRef File) = 0;
46+
virtual std::string getSourceForModuleName(llvm::StringRef ModuleName,
47+
PathRef RequiredSrcFile) = 0;
4848

4949
virtual void setCommandMangler(CommandMangler Mangler) {}
5050

clang-tools-extra/clangd/ScanningProjectModules.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,18 @@ class ScanningAllProjectModules : public ProjectModules {
189189

190190
/// RequiredSourceFile is not used intentionally. See the comments of
191191
/// ModuleDependencyScanner for detail.
192-
PathRef
193-
getSourceForModuleName(llvm::StringRef ModuleName,
194-
PathRef RequiredSourceFile = PathRef()) override {
192+
std::string getSourceForModuleName(llvm::StringRef ModuleName,
193+
PathRef RequiredSourceFile) override {
195194
Scanner.globalScan(Mangler);
196-
return Scanner.getSourceForModuleName(ModuleName);
195+
return Scanner.getSourceForModuleName(ModuleName).str();
196+
}
197+
198+
std::string getModuleNameForSource(PathRef File) override {
199+
auto ScanningResult = Scanner.scan(File, Mangler);
200+
if (!ScanningResult || !ScanningResult->ModuleName)
201+
return {};
202+
203+
return *ScanningResult->ModuleName;
197204
}
198205

199206
private:

0 commit comments

Comments
 (0)