Skip to content

Commit 5edb6e9

Browse files
committed
[Dependency Scanning] Add ability for -scan-dependencies action to serialize and deserialize dependency scanner cache from a .moddepcache file.
Using the serialization format added in swiftlang#37585. - Add load/save code for the `-scan-dependencies` code-path. - Add `libSwiftDriver` entry-points to load/store the cache of a given scanner instance.
1 parent bf77137 commit 5edb6e9

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
@@ -306,6 +306,9 @@ class FrontendOptions {
306306
/// The path at which to either serialize or deserialize the dependency scanner cache.
307307
std::string SerializedDependencyScannerCachePath;
308308

309+
/// Emit remarks indicating use of the serialized module dependency scanning cache
310+
bool EmitDependencyScannerCacheRemarks = false;
311+
309312
/// After performing a dependency scanning action, serialize and deserialize the
310313
/// dependency cache before producing the result.
311314
bool TestDependencyScannerCacheSerialization = false;

include/swift/Option/FrontendOptions.td

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

200+
def dependency_scan_cache_remarks : Flag<["-"], "Rdependency-scan-cache">,
201+
HelpText<"Emit remarks indicating use of the serialized module dependency scanning cache.">;
202+
200203
def enable_copy_propagation : Flag<["-"], "enable-copy-propagation">,
201204
HelpText<"Run SIL copy propagation to shorten object lifetime.">;
202205
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;
@@ -1105,17 +1114,30 @@ identifyMainModuleDependencies(CompilerInstance &instance) {
11051114

11061115
} // namespace
11071116

1108-
static void serializeDependencyCache(DiagnosticEngine &diags,
1109-
const std::string &path,
1117+
static void serializeDependencyCache(CompilerInstance &instance,
11101118
const ModuleDependenciesCache &cache) {
1119+
const FrontendOptions &opts = instance.getInvocation().getFrontendOptions();
1120+
ASTContext &Context = instance.getASTContext();
1121+
auto savePath = opts.SerializedDependencyScannerCachePath;
11111122
module_dependency_cache_serialization::writeInterModuleDependenciesCache(
1112-
diags, path, cache);
1123+
Context.Diags, savePath, cache);
1124+
if (opts.EmitDependencyScannerCacheRemarks) {
1125+
Context.Diags.diagnose(SourceLoc(), diag::remark_save_cache, savePath);
1126+
}
11131127
}
11141128

1115-
static void deserializeDependencyCache(const std::string &path,
1129+
static void deserializeDependencyCache(CompilerInstance &instance,
11161130
ModuleDependenciesCache &cache) {
1117-
module_dependency_cache_serialization::readInterModuleDependenciesCache(
1118-
path, cache);
1131+
const FrontendOptions &opts = instance.getInvocation().getFrontendOptions();
1132+
ASTContext &Context = instance.getASTContext();
1133+
auto loadPath = opts.SerializedDependencyScannerCachePath;
1134+
if (module_dependency_cache_serialization::readInterModuleDependenciesCache(
1135+
loadPath, cache)) {
1136+
Context.Diags.diagnose(SourceLoc(), diag::warn_scaner_deserialize_failed,
1137+
loadPath);
1138+
} else if (opts.EmitDependencyScannerCacheRemarks) {
1139+
Context.Diags.diagnose(SourceLoc(), diag::remark_reuse_cache, loadPath);
1140+
}
11191141
}
11201142

11211143
bool swift::dependencies::scanDependencies(CompilerInstance &instance) {
@@ -1124,22 +1146,32 @@ bool swift::dependencies::scanDependencies(CompilerInstance &instance) {
11241146
std::string path = opts.InputsAndOutputs.getSingleOutputFilename();
11251147
std::error_code EC;
11261148
llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None);
1127-
1128-
// `-scan-dependencies` invocations use a single new instance
1129-
// of a module cache
1130-
ModuleDependenciesCache cache;
11311149
if (out.has_error() || EC) {
11321150
Context.Diags.diagnose(SourceLoc(), diag::error_opening_output, path,
11331151
EC.message());
11341152
out.clear_error();
11351153
return true;
11361154
}
11371155

1138-
// Execute scan, and write JSON output to the output stream
1156+
// `-scan-dependencies` invocations use a single new instance
1157+
// of a module cache
1158+
ModuleDependenciesCache cache;
1159+
1160+
if (opts.ReuseDependencyScannerCache)
1161+
deserializeDependencyCache(instance, cache);
1162+
1163+
// Execute scan
11391164
auto dependenciesOrErr = performModuleScan(instance, cache);
1165+
1166+
// Serialize the dependency cache if -serialize-dependency-scan-cache
1167+
// is specified
1168+
if (opts.SerializeDependencyScannerCache)
1169+
serializeDependencyCache(instance, cache);
1170+
11401171
if (dependenciesOrErr.getError())
11411172
return true;
11421173
auto dependencies = std::move(*dependenciesOrErr);
1174+
11431175
// Write out the JSON description.
11441176
writeJSON(out, dependencies);
11451177
// This process succeeds regardless of whether any errors occurred.
@@ -1258,7 +1290,19 @@ swift::dependencies::performModuleScan(CompilerInstance &instance,
12581290
std::set<ModuleDependencyID>> allModules;
12591291

12601292
allModules.insert({mainModuleName.str(), mainDependencies.getKind()});
1261-
cache.recordDependencies(mainModuleName, std::move(mainDependencies));
1293+
1294+
// We may be re-using an instance of the cache which already contains
1295+
// an entry for this module.
1296+
if (cache.findDependencies(mainModuleName,
1297+
ModuleDependenciesKind::SwiftTextual)) {
1298+
cache.updateDependencies(
1299+
std::make_pair(mainModuleName.str(),
1300+
ModuleDependenciesKind::SwiftTextual),
1301+
std::move(mainDependencies));
1302+
} else {
1303+
cache.recordDependencies(mainModuleName, std::move(mainDependencies));
1304+
}
1305+
12621306
auto &ctx = instance.getASTContext();
12631307
auto ModuleCachePath = getModuleCachePathFromClang(
12641308
ctx.getClangModuleLoader()->getClangInstance());
@@ -1299,15 +1343,17 @@ swift::dependencies::performModuleScan(CompilerInstance &instance,
12991343
ModuleDependenciesCache loadedCache;
13001344
if (FEOpts.TestDependencyScannerCacheSerialization) {
13011345
llvm::SmallString<128> buffer;
1302-
auto EC = llvm::sys::fs::createTemporaryFile("depscan_cache", "moddepcache", buffer);
1346+
auto EC = llvm::sys::fs::createTemporaryFile("depscan_cache", "moddepcache",
1347+
buffer);
13031348
if (EC) {
1304-
instance.getDiags().diagnose(SourceLoc(),
1305-
diag::error_unable_to_make_temporary_file,
1306-
EC.message());
1349+
instance.getDiags().diagnose(
1350+
SourceLoc(), diag::error_unable_to_make_temporary_file, EC.message());
13071351
} else {
13081352
std::string path = buffer.str().str();
1309-
serializeDependencyCache(instance.getDiags(), path, cache);
1310-
deserializeDependencyCache(path, loadedCache);
1353+
module_dependency_cache_serialization::writeInterModuleDependenciesCache(
1354+
instance.getDiags(), path, cache);
1355+
module_dependency_cache_serialization::readInterModuleDependenciesCache(
1356+
path, loadedCache);
13111357
resultCache = &loadedCache;
13121358
}
13131359
}

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

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

106106
Opts.SerializeDependencyScannerCache |= Args.hasArg(OPT_serialize_dependency_scan_cache);
107107
Opts.ReuseDependencyScannerCache |= Args.hasArg(OPT_reuse_dependency_scan_cache);
108+
Opts.EmitDependencyScannerCacheRemarks |= Args.hasArg(OPT_dependency_scan_cache_remarks);
108109
Opts.TestDependencyScannerCacheSerialization |= Args.hasArg(OPT_debug_test_dependency_scan_cache_serialization);
109110
if (const Arg *A = Args.getLastArg(OPT_dependency_scan_cache_path)) {
110111
Opts.SerializedDependencyScannerCachePath = A->getValue();

0 commit comments

Comments
 (0)