Skip to content

Commit e8d53f6

Browse files
[CAS] Introduce ActionCache into llvm::cas (#5163)
Introduce ActionCache which can be used together with a CAS to cache computation results with a key.
1 parent e32e81a commit e8d53f6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+776
-279
lines changed

clang/include/clang/Basic/DiagnosticCASKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ let Component = "CAS" in {
1111
def err_builtin_cas_cannot_be_initialized : Error<
1212
"CAS cannot be initialized from '%0' on disk (check -fcas-path)">,
1313
DefaultFatal;
14+
def err_builtin_actioncache_cannot_be_initialized : Error<
15+
"ActionCache cannot be initialized from '%0' on disk (check -faction-cache-path)">,
16+
DefaultFatal;
1417
def err_cas_cannot_parse_root_id : Error<
1518
"CAS cannot parse root-id '%0' specified by -fcas-fs">, DefaultFatal;
1619
def err_cas_filesystem_cannot_be_initialized : Error<

clang/include/clang/CAS/CASOptions.h

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
#include <vector>
2020

2121
namespace llvm {
22+
class Error;
2223
namespace cas {
24+
class ActionCache;
2325
class CASDB;
2426
} // end namespace cas
2527
} // end namespace llvm
@@ -52,10 +54,11 @@ class CASConfiguration {
5254
/// - "auto" is an alias for an automatically chosen location in the user's
5355
/// system cache.
5456
std::string CASPath;
57+
std::string CachePath;
5558

5659
friend bool operator==(const CASConfiguration &LHS,
5760
const CASConfiguration &RHS) {
58-
return LHS.CASPath == RHS.CASPath;
61+
return LHS.CASPath == RHS.CASPath && LHS.CachePath == RHS.CachePath;
5962
}
6063
friend bool operator!=(const CASConfiguration &LHS,
6164
const CASConfiguration &RHS) {
@@ -73,7 +76,7 @@ class CASConfiguration {
7376
/// defined in CASConfiguration to enable caching a CAS instance.
7477
///
7578
/// CASOptions includes \a getOrCreateCAS() and \a
76-
/// getOrCreateCASAndHideConfig() for creating a CAS and caching it.
79+
/// getOrCreateActionCache() for creating CAS and ActionCache.
7780
///
7881
/// FIXME: The the caching is done here, instead of as a field in \a
7982
/// CompilerInstance, in order to ensure that \a
@@ -92,24 +95,38 @@ class CASOptions : public CASConfiguration {
9295
getOrCreateCAS(DiagnosticsEngine &Diags,
9396
bool CreateEmptyCASOnFailure = false) const;
9497

95-
/// Get a CAS defined by the options above. Future calls will return the same
98+
/// Get a ActionCache defined by the options above. Future calls will return
99+
/// the same ActionCache instance... unless the configuration has changed, in
100+
/// which case a new one will be created.
101+
///
102+
/// If \p CreateEmptyCacheOnFailure, returns an empty in-memory ActionCache on
103+
/// failure. Else, returns \c nullptr on failure.
104+
std::shared_ptr<llvm::cas::ActionCache>
105+
getOrCreateActionCache(DiagnosticsEngine &Diags,
106+
bool CreateEmptyCacheOnFailures = false) const;
107+
108+
/// Freeze CAS Configuration. Future calls will return the same
96109
/// CAS instance, even if the configuration changes again later.
97110
///
98111
/// The configuration will be wiped out to prevent it being observable or
99112
/// affecting the output of something that takes \a CASOptions as an input.
100113
/// This also "locks in" the return value of \a getOrCreateCAS(): future
101114
/// calls will not check if the configuration has changed.
102-
std::shared_ptr<llvm::cas::CASDB>
103-
getOrCreateCASAndHideConfig(DiagnosticsEngine &Diags);
115+
void freezeConfig(DiagnosticsEngine &Diags);
104116

105117
/// If the configuration is not for a persistent store, it modifies it to the
106118
/// default on-disk CAS, otherwise this is a noop.
107119
void ensurePersistentCAS();
108120

109121
private:
122+
/// Initialize Cached CAS and ActionCache.
123+
void initCache(DiagnosticsEngine &Diags) const;
124+
110125
struct CachedCAS {
111126
/// A cached CAS instance.
112127
std::shared_ptr<llvm::cas::CASDB> CAS;
128+
/// An ActionCache instnace.
129+
std::shared_ptr<llvm::cas::ActionCache> AC;
113130

114131
/// Remember how the CAS was created.
115132
CASConfiguration Config;

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6513,6 +6513,12 @@ def fcas_path : Separate<["-"], "fcas-path">,
65136513
" '-fcas-path=auto' chooses a path in the user's system cache.">,
65146514
MarshallingInfoString<CASOpts<"CASPath">>;
65156515

6516+
def faction_cache_path : Separate<["-"], "faction-cache-path">,
6517+
Group<f_Group>, MetaVarName<"<dir>|auto">,
6518+
HelpText<"Path to a persistent on-disk backing store for the builtin Cache."
6519+
" '-faction-cache-path=auto' chooses a path in the user's system cache.">,
6520+
MarshallingInfoString<CASOpts<"CachePath">>;
6521+
65166522
// FIXME: Add to driver once it's supported by -fdepscan.
65176523
def fcas_fs : Separate<["-"], "fcas-fs">,
65186524
Group<f_Group>, MetaVarName<"<tree>">,

clang/include/clang/Frontend/CompilerInstance.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ class CompilerInstance : public ModuleLoader {
8787
/// The CAS, if any.
8888
std::shared_ptr<llvm::cas::CASDB> CAS;
8989

90+
/// The ActionCache, if any.
91+
std::shared_ptr<llvm::cas::ActionCache> ActionCache;
92+
9093
/// The file manager.
9194
IntrusiveRefCntPtr<FileManager> FileMgr;
9295

@@ -440,6 +443,7 @@ class CompilerInstance : public ModuleLoader {
440443

441444
/// Get the CAS, or create it using the configuration in CompilerInvocation.
442445
llvm::cas::CASDB &getOrCreateCAS();
446+
llvm::cas::ActionCache &getOrCreateActionCache();
443447

444448
/// }
445449
/// @name Source Manager

clang/include/clang/Tooling/DependencyScanning/DependencyScanningCASFilesystem.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h"
1414
#include "llvm/ADT/StringMap.h"
1515
#include "llvm/ADT/StringSet.h"
16+
#include "llvm/CAS/ActionCache.h"
1617
#include "llvm/CAS/CASID.h"
1718
#include "llvm/CAS/CASReference.h"
1819
#include "llvm/CAS/ThreadSafeFileSystem.h"
@@ -34,7 +35,8 @@ namespace dependencies {
3435
class DependencyScanningCASFilesystem : public llvm::cas::ThreadSafeFileSystem {
3536
public:
3637
DependencyScanningCASFilesystem(
37-
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> WorkerFS);
38+
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> WorkerFS,
39+
llvm::cas::ActionCache &Cache);
3840

3941
~DependencyScanningCASFilesystem();
4042

@@ -104,6 +106,7 @@ class DependencyScanningCASFilesystem : public llvm::cas::ThreadSafeFileSystem {
104106
llvm::cas::CachingOnDiskFileSystem &getCachingFS();
105107

106108
llvm::cas::CASDB &CAS;
109+
llvm::cas::ActionCache &Cache;
107110
Optional<llvm::cas::ObjectRef> ClangFullVersionID;
108111
Optional<llvm::cas::ObjectRef> DepDirectivesID;
109112
Optional<llvm::cas::ObjectRef> EmptyBlobID;

clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "clang/CAS/CASOptions.h"
1313
#include "clang/Tooling/DependencyScanning/DependencyScanningCASFilesystem.h"
1414
#include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h"
15+
#include "llvm/CAS/ActionCache.h"
1516

1617
namespace clang {
1718
namespace tooling {
@@ -58,6 +59,7 @@ class DependencyScanningService {
5859
public:
5960
DependencyScanningService(
6061
ScanningMode Mode, ScanningOutputFormat Format, CASOptions CASOpts,
62+
std::shared_ptr<llvm::cas::ActionCache> Cache,
6163
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> SharedFS,
6264
bool ReuseFileManager = true, bool OptimizeArgs = false,
6365
bool EagerLoadModules = false);
@@ -79,6 +81,10 @@ class DependencyScanningService {
7981
}
8082

8183
const CASOptions &getCASOpts() const { return CASOpts; }
84+
llvm::cas::ActionCache &getCache() const {
85+
assert(Cache && "Cache is not initialized");
86+
return *Cache;
87+
}
8288

8389
llvm::cas::CachingOnDiskFileSystem &getSharedFS() { return *SharedFS; }
8490

@@ -88,6 +94,7 @@ class DependencyScanningService {
8894
const ScanningMode Mode;
8995
const ScanningOutputFormat Format;
9096
CASOptions CASOpts;
97+
std::shared_ptr<llvm::cas::ActionCache> Cache;
9198
const bool ReuseFileManager;
9299
/// Whether to optimize the modules' command-line arguments.
93100
const bool OptimizeArgs;

clang/lib/CAS/CASOptions.cpp

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99
#include "clang/CAS/CASOptions.h"
1010
#include "clang/Basic/Diagnostic.h"
1111
#include "clang/Basic/DiagnosticCAS.h"
12+
#include "llvm/CAS/ActionCache.h"
1213
#include "llvm/CAS/CASDB.h"
14+
#include "llvm/Support/Error.h"
1315

1416
using namespace clang;
1517
using namespace llvm::cas;
1618

1719
static std::shared_ptr<llvm::cas::CASDB>
18-
createCAS(const CASConfiguration &Config, DiagnosticsEngine &Diags,
19-
bool CreateEmptyCASOnFailure) {
20+
createCAS(const CASConfiguration &Config, DiagnosticsEngine &Diags) {
2021
if (Config.CASPath.empty())
2122
return llvm::cas::createInMemoryCAS();
2223

@@ -33,7 +34,7 @@ createCAS(const CASConfiguration &Config, DiagnosticsEngine &Diags,
3334
llvm::expectedToOptional(llvm::cas::createOnDiskCAS(Path)))
3435
return std::move(*MaybeCAS);
3536
Diags.Report(diag::err_builtin_cas_cannot_be_initialized) << Path;
36-
return CreateEmptyCASOnFailure ? llvm::cas::createInMemoryCAS() : nullptr;
37+
return nullptr;
3738
}
3839

3940
std::shared_ptr<llvm::cas::CASDB>
@@ -42,22 +43,21 @@ CASOptions::getOrCreateCAS(DiagnosticsEngine &Diags,
4243
if (Cache.Config.IsFrozen)
4344
return Cache.CAS;
4445

45-
auto &CurrentConfig = static_cast<const CASConfiguration &>(*this);
46-
if (!Cache.CAS || CurrentConfig != Cache.Config) {
47-
Cache.Config = CurrentConfig;
48-
Cache.CAS = createCAS(Cache.Config, Diags, CreateEmptyCASOnFailure);
49-
}
50-
46+
initCache(Diags);
47+
if (Cache.CAS)
48+
return Cache.CAS;
49+
if (!CreateEmptyCASOnFailure)
50+
return nullptr;
51+
Cache.CAS = llvm::cas::createInMemoryCAS();
5152
return Cache.CAS;
5253
}
5354

54-
std::shared_ptr<llvm::cas::CASDB>
55-
CASOptions::getOrCreateCASAndHideConfig(DiagnosticsEngine &Diags) {
55+
void CASOptions::freezeConfig(DiagnosticsEngine &Diags) {
5656
if (Cache.Config.IsFrozen)
57-
return Cache.CAS;
57+
return;
5858

59-
std::shared_ptr<llvm::cas::CASDB> CAS = getOrCreateCAS(Diags);
60-
assert(CAS == Cache.CAS && "Expected CAS to be cached");
59+
// Make sure the cache is initialized.
60+
initCache(Diags);
6161

6262
// Freeze the CAS and wipe out the visible config to hide it from future
6363
// accesses. For example, future diagnostics cannot see this. Something that
@@ -67,13 +67,48 @@ CASOptions::getOrCreateCASAndHideConfig(DiagnosticsEngine &Diags) {
6767
CurrentConfig = CASConfiguration();
6868
CurrentConfig.IsFrozen = Cache.Config.IsFrozen = true;
6969

70-
if (CAS) {
70+
if (Cache.CAS) {
7171
// Set the CASPath to the hash schema, since that leaks through CASContext's
7272
// API and is observable.
73-
CurrentConfig.CASPath = CAS->getHashSchemaIdentifier().str();
73+
CurrentConfig.CASPath = Cache.CAS->getHashSchemaIdentifier().str();
7474
}
75+
if (Cache.AC)
76+
CurrentConfig.CachePath = "";
77+
}
78+
79+
static std::shared_ptr<llvm::cas::ActionCache>
80+
createCache(CASDB &CAS, const CASConfiguration &Config,
81+
DiagnosticsEngine &Diags) {
82+
if (Config.CachePath.empty())
83+
return llvm::cas::createInMemoryActionCache(CAS);
84+
85+
// Compute the path.
86+
std::string Path = Config.CASPath;
87+
if (Path == "auto")
88+
Path = getDefaultOnDiskActionCachePath();
7589

76-
return CAS;
90+
// FIXME: Pass on the actual error from the CAS.
91+
if (auto MaybeCache = llvm::expectedToOptional(
92+
llvm::cas::createOnDiskActionCache(CAS, Path)))
93+
return std::move(*MaybeCache);
94+
Diags.Report(diag::err_builtin_actioncache_cannot_be_initialized) << Path;
95+
return nullptr;
96+
}
97+
98+
std::shared_ptr<llvm::cas::ActionCache>
99+
CASOptions::getOrCreateActionCache(DiagnosticsEngine &Diags,
100+
bool CreateEmptyOnFailure) const {
101+
if (Cache.Config.IsFrozen)
102+
return Cache.AC;
103+
104+
initCache(Diags);
105+
if (Cache.AC)
106+
return Cache.AC;
107+
if (!CreateEmptyOnFailure)
108+
return nullptr;
109+
110+
Cache.CAS = Cache.CAS ? Cache.CAS : llvm::cas::createInMemoryCAS();
111+
return llvm::cas::createInMemoryActionCache(*Cache.CAS);
77112
}
78113

79114
void CASOptions::ensurePersistentCAS() {
@@ -83,8 +118,19 @@ void CASOptions::ensurePersistentCAS() {
83118
llvm_unreachable("Cannot ensure persistent CAS if it's unknown / frozen");
84119
case InMemoryCAS:
85120
CASPath = "auto";
121+
CachePath = "auto";
86122
break;
87123
case OnDiskCAS:
88124
break;
89125
}
90126
}
127+
128+
void CASOptions::initCache(DiagnosticsEngine &Diags) const {
129+
auto &CurrentConfig = static_cast<const CASConfiguration &>(*this);
130+
if (CurrentConfig == Cache.Config && Cache.CAS && Cache.AC)
131+
return;
132+
133+
Cache.Config = CurrentConfig;
134+
Cache.CAS = createCAS(Cache.Config, Diags);
135+
Cache.AC = createCache(*Cache.CAS, Cache.Config, Diags);
136+
}

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,16 @@ llvm::cas::CASDB &CompilerInstance::getOrCreateCAS() {
880880
return *CAS;
881881
}
882882

883+
llvm::cas::ActionCache &CompilerInstance::getOrCreateActionCache() {
884+
if (ActionCache)
885+
return *ActionCache;
886+
887+
ActionCache = getInvocation().getCASOpts().getOrCreateActionCache(
888+
getDiagnostics(),
889+
/*CreateEmptyActionCacheOnFailure=*/true);
890+
return *ActionCache;
891+
}
892+
883893
std::unique_ptr<raw_pwrite_stream>
884894
CompilerInstance::createOutputFile(StringRef OutputPath, bool Binary,
885895
bool RemoveFileOnSignal, bool UseTemporary,

clang/lib/Tooling/DependencyScanning/DependencyScanningCASFilesystem.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "clang/Tooling/DependencyScanning/DependencyScanningCASFilesystem.h"
1010
#include "clang/Basic/Version.h"
1111
#include "clang/Lex/DependencyDirectivesScanner.h"
12+
#include "llvm/CAS/ActionCache.h"
1213
#include "llvm/CAS/CASDB.h"
1314
#include "llvm/CAS/CachingOnDiskFileSystem.h"
1415
#include "llvm/CAS/HierarchicalTreeBuilder.h"
@@ -34,8 +35,10 @@ static void reportAsFatalIfError(llvm::Error E) {
3435
using llvm::Error;
3536

3637
DependencyScanningCASFilesystem::DependencyScanningCASFilesystem(
37-
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> WorkerFS)
38-
: FS(WorkerFS), Entries(EntryAlloc), CAS(WorkerFS->getCAS()) {}
38+
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> WorkerFS,
39+
llvm::cas::ActionCache &Cache)
40+
: FS(WorkerFS), Entries(EntryAlloc), CAS(WorkerFS->getCAS()), Cache(Cache) {
41+
}
3942

4043
DependencyScanningCASFilesystem::~DependencyScanningCASFilesystem() = default;
4144

@@ -84,12 +87,12 @@ template <typename T> static void readle(StringRef &Slice, T &Out) {
8487
}
8588

8689
static Error loadDepDirectives(
87-
cas::CASDB &CAS, cas::CASID ID,
90+
cas::CASDB &CAS, cas::ObjectRef Ref,
8891
llvm::SmallVectorImpl<dependency_directives_scan::Token> &DepTokens,
8992
llvm::SmallVectorImpl<dependency_directives_scan::Directive>
9093
&DepDirectives) {
9194
using namespace dependency_directives_scan;
92-
auto Blob = CAS.getProxy(ID);
95+
auto Blob = CAS.getProxy(Ref);
9396
if (!Blob)
9497
return Blob.takeError();
9598

@@ -164,9 +167,10 @@ void DependencyScanningCASFilesystem::scanForDirectives(
164167
}
165168

166169
// Check the result cache.
167-
if (Optional<CASID> OutputID =
168-
expectedToOptional(CAS.getCachedResult(*InputID))) {
169-
reportAsFatalIfError(loadDepDirectives(CAS, *OutputID, Tokens, Directives));
170+
if (Optional<ObjectRef> OutputRef =
171+
reportAsFatalIfError(Cache.get(*InputID))) {
172+
reportAsFatalIfError(
173+
loadDepDirectives(CAS, *OutputRef, Tokens, Directives));
170174
return;
171175
}
172176

@@ -178,16 +182,15 @@ void DependencyScanningCASFilesystem::scanForDirectives(
178182
// Failure. Cache empty directives.
179183
Tokens.clear();
180184
Directives.clear();
181-
reportAsFatalIfError(
182-
CAS.putCachedResult(*InputID, CAS.getID(*EmptyBlobID)));
185+
reportAsFatalIfError(Cache.put(*InputID, *EmptyBlobID));
183186
return;
184187
}
185188

186189
// Success. Add to the CAS and get back persistent output data.
187-
cas::CASID DirectivesID =
188-
CAS.getID(reportAsFatalIfError(storeDepDirectives(CAS, Directives)));
190+
cas::ObjectRef DirectivesID =
191+
reportAsFatalIfError(storeDepDirectives(CAS, Directives));
189192
// Cache the computation.
190-
reportAsFatalIfError(CAS.putCachedResult(*InputID, DirectivesID));
193+
reportAsFatalIfError(Cache.put(*InputID, DirectivesID));
191194
}
192195

193196
Expected<StringRef>

0 commit comments

Comments
 (0)