Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions include/swift/AST/ModuleDependencies.h
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,9 @@ class ModuleDependenciesCache {
private:
/// Discovered dependencies
ModuleDependenciesKindMap ModuleDependenciesMap;
/// A set of module identifiers for which a scanning action failed
/// to discover a Swift module dependency
llvm::StringSet<> negativeSwiftDependencyCache;
/// Set containing all of the Clang modules that have already been seen.
llvm::DenseSet<clang::tooling::dependencies::ModuleID> alreadySeenClangModules;
/// Name of the module under scan
Expand Down Expand Up @@ -1111,6 +1114,10 @@ class ModuleDependenciesCache {
bool hasDependency(StringRef moduleName) const;
/// Whether we have cached dependency information for the given Swift module.
bool hasSwiftDependency(StringRef moduleName) const;
/// Whether we have previously failed a lookup of a Swift dependency for the
/// given identifier.
bool hasNegativeSwiftDependency(StringRef moduleName) const;

/// Report the number of recorded Clang dependencies
int numberOfClangDependencies() const;
/// Report the number of recorded Swift dependencies
Expand Down Expand Up @@ -1232,6 +1239,8 @@ class ModuleDependenciesCache {
void
addVisibleClangModules(ModuleDependencyID moduleID,
const std::vector<std::string> &moduleNames);
/// Add an identifier to the set of failed Swift module queries
void recordFailedSwiftDependencyLookup(StringRef moduleIdentifier);

StringRef getMainModuleName() const { return mainScanModuleName; }

Expand Down
10 changes: 9 additions & 1 deletion lib/AST/ModuleDependencies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,14 +760,17 @@ bool ModuleDependenciesCache::hasSwiftDependency(StringRef moduleName) const {
return findSwiftDependency(moduleName).has_value();
}

bool ModuleDependenciesCache::hasNegativeSwiftDependency(StringRef moduleName) const {
return negativeSwiftDependencyCache.contains(moduleName);
}

int ModuleDependenciesCache::numberOfClangDependencies() const {
return ModuleDependenciesMap.at(ModuleDependencyKind::Clang).size();
}
int ModuleDependenciesCache::numberOfSwiftDependencies() const {
return ModuleDependenciesMap.at(ModuleDependencyKind::SwiftInterface).size() +
ModuleDependenciesMap.at(ModuleDependencyKind::SwiftBinary).size();
}

void ModuleDependenciesCache::recordDependency(
StringRef moduleName, ModuleDependencyInfo dependency) {
auto dependenciesKind = dependency.getKind();
Expand Down Expand Up @@ -946,6 +949,11 @@ void ModuleDependenciesCache::addVisibleClangModules(
updateDependency(moduleID, updatedDependencyInfo);
}

void ModuleDependenciesCache::recordFailedSwiftDependencyLookup(
StringRef moduleIdentifier) {
negativeSwiftDependencyCache.insert(moduleIdentifier);
}

llvm::StringSet<> &ModuleDependenciesCache::getVisibleClangModules(
ModuleDependencyID moduleID) const {
ASSERT(moduleID.Kind == ModuleDependencyKind::SwiftSource ||
Expand Down
20 changes: 15 additions & 5 deletions lib/DependencyScan/ModuleDependencyScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "swift/Basic/Defer.h"
#include "swift/Basic/FileTypes.h"
#include "swift/Basic/PrettyStackTrace.h"
#include "swift/Basic/Statistic.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/Frontend/CompileJobCacheKey.h"
#include "swift/Frontend/ModuleInterfaceLoader.h"
Expand Down Expand Up @@ -1389,6 +1390,13 @@ void ModuleDependencyScanner::resolveSwiftImportsForModule(
// Avoid querying the underlying Clang module here
if (moduleID.ModuleName == dependsOn.importIdentifier)
continue;
// Avoid querying Swift module dependencies previously discovered
if (DependencyCache.hasSwiftDependency(dependsOn.importIdentifier))
continue;
// Avoid querying Swift module dependencies which have already produced
// in a negative (not found) result
if (DependencyCache.hasNegativeSwiftDependency(dependsOn.importIdentifier))
continue;
ScanningThreadPool.async(
scanForSwiftModuleDependency,
getModuleImportIdentifier(dependsOn.importIdentifier),
Expand Down Expand Up @@ -1428,10 +1436,13 @@ void ModuleDependencyScanner::resolveSwiftImportsForModule(
moduleImport.importIdentifier))
importedSwiftDependencies.insert(
{moduleImport.importIdentifier, cachedInfo.value()->getKind()});
else
else {
ScanDiagnosticReporter.diagnoseFailureOnOnlyIncompatibleCandidates(
moduleImport, lookupResult.incompatibleCandidates,
DependencyCache, std::nullopt);
DependencyCache
.recordFailedSwiftDependencyLookup(moduleImport.importIdentifier);
}
};

for (const auto &importInfo : moduleDependencyInfo.getModuleImports())
Expand Down Expand Up @@ -1575,10 +1586,9 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependenciesForModule(
auto moduleName = moduleIdentifier.str();
{
std::lock_guard<std::mutex> guard(lookupResultLock);
if (DependencyCache.hasDependency(moduleName,
ModuleDependencyKind::SwiftInterface) ||
DependencyCache.hasDependency(moduleName,
ModuleDependencyKind::SwiftBinary))
if (DependencyCache.hasDependency(moduleName, ModuleDependencyKind::SwiftInterface) ||
DependencyCache.hasDependency(moduleName, ModuleDependencyKind::SwiftBinary) ||
DependencyCache.hasNegativeSwiftDependency(moduleName))
return;
}

Expand Down
2 changes: 1 addition & 1 deletion test/ScanDependencies/basic_query_metrics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// RUN: cat %t/remarks.txt | %FileCheck %s

// Ensure that despite being a common dependency to multiple Swift modules, only 1 query is performed to find 'C'
// CHECK: remark: Number of Swift module queries: '6'
// CHECK: remark: Number of Swift module queries: '3'
// CHECK: remark: Number of named Clang module queries: '1'
// CHEKC: remark: Number of recorded Clang module dependencies queried by-name from a Swift client: '1'
// CHECK: remark: Number of recorded Swift module dependencies: '2'
Expand Down
2 changes: 2 additions & 0 deletions test/ScanDependencies/module_deps_cache_reuse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import SubE
// CHECK-REMARK-SAVE: remark: Incremental module scan: Serializing module scanning dependency cache to:

// CHECK-REMARK-LOAD: remark: Incremental module scan: Re-using serialized module scanning dependency cache from:
// 'SwiftShims', 'C' and 'B' are Clang modules which are directly imorted from Swift code in this test, without a corresponding Swift overlay module. Because we do not serialize negative Swift dependency lookup results, resolving a dependency on these modules involves a query for whether a Swift module under this name can be found. This query fails and the subsequent query for this identifier as a Clang dependency is then able to re-use the loaded serialized cache.
// CHECK-REMARK-LOAD: remark: Number of Swift module queries: '3'
// FIXME: Today, we do not serialize dependencies of the main source module which results in a lookup for 'C' even though
// it is fully redundant.
// CHECK-REMARK-LOAD: remark: Number of named Clang module queries: '1'
Expand Down