Skip to content

Commit acb4e84

Browse files
committed
[Dependency Scanning] Add functionality to validate contents of a loaded scanner cache state
Checking each module dependency info if it is up-to-date with respect to when the cache contents were serialized in a prior scan. - Add a timestamp field to the serialization format for the dependency scanner cache - Add a flag "-validate-prior-dependency-scan-cache" which, when combined with "-load-dependency-scan-cache" will have the scanner prune dependencies from the deserialized cache which have inputs that are newer than the prior scan itself With the above in-place, the scan otherwise proceeds as-is, getting cache hits for entries still valid since the prior scan.
1 parent 0ba17c5 commit acb4e84

16 files changed

+408
-51
lines changed

include/swift/AST/DiagnosticsCommon.def

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,17 +212,28 @@ ERROR(scanner_arguments_invalid, none,
212212
ERROR(error_scanner_extra, none,
213213
"failed inside dependency scanner: '%0'", (StringRef))
214214

215-
WARNING(warn_scanner_deserialize_failed, none,
216-
"Failed to load module scanning dependency cache from: '%0', re-building scanner cache from scratch.", (StringRef))
215+
REMARK(warn_scanner_deserialize_failed, none,
216+
"Incremental module scan: Failed to load module scanning dependency cache from: '%0', re-building scanner cache from scratch.", (StringRef))
217217

218218
REMARK(remark_reuse_cache, none,
219-
"Re-using serialized module scanning dependency cache from: '%0'.", (StringRef))
219+
"Incremental module scan: Re-using serialized module scanning dependency cache from: '%0'.", (StringRef))
220220

221221
REMARK(remark_scanner_uncached_lookups, none,
222222
"Module Dependency Scanner queries executed: '%0'.", (unsigned))
223223

224224
REMARK(remark_save_cache, none,
225-
"Serializing module scanning dependency cache to: '%0'.", (StringRef))
225+
"Incremental module scan: Serializing module scanning dependency cache to: '%0'.", (StringRef))
226+
227+
REMARK(remark_scanner_stale_result_invalidate, none,
228+
"Incremental module scan: Dependency info for module '%0' invalidated due to a modified input"
229+
" since last scan: '%1'.", (StringRef, StringRef))
230+
231+
REMARK(remark_scanner_invalidate_upstream, none,
232+
"Incremental module scan: Dependency info for module '%0' invalidated due to an out-of-date"
233+
" dependency.", (StringRef))
234+
235+
REMARK(remark_cache_reuse_disabled_with_cas, none,
236+
"Incremental module scan: Re-using serialized module scanning dependency cache disabled in Caching build", ())
226237

227238
//------------------------------------------------------------------------------
228239
// MARK: custom attribute diagnostics

include/swift/AST/ModuleDependencies.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,9 @@ class ModuleDependenciesCache {
11291129
std::string scannerContextHash;
11301130
/// The location of where the built modules will be output to
11311131
std::string moduleOutputPath;
1132+
/// The timestamp of the beginning of the scanning query action
1133+
/// using this cache
1134+
const llvm::sys::TimePoint<> scanInitializationTime;
11321135

11331136
/// Retrieve the dependencies map that corresponds to the given dependency
11341137
/// kind.
@@ -1235,6 +1238,9 @@ class ModuleDependenciesCache {
12351238
/// Update stored dependencies for the given module.
12361239
void updateDependency(ModuleDependencyID moduleID,
12371240
ModuleDependencyInfo dependencyInfo);
1241+
1242+
/// Remove a given dependency info from the cache.
1243+
void removeDependency(ModuleDependencyID moduleID);
12381244

12391245
/// Resolve this module's set of directly-imported Swift module
12401246
/// dependencies

include/swift/Basic/Statistics.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ FRONTEND_STATISTIC(AST, ModuleVisibilityCacheMiss)
165165
FRONTEND_STATISTIC(AST, ModuleShadowCacheHit)
166166
FRONTEND_STATISTIC(AST, ModuleShadowCacheMiss)
167167

168+
/// Number of types deserialized.
169+
FRONTEND_STATISTIC(AST, NumDepScanFilesystemLookups)
170+
168171
/// Number of full function bodies parsed.
169172
FRONTEND_STATISTIC(Parse, NumFunctionsParsed)
170173

include/swift/DependencyScan/ScanDependencies.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ namespace swift {
2727
class CompilerInvocation;
2828
class CompilerInstance;
2929
class ModuleDependenciesCache;
30+
struct ModuleDependencyID;
31+
struct ModuleDependencyIDHash;
32+
using ModuleDependencyIDSet =
33+
std::unordered_set<ModuleDependencyID, ModuleDependencyIDHash>;
3034
class SwiftDependencyScanningService;
3135

3236
namespace dependencies {
@@ -58,6 +62,35 @@ performModulePrescan(CompilerInstance &instance,
5862
DependencyScanDiagnosticCollector *diagnostics,
5963
ModuleDependenciesCache &cache);
6064

65+
namespace incremental {
66+
/// For the given module dependency graph captured in the 'cache',
67+
/// validate whether each dependency node is up-to-date w.r.t. serialization
68+
/// time-stamp. i.e. if any of the input files of a module dependency are newer
69+
/// than the serialized dependency graph, it is considered invalidated and must
70+
/// be re-scanned.
71+
void validateInterModuleDependenciesCache(
72+
const ModuleDependencyID &rootModuleID, ModuleDependenciesCache &cache,
73+
const llvm::sys::TimePoint<> &cacheTimeStamp, llvm::vfs::FileSystem &fs,
74+
DiagnosticEngine &diags, bool emitRemarks = false);
75+
76+
/// Perform a postorder DFS to locate modules whose build recipe is out-of-date
77+
/// with respect to their inputs. Upon encountering such a module, add it to the
78+
/// set of invalidated modules, along with the path from the root to this
79+
/// module.
80+
void outOfDateModuleScan(const ModuleDependencyID &sourceModuleID,
81+
const ModuleDependenciesCache &cache,
82+
const llvm::sys::TimePoint<> &cacheTimeStamp,
83+
llvm::vfs::FileSystem &fs, DiagnosticEngine &diags,
84+
bool emitRemarks, ModuleDependencyIDSet &visited,
85+
ModuleDependencyIDSet &modulesRequiringRescan);
86+
87+
/// Validate whether all inputs of a given module dependency
88+
/// are older than the cache serialization time.
89+
bool verifyModuleDependencyUpToDate(
90+
const ModuleDependencyID &moduleID, const ModuleDependenciesCache &cache,
91+
const llvm::sys::TimePoint<> &cacheTimeStamp, llvm::vfs::FileSystem &fs,
92+
DiagnosticEngine &diags, bool emitRemarks);
93+
} // end namespace incremental
6194
} // end namespace dependencies
6295
} // end namespace swift
6396

include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ namespace graph_block {
9595
enum {
9696
METADATA = 1,
9797
MODULE_NODE,
98+
TIME_NODE,
9899
LINK_LIBRARY_NODE,
99100
LINK_LIBRARY_ARRAY_NODE,
100101
MACRO_DEPENDENCY_NODE,
@@ -113,13 +114,19 @@ enum {
113114

114115
// Always the first record in the file.
115116
using MetadataLayout = BCRecordLayout<
116-
METADATA, // ID
117-
BCFixed<16>, // Inter-Module Dependency graph format major version
118-
BCFixed<16>, // Inter-Module Dependency graph format minor version
119-
BCBlob // Scanner Invocation Context Hash
117+
METADATA, // ID
118+
BCFixed<16>, // Inter-Module Dependency graph format major version
119+
BCFixed<16>, // Inter-Module Dependency graph format minor version
120+
BCBlob // Scanner Invocation Context Hash
120121
>;
121122

122-
// After the metadata record, we have zero or more identifier records,
123+
// After the metadata record, emit serialization time-stamp.
124+
using TimeLayout = BCRecordLayout<
125+
TIME_NODE, // ID
126+
BCBlob // Nanoseconds since epoch as a string
127+
>;
128+
129+
// After the time stamp record, we have zero or more identifier records,
123130
// for each unique string that is referenced in the graph.
124131
//
125132
// Identifiers are referenced by their sequence number, starting from 1.
@@ -138,29 +145,31 @@ using IdentifierNodeLayout = BCRecordLayout<IDENTIFIER_NODE, BCBlob>;
138145
using IdentifierArrayLayout =
139146
BCRecordLayout<IDENTIFIER_ARRAY_NODE, IdentifierIDArryField>;
140147

141-
// ACTODO: Comment
148+
// A record for a given link library node containing information
149+
// required for the build system client to capture a requirement
150+
// to link a given dependency library.
142151
using LinkLibraryLayout =
143152
BCRecordLayout<LINK_LIBRARY_NODE, // ID
144153
IdentifierIDField, // libraryName
145154
IsFrameworkField, // isFramework
146155
IsForceLoadField // forceLoad
147156
>;
148-
// ACTODO: Comment
149157
using LinkLibraryArrayLayout =
150158
BCRecordLayout<LINK_LIBRARY_ARRAY_NODE, IdentifierIDArryField>;
151159

152-
// ACTODO: Comment
160+
// A record for a Macro module dependency of a given dependency
161+
// node.
153162
using MacroDependencyLayout =
154163
BCRecordLayout<MACRO_DEPENDENCY_NODE, // ID
155164
IdentifierIDField, // macroModuleName
156165
IdentifierIDField, // libraryPath
157166
IdentifierIDField // executablePath
158167
>;
159-
// ACTODO: Comment
160168
using MacroDependencyArrayLayout =
161169
BCRecordLayout<MACRO_DEPENDENCY_ARRAY_NODE, IdentifierIDArryField>;
162170

163-
// ACTODO: Comment
171+
// A record capturing information about a given 'import' statement
172+
// captured in a dependency node, including its source location.
164173
using ImportStatementLayout =
165174
BCRecordLayout<IMPORT_STATEMENT_NODE, // ID
166175
IdentifierIDField, // importIdentifier
@@ -169,7 +178,6 @@ using ImportStatementLayout =
169178
ColumnNumberField, // columnNumber
170179
IsOptionalImport // isOptional
171180
>;
172-
// ACTODO: Comment
173181
using ImportStatementArrayLayout =
174182
BCRecordLayout<IMPORT_STATEMENT_ARRAY_NODE, IdentifierIDArryField>;
175183
using OptionalImportStatementArrayLayout =
@@ -268,12 +276,14 @@ using ClangModuleDetailsLayout =
268276
/// Tries to read the dependency graph from the given buffer.
269277
/// Returns \c true if there was an error.
270278
bool readInterModuleDependenciesCache(llvm::MemoryBuffer &buffer,
271-
ModuleDependenciesCache &cache);
279+
ModuleDependenciesCache &cache,
280+
llvm::sys::TimePoint<> &serializedCacheTimeStamp);
272281

273282
/// Tries to read the dependency graph from the given path name.
274283
/// Returns true if there was an error.
275284
bool readInterModuleDependenciesCache(llvm::StringRef path,
276-
ModuleDependenciesCache &cache);
285+
ModuleDependenciesCache &cache,
286+
llvm::sys::TimePoint<> &serializedCacheTimeStamp);
277287

278288
/// Tries to write the dependency graph to the given path name.
279289
/// Returns true if there was an error.

include/swift/Frontend/FrontendOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,11 @@ class FrontendOptions {
363363
/// Load and re-use a prior serialized dependency scanner cache.
364364
bool ReuseDependencyScannerCache = false;
365365

366+
/// Upon loading a prior serialized dependency scanner cache, filter out
367+
/// dependency module information which is no longer up-to-date with respect
368+
/// to input files of every given module.
369+
bool ValidatePriorDependencyScannerCache = false;
370+
366371
/// The path at which to either serialize or deserialize the dependency scanner cache.
367372
std::string SerializedDependencyScannerCachePath;
368373

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,10 @@ def serialize_dependency_scan_cache : Flag<["-"], "serialize-dependency-scan-cac
266266
HelpText<"After performing a dependency scan, serialize the scanner's internal state.">;
267267

268268
def reuse_dependency_scan_cache : Flag<["-"], "load-dependency-scan-cache">,
269-
HelpText<"After performing a dependency scan, serialize the scanner's internal state.">;
269+
HelpText<"For performing a dependency scan, deserialize the scanner's internal state from a prior scan.">;
270+
271+
def validate_prior_dependency_scan_cache : Flag<["-"], "validate-prior-dependency-scan-cache">,
272+
HelpText<"For performing a dependency scan with a prior scanner state, validate module dependencies.">;
270273

271274
def dependency_scan_cache_path : Separate<["-"], "dependency-scan-cache-path">,
272275
HelpText<"The path to output the dependency scanner's internal state.">;

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,6 +1979,11 @@ def driver_explicit_module_build:
19791979
Flags<[HelpHidden, NewDriverOnlyOption]>,
19801980
HelpText<"Prebuild module dependencies to make them explicit">;
19811981

1982+
def incremental_dependency_scan:
1983+
Flag<["-"], "incremental-dependency-scan">,
1984+
Flags<[HelpHidden, NewDriverOnlyOption]>,
1985+
HelpText<"Re-use/validate prior build dependency scan artifacts">;
1986+
19821987
def driver_experimental_explicit_module_build:
19831988
Flag<["-"], "experimental-explicit-module-build">,
19841989
Flags<[HelpHidden, NewDriverOnlyOption]>,

lib/AST/ModuleDependencies.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,8 @@ ModuleDependenciesCache::ModuleDependenciesCache(
728728
: globalScanningService(globalScanningService),
729729
mainScanModuleName(mainScanModuleName),
730730
scannerContextHash(scannerContextHash),
731-
moduleOutputPath(moduleOutputPath) {
731+
moduleOutputPath(moduleOutputPath),
732+
scanInitializationTime(std::chrono::system_clock::now()) {
732733
for (auto kind = ModuleDependencyKind::FirstKind;
733734
kind != ModuleDependencyKind::LastKind; ++kind)
734735
ModuleDependenciesMap.insert({kind, ModuleNameToDependencyMap()});
@@ -807,6 +808,7 @@ ModuleDependenciesCache::findSwiftDependency(StringRef moduleName) const {
807808

808809
const ModuleDependencyInfo &ModuleDependenciesCache::findKnownDependency(
809810
const ModuleDependencyID &moduleID) const {
811+
810812
auto dep = findDependency(moduleID);
811813
assert(dep && "dependency unknown");
812814
return **dep;
@@ -860,6 +862,11 @@ void ModuleDependenciesCache::updateDependency(
860862
map.insert_or_assign(moduleID.ModuleName, std::move(dependencyInfo));
861863
}
862864

865+
void ModuleDependenciesCache::removeDependency(ModuleDependencyID moduleID) {
866+
auto &map = getDependenciesMap(moduleID.Kind);
867+
map.erase(moduleID.ModuleName);
868+
}
869+
863870
void
864871
ModuleDependenciesCache::setImportedSwiftDependencies(ModuleDependencyID moduleID,
865872
const ArrayRef<ModuleDependencyID> dependencyIDs) {

0 commit comments

Comments
 (0)