Skip to content

Commit 0314a31

Browse files
Mirror outputs into CAS using CASOutputBackend
When `-enable-cas` option is used, mirror the output into CAS so it can be fetched from CAS with the cache key in the future.
1 parent de84570 commit 0314a31

13 files changed

+448
-14
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,10 @@ ERROR(error_output_missing,none,
485485
REMARK(matching_output_produced,none,
486486
"produced matching output file '%0' for deterministic check: hash '%1'", (StringRef, StringRef))
487487

488+
// Caching related diagnostics
489+
ERROR(error_caching_no_cas_fs, none,
490+
"caching is enabled without -cas-fs option, input is not immutable", ())
491+
488492
// CAS related diagnostics
489493
ERROR(error_create_cas, none, "failed to create CAS '%0' (%1)", (StringRef, StringRef))
490494
ERROR(error_invalid_cas_id, none, "invalid CASID '%0' (%1)", (StringRef, StringRef))

include/swift/Frontend/CachingUtils.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===--- CachingUtils.h -----------------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_FRONTEND_CACHINGUTILS_H
14+
#define SWIFT_FRONTEND_CACHINGUTILS_H
15+
16+
#include "swift/Frontend/FrontendInputsAndOutputs.h"
17+
#include "llvm/ADT/IntrusiveRefCntPtr.h"
18+
#include "llvm/CAS/ActionCache.h"
19+
#include "llvm/CAS/ObjectStore.h"
20+
#include "llvm/CAS/CASReference.h"
21+
#include "llvm/Support/VirtualOutputBackend.h"
22+
#include <memory>
23+
24+
namespace swift {
25+
26+
/// Create a swift caching output backend that stores the output from
27+
/// compiler into a CAS.
28+
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend>
29+
createSwiftCachingOutputBackend(
30+
llvm::cas::ObjectStore &CAS, llvm::cas::ActionCache &Cache,
31+
llvm::cas::ObjectRef BaseKey,
32+
const FrontendInputsAndOutputs &InputsAndOutputs);
33+
34+
/// Load the cached compile result from cache.
35+
std::unique_ptr<llvm::MemoryBuffer> loadCachedCompileResultFromCacheKey(
36+
llvm::cas::ObjectStore &CAS, llvm::cas::ActionCache &Cache,
37+
DiagnosticEngine &Diag, llvm::StringRef CacheKey,
38+
llvm::StringRef Filename = "");
39+
40+
/// Store compiler output.
41+
llvm::Error storeCachedCompilerOutput(llvm::cas::ObjectStore &CAS,
42+
llvm::cas::ActionCache &Cache,
43+
StringRef Path, StringRef Bytes,
44+
llvm::cas::ObjectRef BaseKey,
45+
StringRef CorrespondingInput,
46+
file_types::ID OutputKind);
47+
48+
}
49+
50+
#endif

include/swift/Frontend/Frontend.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,9 @@ class CompilerInstance {
633633
/// i.e. if it can be found.
634634
bool canImportCxxShim() const;
635635

636+
/// Whether this compiler instance supports caching.
637+
bool supportCaching() const;
638+
636639
/// Gets the SourceFile which is the primary input for this CompilerInstance.
637640
/// \returns the primary SourceFile, or nullptr if there is no primary input;
638641
/// if there are _multiple_ primary inputs, fails with an assertion.

include/swift/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,9 @@ class FrontendOptions {
445445
/// \return true if the given action requires input files to be provided.
446446
static bool doesActionPerformEndOfPipelineActions(ActionType action);
447447

448+
/// \return true if the given action supports caching.
449+
static bool supportCompilationCaching(ActionType action);
450+
448451
/// Return a hash code of any components from these options that should
449452
/// contribute to a Swift Bridging PCH hash.
450453
llvm::hash_code getPCHHashComponents() const {

include/swift/Option/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,6 +1814,10 @@ def cas_path: Separate<["-"], "cas-path">,
18141814
Flags<[FrontendOption, NewDriverOnlyOption]>,
18151815
HelpText<"Path to CAS">, MetaVarName<"<path>">;
18161816

1817+
def allow_unstable_cache_key_for_testing: Flag<["-"], "allow-unstable-cache-key-for-testing">,
1818+
Flags<[FrontendOption, HelpHidden, NoDriverOption]>,
1819+
HelpText<"Allow compilation caching with unstable inputs for testing purpose">;
1820+
18171821
// END ONLY SUPPORTED IN NEW DRIVER
18181822

18191823
def enable_cas: Flag<["-"], "enable-cas">,

lib/DriverTool/swift_cache_tool_main.cpp

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/Basic/LLVM.h"
1919
#include "swift/Basic/LLVMInitialize.h"
2020
#include "swift/Basic/Version.h"
21+
#include "swift/Frontend/CachingUtils.h"
2122
#include "swift/Frontend/CompileJobCacheKey.h"
2223
#include "swift/Frontend/Frontend.h"
2324
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
@@ -28,6 +29,7 @@
2829
#include "llvm/Option/OptTable.h"
2930
#include "llvm/Support/Error.h"
3031
#include "llvm/Support/JSON.h"
32+
#include "llvm/Support/MemoryBuffer.h"
3133
#include <memory>
3234

3335
using namespace swift;
@@ -39,7 +41,15 @@ namespace {
3941
enum class SwiftCacheToolAction {
4042
Invalid,
4143
PrintBaseKey,
42-
PrintOutputKeys
44+
PrintOutputKeys,
45+
ValidateOutputs
46+
};
47+
48+
struct OutputEntry {
49+
std::string InputPath;
50+
std::string OutputPath;
51+
std::string OutputKind;
52+
std::string CacheKey;
4353
};
4454

4555
enum ID {
@@ -85,6 +95,7 @@ class SwiftCacheToolInvocation {
8595
PrintingDiagnosticConsumer PDC;
8696
std::string MainExecutablePath;
8797
std::string CASPath;
98+
std::vector<std::string> Inputs;
8899
std::vector<std::string> FrontendArgs;
89100
SwiftCacheToolAction ActionKind = SwiftCacheToolAction::Invalid;
90101

@@ -123,17 +134,19 @@ class SwiftCacheToolInvocation {
123134
CASPath =
124135
ParsedArgs.getLastArgValue(OPT_cas_path, getDefaultOnDiskCASPath());
125136

137+
Inputs = ParsedArgs.getAllArgValues(OPT_INPUT);
126138
FrontendArgs = ParsedArgs.getAllArgValues(OPT__DASH_DASH);
127139
if (auto *A = ParsedArgs.getLastArg(OPT_cache_tool_action))
128140
ActionKind =
129141
llvm::StringSwitch<SwiftCacheToolAction>(A->getValue())
130142
.Case("print-base-key", SwiftCacheToolAction::PrintBaseKey)
131143
.Case("print-output-keys", SwiftCacheToolAction::PrintOutputKeys)
144+
.Case("validate-outputs", SwiftCacheToolAction::ValidateOutputs)
132145
.Default(SwiftCacheToolAction::Invalid);
133146

134147
if (ActionKind == SwiftCacheToolAction::Invalid) {
135148
llvm::errs() << "Invalid option specified for -cache-tool-action: "
136-
<< "use print-base-key|print-output-keys\n";
149+
<< "use print-base-key|print-output-keys|validate-outputs\n";
137150
return 1;
138151
}
139152

@@ -146,6 +159,8 @@ class SwiftCacheToolInvocation {
146159
return printBaseKey();
147160
case SwiftCacheToolAction::PrintOutputKeys:
148161
return printOutputKeys();
162+
case SwiftCacheToolAction::ValidateOutputs:
163+
return validateOutputs();
149164
case SwiftCacheToolAction::Invalid:
150165
return 0; // No action. Probably just print help. Return.
151166
}
@@ -225,6 +240,7 @@ class SwiftCacheToolInvocation {
225240
}
226241

227242
int printOutputKeys();
243+
int validateOutputs();
228244
};
229245

230246
} // end anonymous namespace
@@ -238,12 +254,6 @@ int SwiftCacheToolInvocation::printOutputKeys() {
238254
if (!BaseKey)
239255
return 1;
240256

241-
struct OutputEntry {
242-
std::string InputPath;
243-
std::string OutputPath;
244-
std::string OutputKind;
245-
std::string CacheKey;
246-
};
247257
std::vector<OutputEntry> OutputKeys;
248258
bool hasError = false;
249259
auto addOutputKey = [&](StringRef InputPath, file_types::ID OutputKind,
@@ -299,6 +309,55 @@ int SwiftCacheToolInvocation::printOutputKeys() {
299309
return 0;
300310
}
301311

312+
int SwiftCacheToolInvocation::validateOutputs() {
313+
auto DB = llvm::cas::createOnDiskUnifiedCASDatabases(CASPath);
314+
if (!DB)
315+
report_fatal_error(DB.takeError());
316+
317+
PrintingDiagnosticConsumer PDC;
318+
Instance.getDiags().addConsumer(PDC);
319+
320+
auto validateCacheKeysFromFile = [&](const std::string &Path) {
321+
auto JSONContent = llvm::MemoryBuffer::getFile(Path);
322+
if (!JSONContent) {
323+
llvm::errs() << "failed to read " << Path << ": "
324+
<< JSONContent.getError().message() << "\n";
325+
return true;
326+
}
327+
auto JSONValue = llvm::json::parse((*JSONContent)->getBuffer());
328+
if (!JSONValue) {
329+
llvm::errs() << "failed to parse " << Path << ": "
330+
<< toString(JSONValue.takeError()) << "\n";
331+
return true;
332+
}
333+
334+
auto Keys = JSONValue->getAsArray();
335+
if (!Keys) {
336+
llvm::errs() << "invalid keys format in " << Path << "\n";
337+
return true;
338+
}
339+
340+
for (const auto& Entry : *Keys) {
341+
if (auto *Obj = Entry.getAsObject()) {
342+
if (auto Key = Obj->getString("CacheKey")) {
343+
if (auto Buffer = loadCachedCompileResultFromCacheKey(
344+
*DB->first, *DB->second, Instance.getDiags(), *Key))
345+
continue;
346+
llvm::errs() << "failed to find output for cache key " << *Key
347+
<< "\n";
348+
return true;
349+
}
350+
}
351+
llvm::errs() << "can't read cache key from " << Path << "\n";
352+
return true;
353+
}
354+
355+
return false;
356+
};
357+
358+
return llvm::any_of(Inputs, validateCacheKeysFromFile);
359+
}
360+
302361
int swift_cache_tool_main(ArrayRef<const char *> Args, const char *Argv0,
303362
void *MainAddr) {
304363
INITIALIZE_LLVM();

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,13 @@ bool ArgsToFrontendOptionsConverter::convert(
355355
Opts.CASPath =
356356
Args.getLastArgValue(OPT_cas_path, llvm::cas::getDefaultOnDiskCASPath());
357357
Opts.CASFSRootID = Args.getLastArgValue(OPT_cas_fs);
358+
if (Opts.EnableCAS && Opts.CASFSRootID.empty() &&
359+
FrontendOptions::supportCompilationCaching(Opts.RequestedAction)) {
360+
if (!Args.hasArg(OPT_allow_unstable_cache_key_for_testing)) {
361+
Diags.diagnose(SourceLoc(), diag::error_caching_no_cas_fs);
362+
return true;
363+
}
364+
}
358365

359366
return false;
360367
}

lib/Frontend/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ add_swift_host_library(swiftFrontend STATIC
33
ArgsToFrontendInputsConverter.cpp
44
ArgsToFrontendOptionsConverter.cpp
55
ArgsToFrontendOutputsConverter.cpp
6+
CachingUtils.cpp
67
CompileJobCacheKey.cpp
78
CompilerInvocation.cpp
89
DependencyVerifier.cpp

0 commit comments

Comments
 (0)