Skip to content

Commit ef24432

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 ef24432

File tree

10 files changed

+1435
-154
lines changed

10 files changed

+1435
-154
lines changed

include/swift-c/DependencyScan/DependencyScan.h

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

@@ -472,16 +518,16 @@ swiftscan_cas_options_set_option(swiftscan_cas_options_t options,
472518
SWIFTSCAN_PUBLIC swiftscan_cas_t swiftscan_cas_create_from_options(
473519
swiftscan_cas_options_t options, swiftscan_string_ref_t *error);
474520

475-
/// Dispose the \c cas instance.
476-
SWIFTSCAN_PUBLIC void swiftscan_cas_dispose(swiftscan_cas_t cas);
477-
478521
/// Store content into CAS. Return \c CASID as string. Return NULL on error.
479522
/// If error happens, the error message is returned via `error` parameter, and
480523
/// caller needs to free the error message via `swiftscan_string_dispose`.
481524
SWIFTSCAN_PUBLIC swiftscan_string_ref_t
482525
swiftscan_cas_store(swiftscan_cas_t cas, uint8_t *data, unsigned size,
483526
swiftscan_string_ref_t *error);
484527

528+
/// Dispose the \c cas instance.
529+
SWIFTSCAN_PUBLIC void swiftscan_cas_dispose(swiftscan_cas_t cas);
530+
485531
/// Compute \c CacheKey for the outputs of a primary input file from a compiler
486532
/// invocation with command-line \c argc and \c argv. When primary input file
487533
/// is not available for compilation, e.g., using WMO, primary file is the first
@@ -492,6 +538,151 @@ SWIFTSCAN_PUBLIC swiftscan_string_ref_t
492538
swiftscan_cache_compute_key(swiftscan_cas_t cas, int argc, const char **argv,
493539
const char *input, swiftscan_string_ref_t *error);
494540

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

497688
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)