Skip to content

Commit 9177399

Browse files
[SwiftScan] Add SwiftScan APIs to replay the cache output
Add new C APIs to libSwiftScan for cache querying and cache replays.
1 parent aa6a588 commit 9177399

File tree

15 files changed

+1216
-101
lines changed

15 files changed

+1216
-101
lines changed

include/swift-c/DependencyScan/DependencyScan.h

Lines changed: 169 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
/// SWIFTSCAN_VERSION_MINOR should increase when there are API additions.
2626
/// SWIFTSCAN_VERSION_MAJOR is intended for "major" source/ABI breaking changes.
2727
#define SWIFTSCAN_VERSION_MAJOR 0
28-
#define SWIFTSCAN_VERSION_MINOR 5
28+
#define SWIFTSCAN_VERSION_MINOR 6
2929

3030
SWIFTSCAN_BEGIN_DECLS
3131

@@ -441,6 +441,51 @@ typedef struct swiftscan_cas_options_s *swiftscan_cas_options_t;
441441
/// ActionCache.
442442
typedef struct swiftscan_cas_s *swiftscan_cas_t;
443443

444+
/// Opaque container for a cached compilation.
445+
typedef struct swiftscan_cached_compilation_s *swiftscan_cached_compilation_t;
446+
447+
/// Opaque type for a cache replay instance.
448+
typedef struct swiftscan_cache_replay_instance_s
449+
*swiftscan_cache_replay_instance_t;
450+
451+
/// Opaque type for a cancellation token for async cache operations.
452+
typedef struct swiftscan_cache_cancellation_token_s
453+
*swiftscan_cache_cancellation_token_t;
454+
455+
/// Enum types for output types for cache key computation.
456+
/// List should contain all the output file types, including supplemententary
457+
/// outputs, except diagnostics outputs, which are covered by cached diagnostic
458+
/// entry.
459+
typedef enum {
460+
SWIFTSCAN_OUTPUT_TYPE_OBJECT = 0,
461+
SWIFTSCAN_OUTPUT_TYPE_SWIFTMODULE = 1,
462+
SWIFTSCAN_OUTPUT_TYPE_SWIFTINTERFACE = 2,
463+
SWIFTSCAN_OUTPUT_TYPE_SWIFTPRIVATEINTERFACE = 3,
464+
SWIFTSCAN_OUTPUT_TYPE_CLANG_MODULE = 4,
465+
SWIFTSCAN_OUTPUT_TYPE_CLANG_PCH = 5,
466+
SWIFTSCAN_OUTPUT_TYPE_CLANG_HEADER = 6,
467+
SWIFTSCAN_OUTPUT_TYPE_SWIFT_SOURCE_INFO = 7,
468+
SWIFTSCAN_OUTPUT_TYPE_SWIFT_MODULE_DOC = 8,
469+
SWIFTSCAN_OUTPUT_TYPE_DEPENDENCIES = 9,
470+
SWIFTSCAN_OUTPUT_TYPE_SWIFT_DEPS = 10,
471+
SWIFTSCAN_OUTPUT_TYPE_MODULE_TRACE = 11,
472+
SWIFTSCAN_OUTPUT_TYPE_TBD = 12,
473+
SWIFTSCAN_OUTPUT_TYPE_SWIFT_MODULE_SUMMARY = 13,
474+
SWIFTSCAN_OUTPUT_TYPE_SWIFT_ABI_DESCRIPTOR = 14,
475+
SWIFTSCAN_OUTPUT_TYPE_CONST_VALUE = 15,
476+
SWIFTSCAN_OUTPUT_TYPE_MODULE_SEMANTIC_INFO = 16,
477+
SWIFTSCAN_OUTPUT_TYPE_YAML_OPT_RECORD = 17,
478+
SWIFTSCAN_OUTPUT_TYPE_BITSTREAM_OPT_RECORD = 18,
479+
SWIFTSCAN_OUTPUT_TYPE_CACHED_DIAGNOSTICS = 19
480+
} swiftscan_output_kind_t;
481+
482+
/// Enum types for cache result lookup or replay.
483+
typedef enum {
484+
SWIFTSCAN_CACHE_RESULT_SUCCESS = 0,
485+
SWIFTSCAN_CACHE_RESULT_NOT_FOUND = 1,
486+
SWIFTSCAN_CACHE_RESULT_ERROR = 2,
487+
} swiftscan_cache_result_t;
488+
444489
/// Create a \c CASOptions for creating CAS inside scanner specified.
445490
SWIFTSCAN_PUBLIC swiftscan_cas_options_t swiftscan_cas_options_create(void);
446491

@@ -492,6 +537,129 @@ SWIFTSCAN_PUBLIC swiftscan_string_ref_t
492537
swiftscan_cache_compute_key(swiftscan_cas_t cas, int argc, const char **argv,
493538
const char *input, swiftscan_string_ref_t *error);
494539

540+
/// Query the result of the compilation using the output cache key. \c globally
541+
/// suggests if the lookup should check remote cache if such operation exists.
542+
/// Returns the CachedCompilation of the result if found, or nullptr if output
543+
/// is not found or an error occurs. When an error occurs, the error message is
544+
/// returned via \c error parameter and its caller needs to free the message
545+
/// using `swiftscan_string_dispose`. The returned CachedCompilation needs to be
546+
/// freed via `swiftscan_cached_compilation_dispose`.
547+
SWIFTSCAN_PUBLIC swiftscan_cached_compilation_t
548+
swiftscan_cache_query(swiftscan_cas_t cas, const char *key, bool globally,
549+
swiftscan_string_ref_t *error);
550+
551+
/// Async version of `swiftscan_cache_query` where result is returned via
552+
/// callback. Both cache_result enum and CachedCompilation will be provided to
553+
/// callback. \c ctx is an opaque value that passed to the callback and \c
554+
/// swiftscan_cache_cancellation_token_t will return an token that can be used
555+
/// to cancel the async operation. The token needs to be freed by caller using
556+
/// `swiftscan_cache_cancellation_token_dispose`.
557+
SWIFTSCAN_PUBLIC void swiftscan_cache_query_async(
558+
swiftscan_cas_t cas, const char *key, bool globally, void *ctx,
559+
void (*callback)(void *ctx, swiftscan_cache_result_t,
560+
swiftscan_cached_compilation_t,
561+
swiftscan_string_ref_t error),
562+
swiftscan_cache_cancellation_token_t *);
563+
564+
/// Dispose a CachedCompilation.
565+
SWIFTSCAN_PUBLIC void
566+
swiftscan_cached_compilation_dispose(swiftscan_cached_compilation_t);
567+
568+
/// Download and materialized the CASObject referenced by the CASID in the local
569+
/// CAS if needed from a remote CAS.
570+
/// If the return value is SWIFTSCAN_CACHE_RESULT_ERROR, the error message is
571+
/// returned via \c error parameter and its caller needs to free the message
572+
/// using `swiftscan_string_dispose`.
573+
SWIFTSCAN_PUBLIC swiftscan_cache_result_t
574+
swiftscan_cache_load_object(swiftscan_cas_t cas, swiftscan_cached_compilation_t,
575+
swiftscan_string_ref_t *error);
576+
577+
/// Async version of `swiftscan_cache_load_object` where result is returned via
578+
/// callback. \c ctx is an opaque value that passed to the callback and
579+
/// \c swiftscan_cache_cancellation_token_t will return an token that can be
580+
/// used to cancel the async operation. The token needs to be freed by caller
581+
/// using `swiftscan_cache_cancellation_token_dispose`.
582+
SWIFTSCAN_PUBLIC void swiftscan_cache_load_object_async(
583+
swiftscan_cas_t cas, swiftscan_cached_compilation_t, void *ctx,
584+
void (*callback)(void *ctx, swiftscan_cache_result_t,
585+
swiftscan_string_ref_t error),
586+
swiftscan_cache_cancellation_token_t *);
587+
588+
/// Check if CachedCompilation is materialized locally and can be accessed
589+
/// without downloading.
590+
SWIFTSCAN_PUBLIC bool
591+
swiftscan_cache_compilation_is_loaded(swiftscan_cached_compilation_t);
592+
593+
/// Query the number of outputs from a cached compilation. The cached
594+
/// compilation needs to be loaded, otherwise will return error. The error
595+
/// message is returned via \c error parameter and its caller needs to free the
596+
/// message using `swiftscan_string_dispose`.
597+
SWIFTSCAN_PUBLIC unsigned
598+
swiftscan_cache_get_num_cached_outputs(swiftscan_cached_compilation_t,
599+
swiftscan_string_ref_t *error);
600+
601+
/// Query if the kind of otuput exists in a cached compilation. The cached
602+
/// compilation needs to be loaded, otherwise will return error. The error
603+
/// message is returned via \c error parameter and its caller needs to free the
604+
/// message using `swiftscan_string_dispose`.
605+
SWIFTSCAN_PUBLIC bool
606+
swiftscan_cache_compilation_has_output_kind(swiftscan_cached_compilation_t,
607+
swiftscan_output_kind_t,
608+
swiftscan_string_ref_t *error);
609+
610+
/// Make the cache compilation available globally. \c callback will be called
611+
/// on completion.
612+
/// \c swiftscan_cache_cancellation_token_t will return an token that can be
613+
/// used to cancel the async operation. The token needs to be freed by caller
614+
/// using `swiftscan_cache_cancellation_token_dispose`.
615+
SWIFTSCAN_PUBLIC void swiftscan_cache_make_global_async(
616+
swiftscan_cas_t cas, const char *key, void *ctx,
617+
void (*callback)(void *ctx, swiftscan_string_ref_t error),
618+
swiftscan_cache_cancellation_token_t *);
619+
620+
/// Cancel the async cache action that is associated with token.
621+
SWIFTSCAN_PUBLIC void
622+
swiftscan_cache_action_cancel(swiftscan_cache_cancellation_token_t);
623+
624+
/// Dispose the cancellation token.
625+
SWIFTSCAN_PUBLIC void swiftscan_cache_cancellation_token_dispose(
626+
swiftscan_cache_cancellation_token_t);
627+
628+
/// Create a swift cached compilation replay instance with its command-line
629+
/// invocation. Return nullptr when errors occurs and the error message is
630+
/// returned via \c error parameter and its caller needs to free the message
631+
/// using `swiftscan_string_dispose`.
632+
SWIFTSCAN_PUBLIC swiftscan_cache_replay_instance_t
633+
swiftscan_cache_create_replay_instance(int argc, const char **argv,
634+
swiftscan_string_ref_t *error);
635+
636+
/// Dispose swift cached compilation replay instance.
637+
SWIFTSCAN_PUBLIC void
638+
swiftscan_cache_replay_instance_dispose(swiftscan_cache_replay_instance_t);
639+
640+
/// Replay the cached compilation using cached compliation replay instance.
641+
/// If the return value is SWIFTSCAN_CACHE_RESULT_ERROR, the error message is
642+
/// returned via \c error parameter and its caller needs to free the message
643+
/// using `swiftscan_string_dispose`.
644+
SWIFTSCAN_PUBLIC swiftscan_cache_result_t swiftscan_cache_replay_compilation(
645+
swiftscan_cas_t cas, swiftscan_cache_replay_instance_t,
646+
swiftscan_cached_compilation_t, swiftscan_string_ref_t *error);
647+
648+
/// Async replay the cached compilation. Callback function will be provided
649+
/// by the cache replay result, and its stdout, stderr, and any error message.
650+
/// \c ctx is an opaque value that passed to the callback and
651+
/// \c swiftscan_cache_cancellation_token_t will return an token that can be
652+
/// used to cancel the async operation. The token needs to be freed by caller
653+
/// using `swiftscan_cache_cancellation_token_dispose`.
654+
SWIFTSCAN_PUBLIC void swiftscan_cache_replay_compilation_async(
655+
swiftscan_cas_t cas, swiftscan_cache_replay_instance_t,
656+
swiftscan_cached_compilation_t, void *ctx,
657+
void (*callback)(void *ctx, swiftscan_cache_result_t,
658+
swiftscan_string_ref_t std_out,
659+
swiftscan_string_ref_t std_err,
660+
swiftscan_string_ref_t error),
661+
swiftscan_cache_cancellation_token_t *);
662+
495663
//===----------------------------------------------------------------------===//
496664

497665
SWIFTSCAN_END_DECLS

lib/DriverTool/swift_cache_tool_main.cpp

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,8 @@ enum class SwiftCacheToolAction {
5050

5151
struct OutputEntry {
5252
std::string InputPath;
53-
std::string OutputPath;
54-
std::string OutputKind;
5553
std::string CacheKey;
54+
std::vector<std::pair<std::string, std::string>> Outputs;
5655
};
5756

5857
enum ID {
@@ -285,44 +284,41 @@ int SwiftCacheToolInvocation::printOutputKeys() {
285284

286285
std::vector<OutputEntry> OutputKeys;
287286
bool hasError = false;
288-
auto addOutputKey = [&](StringRef InputPath, file_types::ID OutputKind,
289-
StringRef OutputPath) {
287+
auto addFromInputFile = [&](const InputFile &Input) {
288+
auto InputPath = Input.getFileName();
290289
auto OutputKey =
291290
createCompileJobCacheKeyForOutput(CAS, *BaseKey, InputPath);
292291
if (!OutputKey) {
293-
llvm::errs() << "cannot create cache key for " << OutputPath << ": "
292+
llvm::errs() << "cannot create cache key for " << InputPath << ": "
294293
<< toString(OutputKey.takeError()) << "\n";
295294
hasError = true;
296295
}
297296
OutputKeys.emplace_back(
298-
OutputEntry{InputPath.str(), OutputPath.str(),
299-
file_types::getTypeName(OutputKind).str(),
300-
CAS.getID(*OutputKey).toString()});
301-
};
302-
auto addFromInputFile = [&](const InputFile &Input) {
303-
auto InputPath = Input.getFileName();
297+
OutputEntry{InputPath, CAS.getID(*OutputKey).toString(), {}});
298+
auto &Outputs = OutputKeys.back().Outputs;
304299
if (!Input.outputFilename().empty())
305-
addOutputKey(InputPath,
306-
Invocation.getFrontendOptions()
307-
.InputsAndOutputs.getPrincipalOutputType(),
308-
Input.outputFilename());
300+
Outputs.emplace_back(file_types::getTypeName(
301+
Invocation.getFrontendOptions()
302+
.InputsAndOutputs.getPrincipalOutputType()),
303+
Input.outputFilename());
309304
Input.getPrimarySpecificPaths()
310305
.SupplementaryOutputs.forEachSetOutputAndType(
311306
[&](const std::string &File, file_types::ID ID) {
312307
// Dont print serialized diagnostics.
313308
if (file_types::isProducedFromDiagnostics(ID))
314309
return;
315-
316-
addOutputKey(InputPath, ID, File);
310+
Outputs.emplace_back(file_types::getTypeName(ID), File);
317311
});
318312
};
319313
llvm::for_each(
320314
Invocation.getFrontendOptions().InputsAndOutputs.getAllInputs(),
321315
addFromInputFile);
322316

323317
// Add diagnostics file.
324-
addOutputKey("<cached-diagnostics>", file_types::ID::TY_CachedDiagnostics,
325-
"<cached-diagnostics>");
318+
if (!OutputKeys.empty())
319+
OutputKeys.front().Outputs.emplace_back(
320+
file_types::getTypeName(file_types::ID::TY_CachedDiagnostics),
321+
"<cached-diagnostics>");
326322

327323
if (hasError)
328324
return 1;
@@ -331,10 +327,16 @@ int SwiftCacheToolInvocation::printOutputKeys() {
331327
Out.array([&] {
332328
for (const auto &E : OutputKeys) {
333329
Out.object([&] {
334-
Out.attribute("OutputPath", E.OutputPath);
335-
Out.attribute("OutputKind", E.OutputKind);
336330
Out.attribute("Input", E.InputPath);
337331
Out.attribute("CacheKey", E.CacheKey);
332+
Out.attributeArray("Outputs", [&] {
333+
for (const auto &OutEntry : E.Outputs) {
334+
Out.object([&] {
335+
Out.attribute("Kind", OutEntry.first);
336+
Out.attribute("Path", OutEntry.second);
337+
});
338+
}
339+
});
338340
});
339341
}
340342
});

lib/Frontend/CASOutputBackends.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ void SwiftCASOutputBackend::Implementation::initBackend(
157157
});
158158
};
159159
llvm::for_each(InputsAndOutputs.getAllInputs(), addInput);
160+
161+
// FIXME: The current diagnostics is associated with the first input file.
162+
OutputToInputMap.insert(
163+
{"<cached-diagnostics>",
164+
{InputsAndOutputs.getAllInputs()[0], file_types::TY_CachedDiagnostics}});
160165
}
161166

162167
Error SwiftCASOutputBackend::Implementation::storeImpl(

lib/Frontend/CachedDiagnostics.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -772,10 +772,13 @@ CachingDiagnosticsProcessor::CachingDiagnosticsProcessor(
772772
}
773773

774774
StringRef Content = Compression.empty() ? Output : toStringRef(Compression);
775-
// Store CachedDiagnostics in the CAS/Cache. There is no real associated
776-
// inputs.
775+
// Store CachedDiagnostics in the CAS/Cache.
776+
// FIXME: Currently, it is associated with first input file.
777777
auto Err = Instance.getCASOutputBackend().storeCachedDiagnostics(
778-
"<cached-diagnostics>", Content);
778+
Instance.getInvocation()
779+
.getFrontendOptions()
780+
.InputsAndOutputs.getFilenameOfFirstInput(),
781+
Content);
779782

780783
if (Err) {
781784
Instance.getDiags().diagnose(SourceLoc(), diag::error_cas,

lib/Frontend/CachingUtils.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -209,19 +209,15 @@ bool replayCachedCompilerOutputs(
209209
Outputs.try_emplace(ID, File);
210210
});
211211

212-
// Nothing to replay.
213-
if (Outputs.empty())
214-
return;
212+
// Add cached diagnostic entry for lookup. Output path doesn't matter here.
213+
Outputs.try_emplace(file_types::ID::TY_CachedDiagnostics,
214+
"<cached-diagnostics>");
215215

216216
return replayOutputsForInputFile(InputPath, Outputs);
217217
};
218218

219219
llvm::for_each(InputsAndOutputs.getAllInputs(), replayOutputFromInput);
220220

221-
replayOutputsForInputFile(
222-
"<cached-diagnostics>",
223-
{{file_types::ID::TY_CachedDiagnostics, "<cached-diagnostics>"}});
224-
225221
if (!CanReplayAllOutput)
226222
return false;
227223

lib/FrontendTool/FrontendTool.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2107,9 +2107,8 @@ class PrettyStackTraceFrontend : public llvm::PrettyStackTraceEntry {
21072107
};
21082108
};
21092109

2110-
int swift::performFrontend(ArrayRef<const char *> Args,
2111-
const char *Argv0, void *MainAddr,
2112-
FrontendObserver *observer) {
2110+
int swift::performFrontend(ArrayRef<const char *> Args, const char *Argv0,
2111+
void *MainAddr, FrontendObserver *observer) {
21132112
INITIALIZE_LLVM();
21142113
llvm::setBugReportMsg(SWIFT_CRASH_BUG_REPORT_MESSAGE "\n");
21152114
llvm::EnablePrettyStackTraceOnSigInfoForThisThread();

test/CAS/Inputs/ExtractOutputKey.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010

1111

1212
with open(input_json, 'r') as file:
13-
outputs = json.load(file)
14-
for output in outputs:
15-
if output['OutputPath'] != output_path:
16-
continue
17-
print(output['CacheKey'])
13+
entries = json.load(file)
14+
for entry in entries:
15+
for output in entry["Outputs"]:
16+
if output['Path'] != output_path:
17+
continue
18+
print(entry['CacheKey'])

0 commit comments

Comments
 (0)