Skip to content

Commit b8f5226

Browse files
[Caching] Add new CacheReplay APIs to libSwiftScan
Add new APIs libSwiftScan that can be used for cache query and cache replay. This enables swift-driver or build system to query the cache and replay the compilation results without invocation swift-frontend for better scheduling.
1 parent 30cfa3d commit b8f5226

File tree

10 files changed

+1435
-154
lines changed

10 files changed

+1435
-154
lines changed

include/swift-c/DependencyScan/DependencyScan.h

Lines changed: 196 additions & 4 deletions
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,53 @@ 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 container for a cached compilation output.
448+
typedef struct swiftscan_cached_output_s *swiftscan_cached_output_t;
449+
450+
/// Opaque type for a cache replay instance.
451+
typedef struct swiftscan_cache_replay_instance_s
452+
*swiftscan_cache_replay_instance_t;
453+
454+
/// Opaque container for a cached compilation replay result.
455+
typedef struct swiftscan_cache_replay_result_s
456+
*swiftscan_cache_replay_result_t;
457+
458+
/// Opaque type for a cancellation token for async cache operations.
459+
typedef struct swiftscan_cache_cancellation_token_s
460+
*swiftscan_cache_cancellation_token_t;
461+
462+
/// Enum types for output types for cache key computation.
463+
/// List should contain all the output file types, including supplemententary
464+
/// outputs, except diagnostics outputs, which are covered by cached diagnostic
465+
/// entry.
466+
typedef enum {
467+
SWIFTSCAN_OUTPUT_TYPE_OBJECT = 0,
468+
SWIFTSCAN_OUTPUT_TYPE_SWIFTMODULE = 1,
469+
SWIFTSCAN_OUTPUT_TYPE_SWIFTINTERFACE = 2,
470+
SWIFTSCAN_OUTPUT_TYPE_SWIFTPRIVATEINTERFACE = 3,
471+
SWIFTSCAN_OUTPUT_TYPE_CLANG_MODULE = 4,
472+
SWIFTSCAN_OUTPUT_TYPE_CLANG_PCH = 5,
473+
SWIFTSCAN_OUTPUT_TYPE_CLANG_HEADER = 6,
474+
SWIFTSCAN_OUTPUT_TYPE_SWIFT_SOURCE_INFO = 7,
475+
SWIFTSCAN_OUTPUT_TYPE_SWIFT_MODULE_DOC = 8,
476+
SWIFTSCAN_OUTPUT_TYPE_DEPENDENCIES = 9,
477+
SWIFTSCAN_OUTPUT_TYPE_SWIFT_DEPS = 10,
478+
SWIFTSCAN_OUTPUT_TYPE_MODULE_TRACE = 11,
479+
SWIFTSCAN_OUTPUT_TYPE_TBD = 12,
480+
SWIFTSCAN_OUTPUT_TYPE_SWIFT_MODULE_SUMMARY = 13,
481+
SWIFTSCAN_OUTPUT_TYPE_SWIFT_ABI_DESCRIPTOR = 14,
482+
SWIFTSCAN_OUTPUT_TYPE_SWIFT_API_DESCRIPTOR = 15,
483+
SWIFTSCAN_OUTPUT_TYPE_CONST_VALUE = 16,
484+
SWIFTSCAN_OUTPUT_TYPE_MODULE_SEMANTIC_INFO = 17,
485+
SWIFTSCAN_OUTPUT_TYPE_YAML_OPT_RECORD = 18,
486+
SWIFTSCAN_OUTPUT_TYPE_BITSTREAM_OPT_RECORD = 19,
487+
SWIFTSCAN_OUTPUT_TYPE_CACHED_DIAGNOSTICS = 20,
488+
SWIFTSCAN_OUTPUT_TYPE_LAST = SWIFTSCAN_OUTPUT_TYPE_CACHED_DIAGNOSTICS
489+
} swiftscan_output_kind_t;
490+
444491
/// Create a \c CASOptions for creating CAS inside scanner specified.
445492
SWIFTSCAN_PUBLIC swiftscan_cas_options_t swiftscan_cas_options_create(void);
446493

@@ -472,16 +519,16 @@ swiftscan_cas_options_set_option(swiftscan_cas_options_t options,
472519
SWIFTSCAN_PUBLIC swiftscan_cas_t swiftscan_cas_create_from_options(
473520
swiftscan_cas_options_t options, swiftscan_string_ref_t *error);
474521

475-
/// Dispose the \c cas instance.
476-
SWIFTSCAN_PUBLIC void swiftscan_cas_dispose(swiftscan_cas_t cas);
477-
478522
/// Store content into CAS. Return \c CASID as string. Return NULL on error.
479523
/// If error happens, the error message is returned via `error` parameter, and
480524
/// caller needs to free the error message via `swiftscan_string_dispose`.
481525
SWIFTSCAN_PUBLIC swiftscan_string_ref_t
482526
swiftscan_cas_store(swiftscan_cas_t cas, uint8_t *data, unsigned size,
483527
swiftscan_string_ref_t *error);
484528

529+
/// Dispose the \c cas instance.
530+
SWIFTSCAN_PUBLIC void swiftscan_cas_dispose(swiftscan_cas_t cas);
531+
485532
/// Compute \c CacheKey for the outputs of a primary input file from a compiler
486533
/// invocation with command-line \c argc and \c argv. When primary input file
487534
/// is not available for compilation, e.g., using WMO, primary file is the first
@@ -492,6 +539,151 @@ SWIFTSCAN_PUBLIC swiftscan_string_ref_t
492539
swiftscan_cache_compute_key(swiftscan_cas_t cas, int argc, const char **argv,
493540
const char *input, swiftscan_string_ref_t *error);
494541

542+
/// Query the result of the compilation using the output cache key. \c globally
543+
/// suggests if the lookup should check remote cache if such operation exists.
544+
/// Returns the cached compilation of the result if found, or nullptr if output
545+
/// is not found or an error occurs. When an error occurs, the error message is
546+
/// returned via \c error parameter and its caller needs to free the message
547+
/// using `swiftscan_string_dispose`. The returned cached compilation needs to
548+
/// be freed via `swiftscan_cached_compilation_dispose`.
549+
SWIFTSCAN_PUBLIC swiftscan_cached_compilation_t
550+
swiftscan_cache_query(swiftscan_cas_t cas, const char *key, bool globally,
551+
swiftscan_string_ref_t *error);
552+
553+
/// Async version of `swiftscan_cache_query` where result is returned via
554+
/// callback. Both cache_result enum and cached compilation will be provided to
555+
/// callback. \c ctx is an opaque value that passed to the callback and \c
556+
/// swiftscan_cache_cancellation_token_t will return an token that can be used
557+
/// to cancel the async operation. The token needs to be freed by caller using
558+
/// `swiftscan_cache_cancellation_token_dispose`.
559+
SWIFTSCAN_PUBLIC void swiftscan_cache_query_async(
560+
swiftscan_cas_t cas, const char *key, bool globally, void *ctx,
561+
void (*callback)(void *ctx, swiftscan_cached_compilation_t,
562+
swiftscan_string_ref_t error),
563+
swiftscan_cache_cancellation_token_t *);
564+
565+
/// Query the number of outputs from a cached compilation.
566+
SWIFTSCAN_PUBLIC unsigned swiftscan_cached_compilation_get_num_outputs(
567+
swiftscan_cached_compilation_t);
568+
569+
/// Get the output kind for the given index in the cached compilation.
570+
SWIFTSCAN_PUBLIC swiftscan_output_kind_t
571+
swiftscan_cached_compilation_get_output_kind(swiftscan_cached_compilation_t,
572+
unsigned idx);
573+
574+
/// Get the cached output for the given index in the cached compilation.
575+
SWIFTSCAN_PUBLIC swiftscan_cached_output_t
576+
swiftscan_cached_compilation_get_output(swiftscan_cached_compilation_t,
577+
unsigned idx);
578+
579+
/// Make the cache compilation available globally. \c callback will be called
580+
/// on completion.
581+
/// \c swiftscan_cache_cancellation_token_t will return an token that can be
582+
/// used to cancel the async operation. The token needs to be freed by caller
583+
/// using `swiftscan_cache_cancellation_token_dispose`.
584+
SWIFTSCAN_PUBLIC void swiftscan_cached_compilation_make_global_async(
585+
swiftscan_cas_t cas, swiftscan_cached_compilation_t, void *ctx,
586+
void (*callback)(void *ctx, swiftscan_string_ref_t error),
587+
swiftscan_cache_cancellation_token_t *);
588+
589+
/// Dispose a cached compilation.
590+
SWIFTSCAN_PUBLIC
591+
void swiftscan_cached_compilation_dispose(swiftscan_cached_compilation_t);
592+
593+
/// Download and materialize the cached output if needed from a remote CAS.
594+
/// Return true if load is successful, else false if not found or error. If
595+
/// error, the error message is returned via \c error parameter and its caller
596+
/// needs to free the message using `swiftscan_string_dispose`.
597+
SWIFTSCAN_PUBLIC bool
598+
swiftscan_cached_output_load(swiftscan_cas_t cas, swiftscan_cached_output_t,
599+
swiftscan_string_ref_t *error);
600+
601+
/// Async version of `swiftscan_cached_output_load` where result is
602+
/// returned via callback. \c ctx is an opaque value that passed to the callback
603+
/// and \c swiftscan_cache_cancellation_token_t will return an token that can be
604+
/// used to cancel the async operation. The token needs to be freed by caller
605+
/// using `swiftscan_cache_cancellation_token_dispose`.
606+
SWIFTSCAN_PUBLIC void swiftscan_cached_output_load_async(
607+
swiftscan_cas_t cas, swiftscan_cached_output_t, void *ctx,
608+
void (*callback)(void *ctx, bool success, swiftscan_string_ref_t error),
609+
swiftscan_cache_cancellation_token_t *);
610+
611+
/// Check if cached output is materialized locally and can be accessed
612+
/// without downloading.
613+
SWIFTSCAN_PUBLIC bool
614+
swiftscan_cached_output_is_materialized(swiftscan_cas_t,
615+
swiftscan_cached_output_t);
616+
617+
/// Dispose a cached output.
618+
SWIFTSCAN_PUBLIC
619+
void swiftscan_cached_output_dispose(swiftscan_cached_output_t);
620+
621+
/// Cancel the async cache action that is associated with token.
622+
SWIFTSCAN_PUBLIC void
623+
swiftscan_cache_action_cancel(swiftscan_cache_cancellation_token_t);
624+
625+
/// Dispose the cancellation token.
626+
SWIFTSCAN_PUBLIC void swiftscan_cache_cancellation_token_dispose(
627+
swiftscan_cache_cancellation_token_t);
628+
629+
/// Create a swift cached compilation replay instance with its command-line
630+
/// invocation. Return nullptr when errors occurs and the error message is
631+
/// returned via \c error parameter and its caller needs to free the message
632+
/// using `swiftscan_string_dispose`.
633+
SWIFTSCAN_PUBLIC swiftscan_cache_replay_instance_t
634+
swiftscan_cache_replay_instance_create(int argc, const char **argv,
635+
swiftscan_string_ref_t *error);
636+
637+
/// Dispose swift cached compilation replay instance.
638+
SWIFTSCAN_PUBLIC void
639+
swiftscan_cache_replay_instance_dispose(swiftscan_cache_replay_instance_t);
640+
641+
/// Replay the cached compilation using cached compliation replay instance.
642+
/// Returns replay result or nullptr if output not found or error occurs. If
643+
/// error, the error message is returned via \c error parameter and its caller
644+
/// needs to free the message using `swiftscan_string_dispose`.
645+
SWIFTSCAN_PUBLIC swiftscan_cache_replay_result_t
646+
swiftscan_cache_replay_compilation(swiftscan_cas_t cas,
647+
swiftscan_cache_replay_instance_t,
648+
swiftscan_cached_compilation_t,
649+
swiftscan_string_ref_t *error);
650+
651+
/// Async replay the cached compilation. Callback function will be provided
652+
/// by the cache replay result, and its stdout, stderr, and any error message.
653+
/// \c ctx is an opaque value that passed to the callback and
654+
/// \c swiftscan_cache_cancellation_token_t will return an token that can be
655+
/// used to cancel the async operation. The token needs to be freed by caller
656+
/// using `swiftscan_cache_cancellation_token_dispose`.
657+
SWIFTSCAN_PUBLIC void swiftscan_cache_replay_compilation_async(
658+
swiftscan_cas_t cas, swiftscan_cache_replay_instance_t,
659+
swiftscan_cached_compilation_t, void *ctx,
660+
void (*callback)(void *ctx, swiftscan_cache_replay_result_t,
661+
swiftscan_string_ref_t error),
662+
swiftscan_cache_cancellation_token_t *);
663+
664+
/// Get return code from replay. Return code is 0 for success, and a non-zero
665+
/// value for failure.
666+
/// FIXME: This should match the return code from `swift-frontend` invocation.
667+
SWIFTSCAN_PUBLIC
668+
unsigned swiftscan_cache_replay_result_get_return_code(
669+
swiftscan_cache_replay_result_t);
670+
671+
/// Get stdout from cached replay result. The returning swiftscan_string_ref_t
672+
/// is owned by replay result and should not be disposed.
673+
SWIFTSCAN_PUBLIC
674+
swiftscan_string_ref_t
675+
swiftscan_cache_replay_result_get_stdout(swiftscan_cache_replay_result_t);
676+
677+
/// Get stderr from cached replay result. The returning swiftscan_string_ref_t
678+
/// is owned by replay result and should not be disposed.
679+
SWIFTSCAN_PUBLIC
680+
swiftscan_string_ref_t
681+
swiftscan_cache_replay_result_get_stderr(swiftscan_cache_replay_result_t);
682+
683+
/// Dispose a cached replay result.
684+
SWIFTSCAN_PUBLIC
685+
void swiftscan_cache_replay_result_dispose(swiftscan_cache_replay_result_t);
686+
495687
//===----------------------------------------------------------------------===//
496688

497689
SWIFTSCAN_END_DECLS

test/CAS/swift-scan-test.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %swift-scan-test -action compute_cache_key -cas-path %t/cas -input %s -- %target-swift-frontend -cache-compile-job -Rcache-compile-job %s \
4+
// RUN: -emit-module -emit-module-path %t/Test.swiftmodule -c -emit-dependencies -module-name Test -o %t/test.o -cas-path %t/cas \
5+
// RUN: -allow-unstable-cache-key-for-testing > %t/key.casid
6+
7+
// RUN: not %swift-scan-test -action cache_query -id @%t/key.casid -cas-path %t/cas 2>&1 | %FileCheck %s --check-prefix=CHECK-QUERY-NOT-FOUND
8+
9+
// RUN: %target-swift-frontend -cache-compile-job -Rcache-compile-job %s -emit-module -emit-module-path %t/Test.swiftmodule -c -emit-dependencies \
10+
// RUN: -module-name Test -o %t/test.o -cas-path %t/cas -allow-unstable-cache-key-for-testing
11+
12+
// RUN: %swift-scan-test -action cache_query -id @%t/key.casid -cas-path %t/cas | %FileCheck %s --check-prefix=CHECK-QUERY
13+
14+
// RUN: %swift-scan-test -action replay_result -cas-path %t/cas -id @%t/key.casid -- %target-swift-frontend -cache-compile-job -Rcache-compile-job %s \
15+
// RUN: -emit-module -emit-module-path %t/Test2.swiftmodule -c -emit-dependencies -module-name Test -o %t/test2.o -cas-path %t/cas \
16+
// RUN: -allow-unstable-cache-key-for-testing
17+
18+
// RUN: diff %t/Test.swiftmodule %t/Test2.swiftmodule
19+
// RUN: diff %t/test.o %t/test.o
20+
21+
// CHECK-QUERY-NOT-FOUND: cached output not found
22+
// CHECK-QUERY: Cached Compilation for key "llvmcas://{{.*}}" has 4 outputs: (object) (dependencies) (swiftmodule) (cached-diagnostics)
23+
24+
func testFunc() {}

test/lit.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ config.benchmark_driver = inferSwiftBinary('Benchmark_Driver')
346346
config.wasm_ld = inferSwiftBinary('wasm-ld')
347347
config.swift_plugin_server = inferSwiftBinary('swift-plugin-server')
348348
config.swift_parse_test = inferSwiftBinary('swift-parse-test')
349+
config.swift_scan_test = inferSwiftBinary('swift-scan-test')
349350

350351
config.swift_utils = make_path(config.swift_src_root, 'utils')
351352
config.line_directive = make_path(config.swift_utils, 'line-directive')
@@ -638,6 +639,7 @@ config.substitutions.append( ('%target-ptrauth', run_ptrauth ) )
638639
config.substitutions.append( ('%swift-path', config.swift) )
639640
config.substitutions.append( ('%swift-plugin-server', config.swift_plugin_server) )
640641
config.substitutions.append( ('%swift-parse-test', config.swift_parse_test) )
642+
config.substitutions.append( ('%swift-scan-test', config.swift_scan_test) )
641643
config.substitutions.append( ('%validate-json', f"{config.python} -m json.tool") )
642644

643645
# This must come after all substitutions containing "%swift".

tools/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ add_swift_tool_subdirectory(libSwiftScan)
2828
add_swift_tool_subdirectory(libStaticMirror)
2929
add_swift_tool_subdirectory(libMockPlugin)
3030
add_swift_tool_subdirectory(swift-plugin-server)
31+
add_swift_tool_subdirectory(swift-scan-test)
3132

3233
if(SWIFT_INCLUDE_TESTS OR SWIFT_INCLUDE_TEST_BINARIES)
3334
add_swift_tool_subdirectory(swift-ide-test)

tools/libSwiftScan/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ set(LLVM_EXPORTED_SYMBOL_FILE
77
add_swift_host_library(libSwiftScan SHARED
88
libSwiftScan.cpp
99
c-include-check.c
10+
SwiftCaching.cpp
1011
HAS_SWIFT_MODULES)
1112

1213
if(SWIFT_HOST_VARIANT_SDK IN_LIST SWIFT_DARWIN_PLATFORMS)

0 commit comments

Comments
 (0)