Skip to content

Commit 6c30976

Browse files
[Caching] Change swift cache key computation
Update swift cache key computation mechanism from one cache key per output, to one cache key per primary input file (for all outputs that associated with that input). The new schema allows fewer cache lookups while still preserving most of the flexibility for batch mode and incremental mode.
1 parent fad02e3 commit 6c30976

25 files changed

+1012
-353
lines changed

include/swift-c/DependencyScan/DependencyScan.h

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -437,17 +437,6 @@ typedef struct swiftscan_cas_options_s *swiftscan_cas_options_t;
437437
/// ActionCache.
438438
typedef struct swiftscan_cas_s *swiftscan_cas_t;
439439

440-
/// Enum types for output types for cache key computation.
441-
/// TODO: complete the list.
442-
typedef enum {
443-
SWIFTSCAN_OUTPUT_TYPE_OBJECT = 0,
444-
SWIFTSCAN_OUTPUT_TYPE_SWIFTMODULE = 1,
445-
SWIFTSCAN_OUTPUT_TYPE_SWIFTINTERFACE = 2,
446-
SWIFTSCAN_OUTPUT_TYPE_SWIFTPRIVATEINTERFACE = 3,
447-
SWIFTSCAN_OUTPUT_TYPE_CLANG_MODULE = 4,
448-
SWIFTSCAN_OUTPUT_TYPE_CLANG_PCH = 5
449-
} swiftscan_output_kind_t;
450-
451440
/// Create a \c CASOptions for creating CAS inside scanner specified.
452441
SWIFTSCAN_PUBLIC swiftscan_cas_options_t swiftscan_cas_options_create(void);
453442

@@ -489,13 +478,15 @@ SWIFTSCAN_PUBLIC swiftscan_string_ref_t
489478
swiftscan_cas_store(swiftscan_cas_t cas, uint8_t *data, unsigned size,
490479
swiftscan_string_ref_t *error);
491480

492-
/// Compute \c CacheKey for output of \c kind from the compiler invocation \c
493-
/// argc and \c argv with \c input. Return \c CacheKey as string.
481+
/// Compute \c CacheKey for the outputs of a primary input file from a compiler
482+
/// invocation with command-line \c argc and \c argv. When primary input file
483+
/// is not available for compilation, e.g., using WMO, primary file is the first
484+
/// swift input on the command-line by convention. Return \c CacheKey as string.
494485
/// If error happens, the error message is returned via `error` parameter, and
495486
/// caller needs to free the error message via `swiftscan_string_dispose`.
496-
SWIFTSCAN_PUBLIC swiftscan_string_ref_t swiftscan_compute_cache_key(
497-
swiftscan_cas_t cas, int argc, const char **argv, const char *input,
498-
swiftscan_output_kind_t kind, swiftscan_string_ref_t *error);
487+
SWIFTSCAN_PUBLIC swiftscan_string_ref_t
488+
swiftscan_cache_compute_key(swiftscan_cas_t cas, int argc, const char **argv,
489+
const char *input, swiftscan_string_ref_t *error);
499490

500491
//===----------------------------------------------------------------------===//
501492

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ ERROR(error_caching_no_cas_fs, none,
494494
ERROR(error_prefix_mapping, none, "cannot create scanner prefix mapping: '%0'", (StringRef))
495495

496496
REMARK(replay_output, none, "replay output file '%0': key '%1'", (StringRef, StringRef))
497-
REMARK(output_cache_miss, none, "cache miss output file '%0': key '%1'", (StringRef, StringRef))
497+
REMARK(output_cache_miss, none, "cache miss for input file '%0': key '%1'", (StringRef, StringRef))
498498

499499
// CAS related diagnostics
500500
ERROR(error_invalid_cas_id, none, "invalid CASID '%0' (%1)", (StringRef, StringRef))

include/swift/Basic/FileTypes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ bool isAfterLLVM(ID Id);
5858
/// These need to be passed to the Swift frontend
5959
bool isPartOfSwiftCompilation(ID Id);
6060

61+
/// Returns true of the type of the output is produced from a diagnostic engine.
62+
bool isProducedFromDiagnostics(ID Id);
63+
6164
static inline void forAllTypes(llvm::function_ref<void(file_types::ID)> fn) {
6265
for (uint8_t i = 0; i < static_cast<uint8_t>(TY_INVALID); ++i)
6366
fn(static_cast<ID>(i));
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===------CASOutputBackends.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_CASOUTPUTBACKENDS_H
14+
#define SWIFT_FRONTEND_CASOUTPUTBACKENDS_H
15+
16+
#include "swift/Frontend/FrontendInputsAndOutputs.h"
17+
#include "swift/Frontend/FrontendOptions.h"
18+
#include "llvm/CAS/ActionCache.h"
19+
#include "llvm/CAS/ObjectStore.h"
20+
#include "llvm/Support/VirtualOutputBackends.h"
21+
#include "llvm/Support/VirtualOutputFile.h"
22+
23+
namespace swift::cas {
24+
25+
class SwiftCASOutputBackend : public llvm::vfs::OutputBackend {
26+
void anchor() override;
27+
28+
protected:
29+
llvm::IntrusiveRefCntPtr<OutputBackend> cloneImpl() const override;
30+
31+
llvm::Expected<std::unique_ptr<llvm::vfs::OutputFileImpl>>
32+
createFileImpl(llvm::StringRef ResolvedPath,
33+
llvm::Optional<llvm::vfs::OutputConfig> Config) override;
34+
35+
virtual llvm::Error storeImpl(llvm::StringRef Path, llvm::StringRef Bytes,
36+
llvm::StringRef CorrespondingInput,
37+
file_types::ID OutputKind);
38+
39+
private:
40+
file_types::ID getOutputFileType(llvm::StringRef Path) const;
41+
42+
public:
43+
SwiftCASOutputBackend(llvm::cas::ObjectStore &CAS,
44+
llvm::cas::ActionCache &Cache,
45+
llvm::cas::ObjectRef BaseKey,
46+
const FrontendInputsAndOutputs &InputsAndOutputs,
47+
FrontendOptions::ActionType Action);
48+
~SwiftCASOutputBackend();
49+
50+
llvm::Error storeCachedDiagnostics(llvm::StringRef InputFile,
51+
llvm::StringRef Bytes);
52+
53+
private:
54+
class Implementation;
55+
Implementation &Impl;
56+
};
57+
58+
} // end namespace swift::cas
59+
60+
#endif

include/swift/Frontend/CachingUtils.h

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
#ifndef SWIFT_FRONTEND_CACHINGUTILS_H
1414
#define SWIFT_FRONTEND_CACHINGUTILS_H
1515

16+
#include "swift/Frontend/CASOutputBackends.h"
1617
#include "swift/Frontend/CachedDiagnostics.h"
1718
#include "swift/Frontend/FrontendInputsAndOutputs.h"
19+
#include "swift/Frontend/FrontendOptions.h"
1820
#include "clang/CAS/CASOptions.h"
1921
#include "llvm/ADT/IntrusiveRefCntPtr.h"
2022
#include "llvm/CAS/ActionCache.h"
@@ -29,11 +31,12 @@ namespace swift {
2931

3032
/// Create a swift caching output backend that stores the output from
3133
/// compiler into a CAS.
32-
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend>
34+
llvm::IntrusiveRefCntPtr<cas::SwiftCASOutputBackend>
3335
createSwiftCachingOutputBackend(
3436
llvm::cas::ObjectStore &CAS, llvm::cas::ActionCache &Cache,
3537
llvm::cas::ObjectRef BaseKey,
36-
const FrontendInputsAndOutputs &InputsAndOutputs);
38+
const FrontendInputsAndOutputs &InputsAndOutputs,
39+
FrontendOptions::ActionType Action);
3740

3841
/// Replay the output of the compilation from cache.
3942
/// Return true if outputs are replayed, false otherwise.
@@ -46,24 +49,35 @@ bool replayCachedCompilerOutputs(
4649
/// Load the cached compile result from cache.
4750
std::unique_ptr<llvm::MemoryBuffer> loadCachedCompileResultFromCacheKey(
4851
llvm::cas::ObjectStore &CAS, llvm::cas::ActionCache &Cache,
49-
DiagnosticEngine &Diag, llvm::StringRef CacheKey,
52+
DiagnosticEngine &Diag, llvm::StringRef CacheKey, file_types::ID Type,
5053
llvm::StringRef Filename = "");
5154

52-
/// Store compiler output.
53-
llvm::Error storeCachedCompilerOutput(llvm::cas::ObjectStore &CAS,
54-
llvm::cas::ActionCache &Cache,
55-
StringRef Path, StringRef Bytes,
56-
llvm::cas::ObjectRef BaseKey,
57-
StringRef CorrespondingInput,
58-
file_types::ID OutputKind);
59-
6055
llvm::Expected<llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>>
6156
createCASFileSystem(llvm::cas::ObjectStore &CAS, ArrayRef<std::string> FSRoots,
6257
ArrayRef<std::string> IncludeTreeRoots);
6358

6459
std::vector<std::string> remapPathsFromCommandLine(
6560
ArrayRef<std::string> Args,
6661
llvm::function_ref<std::string(StringRef)> RemapCallback);
67-
} // namespace swift
62+
63+
namespace cas {
64+
class CachedResultLoader {
65+
public:
66+
CachedResultLoader(llvm::cas::ObjectStore &CAS, llvm::cas::ActionCache &Cache,
67+
llvm::cas::ObjectRef CacheKey)
68+
: CAS(CAS), Cache(Cache), CacheKey(CacheKey) {}
69+
70+
using CallbackTy =
71+
llvm::function_ref<llvm::Error(file_types::ID, llvm::cas::ObjectRef)>;
72+
// Replay the cached result, return false if a cache miss happened.
73+
llvm::Expected<bool> replay(CallbackTy Callback);
74+
75+
private:
76+
llvm::cas::ObjectStore &CAS;
77+
llvm::cas::ActionCache &Cache;
78+
llvm::cas::ObjectRef CacheKey;
79+
};
80+
} // end namespace cas
81+
} // end namespace swift
6882

6983
#endif

include/swift/Frontend/CompileJobCacheKey.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ createCompileJobBaseCacheKey(llvm::cas::ObjectStore &CAS,
4141
llvm::Expected<llvm::cas::ObjectRef>
4242
createCompileJobCacheKeyForOutput(llvm::cas::ObjectStore &CAS,
4343
llvm::cas::ObjectRef BaseKey,
44-
StringRef ProducingInput,
45-
file_types::ID OutputType);
44+
StringRef ProducingInput);
4645
} // namespace swift
4746

4847
#endif
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
//===------CompileJobCacheResult.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_COMPILEJOBCACHERESULT_H
14+
#define SWIFT_FRONTEND_COMPILEJOBCACHERESULT_H
15+
16+
#include "swift/Basic/FileTypes.h"
17+
#include "llvm/CAS/CASNodeSchema.h"
18+
#include "llvm/CAS/ObjectStore.h"
19+
20+
namespace swift::cas {
21+
22+
class CompileJobResultSchema;
23+
class CompileJobCacheResult : public llvm::cas::ObjectProxy {
24+
public:
25+
/// A single output file or stream.
26+
struct Output {
27+
/// The CAS object for this output.
28+
llvm::cas::ObjectRef Object;
29+
/// The output kind.
30+
file_types::ID Kind;
31+
32+
bool operator==(const Output &Other) const {
33+
return Object == Other.Object && Kind == Other.Kind;
34+
}
35+
};
36+
37+
/// Retrieves each \c Output from this result.
38+
llvm::Error
39+
forEachOutput(llvm::function_ref<llvm::Error(Output)> Callback) const;
40+
41+
/// Loads all outputs concurrently and passes the resulting \c ObjectProxy
42+
/// objects to \p Callback. If there was an error during loading then the
43+
/// callback will not be invoked.
44+
llvm::Error forEachLoadedOutput(
45+
llvm::function_ref<llvm::Error(Output, std::optional<ObjectProxy>)>
46+
Callback);
47+
48+
size_t getNumOutputs() const;
49+
50+
Output getOutput(size_t I) const;
51+
52+
/// Retrieves a specific output specified by \p Kind, if it exists.
53+
llvm::Optional<Output> getOutput(file_types::ID Kind) const;
54+
55+
/// Print this result to \p OS.
56+
llvm::Error print(llvm::raw_ostream &OS);
57+
58+
/// Helper to build a \c CompileJobCacheResult from individual outputs.
59+
class Builder {
60+
public:
61+
Builder();
62+
~Builder();
63+
/// Treat outputs added for \p Path as having the given \p Kind. Otherwise
64+
/// they will have kind \c Unknown.
65+
void addKindMap(file_types::ID Kind, StringRef Path);
66+
/// Add an output with an explicit \p Kind.
67+
void addOutput(file_types::ID Kind, llvm::cas::ObjectRef Object);
68+
/// Add an output for the given \p Path. There must be a a kind map for it.
69+
llvm::Error addOutput(StringRef Path, llvm::cas::ObjectRef Object);
70+
/// Build a single \c ObjectRef representing the provided outputs. The
71+
/// result can be used with \c CompileJobResultSchema to retrieve the
72+
/// original outputs.
73+
llvm::Expected<llvm::cas::ObjectRef> build(llvm::cas::ObjectStore &CAS);
74+
75+
private:
76+
struct PrivateImpl;
77+
PrivateImpl &Impl;
78+
};
79+
80+
private:
81+
llvm::cas::ObjectRef getOutputObject(size_t I) const;
82+
llvm::cas::ObjectRef getPathsListRef() const;
83+
file_types::ID getOutputKind(size_t I) const;
84+
llvm::Expected<llvm::cas::ObjectRef> getOutputPath(size_t I) const;
85+
86+
private:
87+
friend class CompileJobResultSchema;
88+
CompileJobCacheResult(const ObjectProxy &);
89+
};
90+
91+
class CompileJobResultSchema
92+
: public llvm::RTTIExtends<CompileJobResultSchema, llvm::cas::NodeSchema> {
93+
public:
94+
static char ID;
95+
96+
CompileJobResultSchema(llvm::cas::ObjectStore &CAS);
97+
98+
/// Attempt to load \p Ref as a \c CompileJobCacheResult if it matches the
99+
/// schema.
100+
llvm::Expected<CompileJobCacheResult> load(llvm::cas::ObjectRef Ref) const;
101+
102+
bool isRootNode(const CompileJobCacheResult::ObjectProxy &Node) const final;
103+
bool isNode(const CompileJobCacheResult::ObjectProxy &Node) const final;
104+
105+
/// Get this schema's marker node.
106+
llvm::cas::ObjectRef getKindRef() const { return KindRef; }
107+
108+
private:
109+
llvm::cas::ObjectRef KindRef;
110+
};
111+
112+
} // namespace swift::cas
113+
114+
#endif

include/swift/Frontend/Frontend.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/Basic/LangOptions.h"
3131
#include "swift/Basic/SourceManager.h"
3232
#include "swift/ClangImporter/ClangImporter.h"
33+
#include "swift/Frontend/CASOutputBackends.h"
3334
#include "swift/Frontend/CachedDiagnostics.h"
3435
#include "swift/Frontend/DiagnosticVerifier.h"
3536
#include "swift/Frontend/FrontendOptions.h"
@@ -483,6 +484,10 @@ class CompilerInstance {
483484
/// Virtual OutputBackend.
484485
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> OutputBackend = nullptr;
485486

487+
/// CAS OutputBackend.
488+
llvm::IntrusiveRefCntPtr<swift::cas::SwiftCASOutputBackend> CASOutputBackend =
489+
nullptr;
490+
486491
/// The verification output backend.
487492
using HashBackendTy = llvm::vfs::HashingOutputBackend<llvm::BLAKE3>;
488493
llvm::IntrusiveRefCntPtr<HashBackendTy> HashBackend;
@@ -537,6 +542,10 @@ class CompilerInstance {
537542
llvm::vfs::OutputBackend &getOutputBackend() const {
538543
return *OutputBackend;
539544
}
545+
swift::cas::SwiftCASOutputBackend &getCASOutputBackend() const {
546+
return *CASOutputBackend;
547+
}
548+
540549
void
541550
setOutputBackend(llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> Backend) {
542551
OutputBackend = std::move(Backend);

0 commit comments

Comments
 (0)