Skip to content

Commit 374e460

Browse files
authored
Merge pull request #37723 from artemcm/SaveReuseDependencyScannerCache
[Dependency Scanning] Add ability for `-scan-dependencies` action to serialize and deserialize dependency scanner cache from a `.moddepcache` file.
2 parents 330f040 + 7e2c8e9 commit 374e460

File tree

12 files changed

+360
-22
lines changed

12 files changed

+360
-22
lines changed

include/swift-c/DependencyScan/DependencyScan.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,30 @@ swiftscan_batch_scan_result_create(swiftscan_scanner_t scanner,
337337
SWIFTSCAN_PUBLIC swiftscan_import_set_t swiftscan_import_set_create(
338338
swiftscan_scanner_t scanner, swiftscan_scan_invocation_t invocation);
339339

340+
//=== Scanner Cache Operations --------------------------------------------===//
341+
// The following operations expose an implementation detail of the dependency
342+
// scanner: its module dependencies cache. This is done in order
343+
// to allow clients to perform incremental dependency scans by having the
344+
// scanner's state be serializable and re-usable.
345+
346+
/// For the specified \c scanner instance, serialize its state to the specified file-system \c path .
347+
SWIFTSCAN_PUBLIC void
348+
swiftscan_scanner_cache_serialize(swiftscan_scanner_t scanner,
349+
const char * path);
350+
351+
/// For the specified \c scanner instance, load in scanner state from a file at
352+
/// the specified file-system \c path .
353+
SWIFTSCAN_PUBLIC bool
354+
swiftscan_scanner_cache_load(swiftscan_scanner_t scanner,
355+
const char * path);
356+
357+
/// For the specified \c scanner instance, reset its internal state, ensuring subsequent
358+
/// scanning queries are done "from-scratch".
359+
SWIFTSCAN_PUBLIC void
360+
swiftscan_scanner_cache_reset(swiftscan_scanner_t scanner);
361+
362+
//===----------------------------------------------------------------------===//
363+
340364
SWIFTSCAN_END_DECLS
341365

342366
#endif // SWIFT_C_DEPENDENCY_SCAN_H

include/swift/AST/DiagnosticsCommon.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,15 @@ ERROR(scanner_find_cycle, none,
192192
ERROR(scanner_arguments_invalid, none,
193193
"dependencies scanner cannot be configured with arguments: '%0'", (StringRef))
194194

195+
WARNING(warn_scaner_deserialize_failed, none,
196+
"Failed to load module scanning dependency cache from: '%0', re-building scanner cache from scratch.", (StringRef))
197+
198+
REMARK(remark_reuse_cache, none,
199+
"Re-using serialized module scanning dependency cache from: '%0'.", (StringRef))
200+
201+
REMARK(remark_save_cache, none,
202+
"Serializing module scanning dependency cache to: '%0'.", (StringRef))
203+
195204
//------------------------------------------------------------------------------
196205
// MARK: custom attribute diagnostics
197206
//------------------------------------------------------------------------------

include/swift/DependencyScan/DependencyScanningTool.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ class DependencyScanningTool {
5757
const std::vector<BatchScanInput> &BatchInput,
5858
const llvm::StringSet<> &PlaceholderModules);
5959

60+
/// Writes the current `SharedCache` instance to a specified FileSystem path.
61+
void serializeCache(llvm::StringRef path);
62+
/// Loads an instance of a `ModuleDependenciesCache` to serve as the `SharedCache`
63+
/// from a specified FileSystem path.
64+
bool loadCache(llvm::StringRef path);
65+
/// Discard the tool's current `SharedCache` and start anew.
66+
void resetCache();
67+
6068
private:
6169
/// Using the specified invocation command, instantiate a CompilerInstance
6270
/// that will be used for this scan.

include/swift/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,9 @@ class FrontendOptions {
313313
/// The path at which to either serialize or deserialize the dependency scanner cache.
314314
std::string SerializedDependencyScannerCachePath;
315315

316+
/// Emit remarks indicating use of the serialized module dependency scanning cache
317+
bool EmitDependencyScannerCacheRemarks = false;
318+
316319
/// After performing a dependency scanning action, serialize and deserialize the
317320
/// dependency cache before producing the result.
318321
bool TestDependencyScannerCacheSerialization = false;

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ def reuse_dependency_scan_cache : Flag<["-"], "load-dependency-scan-cache">,
194194
def dependency_scan_cache_path : Separate<["-"], "dependency-scan-cache-path">,
195195
HelpText<"The path to output the dependency scanner's internal state.">;
196196

197+
def dependency_scan_cache_remarks : Flag<["-"], "Rdependency-scan-cache">,
198+
HelpText<"Emit remarks indicating use of the serialized module dependency scanning cache.">;
199+
197200
def enable_copy_propagation : Flag<["-"], "enable-copy-propagation">,
198201
HelpText<"Run SIL copy propagation to shorten object lifetime.">;
199202
def disable_copy_propagation : Flag<["-"], "disable-copy-propagation">,

lib/DependencyScan/DependencyScanningTool.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "swift/DependencyScan/DependencyScanningTool.h"
14+
#include "swift/DependencyScan/SerializedModuleDependencyCacheFormat.h"
1415
#include "swift/AST/DiagnosticEngine.h"
1516
#include "swift/AST/DiagnosticsFrontend.h"
1617
#include "swift/Basic/LLVMInitialize.h"
@@ -77,11 +78,37 @@ DependencyScanningTool::getDependencies(
7778
BatchInput.size(), std::make_error_code(std::errc::invalid_argument));
7879
auto Instance = std::move(*InstanceOrErr);
7980

80-
auto batchScanResults = performBatchModuleScan(
81+
auto BatchScanResults = performBatchModuleScan(
8182
*Instance.get(), *SharedCache, VersionedPCMInstanceCacheCache.get(),
8283
Saver, BatchInput);
8384

84-
return batchScanResults;
85+
return BatchScanResults;
86+
}
87+
88+
void DependencyScanningTool::serializeCache(llvm::StringRef path) {
89+
SourceManager SM;
90+
DiagnosticEngine Diags(SM);
91+
Diags.addConsumer(PDC);
92+
module_dependency_cache_serialization::writeInterModuleDependenciesCache(
93+
Diags, path, *SharedCache);
94+
}
95+
96+
bool DependencyScanningTool::loadCache(llvm::StringRef path) {
97+
SourceManager SM;
98+
DiagnosticEngine Diags(SM);
99+
Diags.addConsumer(PDC);
100+
SharedCache = std::make_unique<ModuleDependenciesCache>();
101+
bool Success =
102+
module_dependency_cache_serialization::readInterModuleDependenciesCache(
103+
path, *SharedCache);
104+
if (!Success) {
105+
Diags.diagnose(SourceLoc(), diag::warn_scaner_deserialize_failed, path);
106+
}
107+
return Success;
108+
}
109+
110+
void DependencyScanningTool::resetCache() {
111+
SharedCache.reset(new ModuleDependenciesCache());
85112
}
86113

87114
llvm::ErrorOr<std::unique_ptr<CompilerInstance>>

lib/DependencyScan/ModuleDependencyCacheSerialization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ bool swift::dependencies::module_dependency_cache_serialization::
472472
"loading inter-module dependency graph", path);
473473
auto buffer = llvm::MemoryBuffer::getFile(path);
474474
if (!buffer)
475-
return false;
475+
return true;
476476

477477
return readInterModuleDependenciesCache(*buffer.get(), cache);
478478
}

lib/DependencyScan/ScanDependencies.cpp

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,16 @@ static void discoverCrosssImportOverlayDependencies(
282282

283283
// Record the dummy main module's direct dependencies. The dummy main module
284284
// only directly depend on these newly discovered overlay modules.
285-
cache.recordDependencies(dummyMainName, dummyMainDependencies);
285+
if (cache.findDependencies(dummyMainName,
286+
ModuleDependenciesKind::SwiftTextual)) {
287+
cache.updateDependencies(
288+
std::make_pair(dummyMainName.str(),
289+
ModuleDependenciesKind::SwiftTextual),
290+
dummyMainDependencies);
291+
} else {
292+
cache.recordDependencies(dummyMainName, dummyMainDependencies);
293+
}
294+
286295
llvm::SetVector<ModuleDependencyID, std::vector<ModuleDependencyID>,
287296
std::set<ModuleDependencyID>>
288297
allModules;
@@ -1100,17 +1109,30 @@ identifyMainModuleDependencies(CompilerInstance &instance) {
11001109

11011110
} // namespace
11021111

1103-
static void serializeDependencyCache(DiagnosticEngine &diags,
1104-
const std::string &path,
1112+
static void serializeDependencyCache(CompilerInstance &instance,
11051113
const ModuleDependenciesCache &cache) {
1114+
const FrontendOptions &opts = instance.getInvocation().getFrontendOptions();
1115+
ASTContext &Context = instance.getASTContext();
1116+
auto savePath = opts.SerializedDependencyScannerCachePath;
11061117
module_dependency_cache_serialization::writeInterModuleDependenciesCache(
1107-
diags, path, cache);
1118+
Context.Diags, savePath, cache);
1119+
if (opts.EmitDependencyScannerCacheRemarks) {
1120+
Context.Diags.diagnose(SourceLoc(), diag::remark_save_cache, savePath);
1121+
}
11081122
}
11091123

1110-
static void deserializeDependencyCache(const std::string &path,
1124+
static void deserializeDependencyCache(CompilerInstance &instance,
11111125
ModuleDependenciesCache &cache) {
1112-
module_dependency_cache_serialization::readInterModuleDependenciesCache(
1113-
path, cache);
1126+
const FrontendOptions &opts = instance.getInvocation().getFrontendOptions();
1127+
ASTContext &Context = instance.getASTContext();
1128+
auto loadPath = opts.SerializedDependencyScannerCachePath;
1129+
if (module_dependency_cache_serialization::readInterModuleDependenciesCache(
1130+
loadPath, cache)) {
1131+
Context.Diags.diagnose(SourceLoc(), diag::warn_scaner_deserialize_failed,
1132+
loadPath);
1133+
} else if (opts.EmitDependencyScannerCacheRemarks) {
1134+
Context.Diags.diagnose(SourceLoc(), diag::remark_reuse_cache, loadPath);
1135+
}
11141136
}
11151137

11161138
bool swift::dependencies::scanDependencies(CompilerInstance &instance) {
@@ -1119,22 +1141,32 @@ bool swift::dependencies::scanDependencies(CompilerInstance &instance) {
11191141
std::string path = opts.InputsAndOutputs.getSingleOutputFilename();
11201142
std::error_code EC;
11211143
llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None);
1122-
1123-
// `-scan-dependencies` invocations use a single new instance
1124-
// of a module cache
1125-
ModuleDependenciesCache cache;
11261144
if (out.has_error() || EC) {
11271145
Context.Diags.diagnose(SourceLoc(), diag::error_opening_output, path,
11281146
EC.message());
11291147
out.clear_error();
11301148
return true;
11311149
}
11321150

1133-
// Execute scan, and write JSON output to the output stream
1151+
// `-scan-dependencies` invocations use a single new instance
1152+
// of a module cache
1153+
ModuleDependenciesCache cache;
1154+
1155+
if (opts.ReuseDependencyScannerCache)
1156+
deserializeDependencyCache(instance, cache);
1157+
1158+
// Execute scan
11341159
auto dependenciesOrErr = performModuleScan(instance, cache);
1160+
1161+
// Serialize the dependency cache if -serialize-dependency-scan-cache
1162+
// is specified
1163+
if (opts.SerializeDependencyScannerCache)
1164+
serializeDependencyCache(instance, cache);
1165+
11351166
if (dependenciesOrErr.getError())
11361167
return true;
11371168
auto dependencies = std::move(*dependenciesOrErr);
1169+
11381170
// Write out the JSON description.
11391171
writeJSON(out, dependencies);
11401172
// This process succeeds regardless of whether any errors occurred.
@@ -1253,7 +1285,19 @@ swift::dependencies::performModuleScan(CompilerInstance &instance,
12531285
std::set<ModuleDependencyID>> allModules;
12541286

12551287
allModules.insert({mainModuleName.str(), mainDependencies.getKind()});
1256-
cache.recordDependencies(mainModuleName, std::move(mainDependencies));
1288+
1289+
// We may be re-using an instance of the cache which already contains
1290+
// an entry for this module.
1291+
if (cache.findDependencies(mainModuleName,
1292+
ModuleDependenciesKind::SwiftTextual)) {
1293+
cache.updateDependencies(
1294+
std::make_pair(mainModuleName.str(),
1295+
ModuleDependenciesKind::SwiftTextual),
1296+
std::move(mainDependencies));
1297+
} else {
1298+
cache.recordDependencies(mainModuleName, std::move(mainDependencies));
1299+
}
1300+
12571301
auto &ctx = instance.getASTContext();
12581302
auto ModuleCachePath = getModuleCachePathFromClang(
12591303
ctx.getClangModuleLoader()->getClangInstance());
@@ -1295,15 +1339,17 @@ swift::dependencies::performModuleScan(CompilerInstance &instance,
12951339
ModuleDependenciesCache loadedCache;
12961340
if (FEOpts.TestDependencyScannerCacheSerialization) {
12971341
llvm::SmallString<128> buffer;
1298-
auto EC = llvm::sys::fs::createTemporaryFile("depscan_cache", "moddepcache", buffer);
1342+
auto EC = llvm::sys::fs::createTemporaryFile("depscan_cache", "moddepcache",
1343+
buffer);
12991344
if (EC) {
1300-
instance.getDiags().diagnose(SourceLoc(),
1301-
diag::error_unable_to_make_temporary_file,
1302-
EC.message());
1345+
instance.getDiags().diagnose(
1346+
SourceLoc(), diag::error_unable_to_make_temporary_file, EC.message());
13031347
} else {
13041348
std::string path = buffer.str().str();
1305-
serializeDependencyCache(instance.getDiags(), path, cache);
1306-
deserializeDependencyCache(path, loadedCache);
1349+
module_dependency_cache_serialization::writeInterModuleDependenciesCache(
1350+
instance.getDiags(), path, cache);
1351+
module_dependency_cache_serialization::readInterModuleDependenciesCache(
1352+
path, loadedCache);
13071353
resultCache = &loadedCache;
13081354
}
13091355
}

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ bool ArgsToFrontendOptionsConverter::convert(
119119

120120
Opts.SerializeDependencyScannerCache |= Args.hasArg(OPT_serialize_dependency_scan_cache);
121121
Opts.ReuseDependencyScannerCache |= Args.hasArg(OPT_reuse_dependency_scan_cache);
122+
Opts.EmitDependencyScannerCacheRemarks |= Args.hasArg(OPT_dependency_scan_cache_remarks);
122123
Opts.TestDependencyScannerCacheSerialization |= Args.hasArg(OPT_debug_test_dependency_scan_cache_serialization);
123124
if (const Arg *A = Args.getLastArg(OPT_dependency_scan_cache_path)) {
124125
Opts.SerializedDependencyScannerCachePath = A->getValue();

0 commit comments

Comments
 (0)