Skip to content

Commit c153210

Browse files
[CAS] Add test case for cache key computation
Add tool swift-cache-tool for caching related testing and inspection.
1 parent c7d66b8 commit c153210

File tree

11 files changed

+409
-3
lines changed

11 files changed

+409
-3
lines changed

include/swift/Driver/Driver.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ class Driver {
170170
SwiftIndent, // swift-indent
171171
SymbolGraph, // swift-symbolgraph
172172
APIExtract, // swift-api-extract
173-
APIDigester // swift-api-digester
173+
APIDigester, // swift-api-digester
174+
CacheTool // swift-cache-tool
174175
};
175176

176177
class InputInfoMap;

lib/Driver/Driver.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ void Driver::parseDriverKind(ArrayRef<const char *> Args) {
104104
.Case("swift-symbolgraph-extract", DriverKind::SymbolGraph)
105105
.Case("swift-api-extract", DriverKind::APIExtract)
106106
.Case("swift-api-digester", DriverKind::APIDigester)
107+
.Case("swift-cache-tool", DriverKind::CacheTool)
107108
.Default(None);
108109

109110
if (Kind.has_value())
@@ -3563,6 +3564,7 @@ void Driver::printHelp(bool ShowHidden) const {
35633564
case DriverKind::SymbolGraph:
35643565
case DriverKind::APIExtract:
35653566
case DriverKind::APIDigester:
3567+
case DriverKind::CacheTool:
35663568
ExcludedFlagsBitmask |= options::NoBatchOption;
35673569
break;
35683570
}

lib/DriverTool/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set(driver_sources_and_options
33
autolink_extract_main.cpp
44
modulewrap_main.cpp
55
swift_api_digester_main.cpp
6+
swift_cache_tool_main.cpp
67
swift_indent_main.cpp
78
swift_symbolgraph_extract_main.cpp
89
swift_api_extract_main.cpp)
@@ -27,3 +28,9 @@ if(NOT SWIFT_BUILT_STANDALONE)
2728
endif()
2829

2930
set_swift_llvm_is_available(swiftDriverTool)
31+
32+
set(LLVM_TARGET_DEFINITIONS SwiftCacheToolOptions.td)
33+
swift_tablegen(SwiftCacheToolOptions.inc -gen-opt-parser-defs)
34+
swift_add_public_tablegen_target(SwiftCacheToolOptions)
35+
36+
add_dependencies(swiftDriverTool SwiftCacheToolOptions)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Include the common option parsing interfaces.
2+
include "llvm/Option/OptParser.td"
3+
4+
/////////
5+
// Flags
6+
7+
def help : Flag<["-", "--"], "help">,
8+
HelpText<"Display available options">;
9+
10+
def _DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>;
11+
12+
def cache_tool_action: JoinedOrSeparate<["-"], "cache-tool-action">,
13+
HelpText<"Swift Cache Tool Action Kind">,
14+
MetaVarName<"<print-base-key|print-output-keys|...>">;
15+
16+
def cas_path: Separate<["-"], "cas-path">,
17+
HelpText<"Path to CAS">, MetaVarName<"<path>">;

lib/DriverTool/driver.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ extern int swift_api_digester_main(ArrayRef<const char *> Args,
8686
extern int swift_api_extract_main(ArrayRef<const char *> Args,
8787
const char *Argv0, void *MainAddr);
8888

89+
/// Run 'swift-cache-tool'
90+
extern int swift_cache_tool_main(ArrayRef<const char *> Args, const char *Argv0,
91+
void *MainAddr);
92+
8993
/// Determine if the given invocation should run as a "subcommand".
9094
///
9195
/// Examples of "subcommands" are 'swift build' or 'swift test', which are
@@ -299,6 +303,10 @@ static int run_driver(StringRef ExecName,
299303
return swift_api_digester_main(
300304
TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0],
301305
(void *)(intptr_t)getExecutablePath);
306+
case Driver::DriverKind::CacheTool:
307+
return swift_cache_tool_main(
308+
TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0],
309+
(void *)(intptr_t)getExecutablePath);
302310
default:
303311
break;
304312
}
Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
//===--- swift_cache_tool_main.cpp - Swift caching tool for inspection ----===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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+
// Utility tool for inspecting and accessing swift cache.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
//
17+
#include "swift/AST/DiagnosticsFrontend.h"
18+
#include "swift/Basic/LLVM.h"
19+
#include "swift/Basic/LLVMInitialize.h"
20+
#include "swift/Basic/Version.h"
21+
#include "swift/Frontend/CompileJobCacheKey.h"
22+
#include "swift/Frontend/Frontend.h"
23+
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
24+
#include "swift/Parse/ParseVersion.h"
25+
#include "llvm/CAS/ActionCache.h"
26+
#include "llvm/CAS/BuiltinUnifiedCASDatabases.h"
27+
#include "llvm/CAS/ObjectStore.h"
28+
#include "llvm/Option/OptTable.h"
29+
#include "llvm/Support/Error.h"
30+
#include "llvm/Support/JSON.h"
31+
#include <memory>
32+
33+
using namespace swift;
34+
using namespace llvm::opt;
35+
using namespace llvm::cas;
36+
37+
namespace {
38+
39+
enum class SwiftCacheToolAction {
40+
Invalid,
41+
PrintBaseKey,
42+
PrintOutputKeys
43+
};
44+
45+
enum ID {
46+
OPT_INVALID = 0, // This is not an option ID.
47+
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
48+
HELPTEXT, METAVAR, VALUES) \
49+
OPT_##ID,
50+
#include "SwiftCacheToolOptions.inc"
51+
LastOption
52+
#undef OPTION
53+
};
54+
55+
#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
56+
#include "SwiftCacheToolOptions.inc"
57+
#undef PREFIX
58+
59+
static const OptTable::Info InfoTable[] = {
60+
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
61+
HELPTEXT, METAVAR, VALUES) \
62+
{PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
63+
PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
64+
#include "SwiftCacheToolOptions.inc"
65+
#undef OPTION
66+
};
67+
68+
class CacheToolOptTable : public llvm::opt::OptTable {
69+
public:
70+
CacheToolOptTable() : OptTable(InfoTable) {}
71+
};
72+
73+
class SwiftCacheToolInvocation {
74+
private:
75+
CompilerInstance Instance;
76+
CompilerInvocation Invocation;
77+
PrintingDiagnosticConsumer PDC;
78+
std::string MainExecutablePath;
79+
std::string CASPath;
80+
std::vector<std::string> FrontendArgs;
81+
SwiftCacheToolAction ActionKind = SwiftCacheToolAction::Invalid;
82+
83+
public:
84+
SwiftCacheToolInvocation(const std::string &ExecPath)
85+
: MainExecutablePath(ExecPath) {
86+
Instance.addDiagnosticConsumer(&PDC);
87+
}
88+
89+
std::unique_ptr<llvm::opt::OptTable> createOptTable() {
90+
return std::unique_ptr<OptTable>(new CacheToolOptTable());
91+
}
92+
93+
int parseArgs(ArrayRef<const char *> Args) {
94+
auto &Diags = Instance.getDiags();
95+
96+
std::unique_ptr<llvm::opt::OptTable> Table = createOptTable();
97+
unsigned MissingIndex;
98+
unsigned MissingCount;
99+
llvm::opt::InputArgList ParsedArgs =
100+
Table->ParseArgs(Args, MissingIndex, MissingCount);
101+
if (MissingCount) {
102+
Diags.diagnose(SourceLoc(), diag::error_missing_arg_value,
103+
ParsedArgs.getArgString(MissingIndex), MissingCount);
104+
return 1;
105+
}
106+
107+
if (ParsedArgs.getLastArg(OPT_help)) {
108+
std::string ExecutableName =
109+
llvm::sys::path::stem(MainExecutablePath).str();
110+
Table->printHelp(llvm::outs(), ExecutableName.c_str(), "Swift Cache Tool",
111+
0, 0, /*ShowAllAliases*/ false);
112+
return 0;
113+
}
114+
115+
CASPath =
116+
ParsedArgs.getLastArgValue(OPT_cas_path, getDefaultOnDiskCASPath());
117+
118+
FrontendArgs = ParsedArgs.getAllArgValues(OPT__DASH_DASH);
119+
if (auto *A = ParsedArgs.getLastArg(OPT_cache_tool_action))
120+
ActionKind =
121+
llvm::StringSwitch<SwiftCacheToolAction>(A->getValue())
122+
.Case("print-base-key", SwiftCacheToolAction::PrintBaseKey)
123+
.Case("print-output-keys", SwiftCacheToolAction::PrintOutputKeys)
124+
.Default(SwiftCacheToolAction::Invalid);
125+
126+
if (ActionKind == SwiftCacheToolAction::Invalid) {
127+
llvm::errs() << "Invalid option specified for -cache-tool-action: "
128+
<< "use print-base-key|print-output-keys\n";
129+
return 1;
130+
}
131+
132+
return 0;
133+
}
134+
135+
int run() {
136+
switch (ActionKind) {
137+
case SwiftCacheToolAction::PrintBaseKey:
138+
return printBaseKey();
139+
case SwiftCacheToolAction::PrintOutputKeys:
140+
return printOutputKeys();
141+
case SwiftCacheToolAction::Invalid:
142+
return 0; // No action. Probably just print help. Return.
143+
}
144+
}
145+
146+
private:
147+
bool setupCompiler() {
148+
// Setup invocation.
149+
SmallString<128> workingDirectory;
150+
llvm::sys::fs::current_path(workingDirectory);
151+
152+
// Parse arguments.
153+
if (FrontendArgs.empty()) {
154+
llvm::errs() << "missing swift-frontend command-line after --\n";
155+
return true;
156+
}
157+
// drop swift-frontend executable path from command-line.
158+
if (StringRef(FrontendArgs[0]).endswith("swift-frontend"))
159+
FrontendArgs.erase(FrontendArgs.begin());
160+
161+
SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4>
162+
configurationFileBuffers;
163+
std::vector<const char*> Args;
164+
for (auto &A: FrontendArgs)
165+
Args.emplace_back(A.c_str());
166+
167+
// Make sure CASPath is the same between invocation and cache-tool by
168+
// appending the cas-path since the option doesn't affect cache key.
169+
Args.emplace_back("-cas-path");
170+
Args.emplace_back(CASPath.c_str());
171+
172+
if (Invocation.parseArgs(Args, Instance.getDiags(),
173+
&configurationFileBuffers, workingDirectory,
174+
MainExecutablePath))
175+
return true;
176+
177+
if (!Invocation.getFrontendOptions().EnableCAS) {
178+
llvm::errs() << "Requested command-line arguments do not enable CAS\n";
179+
return true;
180+
}
181+
182+
// Setup instance.
183+
std::string InstanceSetupError;
184+
if (Instance.setup(Invocation, InstanceSetupError, Args)) {
185+
llvm::errs() << "swift-frontend invocation setup error: "
186+
<< InstanceSetupError << "\n";
187+
return true;
188+
}
189+
190+
return false;
191+
}
192+
193+
Optional<ObjectRef> getBaseKey() {
194+
auto BaseKey = Instance.getCompilerBaseKey();
195+
if (!BaseKey) {
196+
Instance.getDiags().diagnose(SourceLoc(), diag::error_cas,
197+
"Base Key doesn't exist");
198+
return None;
199+
}
200+
201+
return *BaseKey;
202+
}
203+
204+
int printBaseKey() {
205+
if (setupCompiler())
206+
return 1;
207+
208+
auto &CAS = Instance.getObjectStore();
209+
auto BaseKey = getBaseKey();
210+
if (!BaseKey)
211+
return 1;
212+
213+
if (ActionKind == SwiftCacheToolAction::PrintBaseKey)
214+
llvm::outs() << CAS.getID(*BaseKey).toString() << "\n";
215+
216+
return 0;
217+
}
218+
219+
int printOutputKeys();
220+
};
221+
222+
} // end anonymous namespace
223+
224+
int SwiftCacheToolInvocation::printOutputKeys() {
225+
if (setupCompiler())
226+
return 1;
227+
228+
auto &CAS = Instance.getObjectStore();
229+
auto BaseKey = getBaseKey();
230+
if (!BaseKey)
231+
return 1;
232+
233+
struct OutputEntry {
234+
std::string InputPath;
235+
std::string OutputPath;
236+
std::string OutputKind;
237+
std::string CacheKey;
238+
};
239+
std::vector<OutputEntry> OutputKeys;
240+
bool hasError = false;
241+
auto addOutputKey = [&](StringRef InputPath, file_types::ID OutputKind,
242+
StringRef OutputPath) {
243+
auto OutputKey =
244+
createCompileJobCacheKeyForOutput(CAS, *BaseKey, InputPath, OutputKind);
245+
if (!OutputKey) {
246+
llvm::errs() << "cannot create cache key for " << OutputPath << ": "
247+
<< toString(OutputKey.takeError()) << "\n";
248+
hasError = true;
249+
}
250+
OutputKeys.emplace_back(
251+
OutputEntry{InputPath.str(), OutputPath.str(),
252+
file_types::getTypeName(OutputKind).str(),
253+
CAS.getID(*OutputKey).toString()});
254+
};
255+
auto addFromInputFile = [&](const InputFile &Input) {
256+
auto InputPath = Input.getFileName();
257+
if (!Input.outputFilename().empty())
258+
addOutputKey(InputPath,
259+
Invocation.getFrontendOptions()
260+
.InputsAndOutputs.getPrincipalOutputType(),
261+
Input.outputFilename());
262+
Input.getPrimarySpecificPaths()
263+
.SupplementaryOutputs.forEachSetOutputAndType(
264+
[&](const std::string &File, file_types::ID ID) {
265+
// Dont print serialized diagnostics.
266+
if (ID == file_types::ID::TY_SerializedDiagnostics)
267+
return;
268+
269+
addOutputKey(InputPath, ID, File);
270+
});
271+
};
272+
llvm::for_each(
273+
Invocation.getFrontendOptions().InputsAndOutputs.getAllInputs(),
274+
addFromInputFile);
275+
276+
if (hasError)
277+
return 1;
278+
279+
llvm::json::OStream Out(llvm::outs(), /*IndentSize=*/4);
280+
Out.array([&] {
281+
for (const auto &E : OutputKeys) {
282+
Out.object([&] {
283+
Out.attribute("OutputPath", E.OutputPath);
284+
Out.attribute("OutputKind", E.OutputKind);
285+
Out.attribute("Input", E.InputPath);
286+
Out.attribute("CacheKey", E.CacheKey);
287+
});
288+
}
289+
});
290+
291+
return 0;
292+
}
293+
294+
int swift_cache_tool_main(ArrayRef<const char *> Args, const char *Argv0,
295+
void *MainAddr) {
296+
INITIALIZE_LLVM();
297+
298+
SwiftCacheToolInvocation Invocation(
299+
llvm::sys::fs::getMainExecutable(Argv0, MainAddr));
300+
301+
if (Invocation.parseArgs(Args) != 0)
302+
return EXIT_FAILURE;
303+
304+
if (Invocation.run() != 0)
305+
return EXIT_FAILURE;
306+
307+
return EXIT_SUCCESS;
308+
}

0 commit comments

Comments
 (0)