├── runtime ├── .gitignore ├── pedigree_globals.cpp ├── init.h ├── local-reducer-api.h ├── worker_coord.h ├── scheduler.h ├── local.h ├── efficiency.h ├── hyperobject_base.h ├── personality-cpp.cpp ├── personality-c.c ├── internal-malloc-impl.h ├── worker.h ├── cilk2c.h ├── fiber-header.h ├── mutex.h ├── jmpbuf.h ├── pedigree_ext.cpp ├── Makefile ├── pedigree-internal.h ├── internal-malloc.h ├── local-reducer-api.cpp ├── rts-config.h ├── pedigree_lib.cpp ├── sched_stats.h ├── closure.h ├── cilk2c_inlined.h ├── cilk-internal.h ├── frame.h ├── fiber.h ├── debug.h ├── cilk2c.cpp └── readydeque.h ├── handcomp_test ├── ZERO.c ├── getoptions.h ├── Makefile ├── ktiming.h ├── fib.cpp ├── getoptions.cpp ├── ktiming.cpp ├── nqueens.cpp └── mm_dac.cpp ├── android ├── jni │ ├── Android.mk │ ├── Application.mk │ ├── libopencilk.mk │ └── libopencilk-abi.mk └── README.md ├── .clang-format ├── include ├── cilk │ ├── cilk_stub.h │ ├── cilk.h │ ├── opadd_reducer.h │ ├── holder.h │ ├── reducer │ ├── cilk_api.h │ └── ostream_reducer.h └── CMakeLists.txt ├── .gitignore ├── unittests ├── mock-local-hypertable-hash.h ├── mock-worker.c ├── mock-local-hypertable-old-hash.h ├── Makefile ├── test-old-hash-hypertable.c ├── test-hypertable-common.h └── test-hypertable.c ├── cmake ├── LLVMCommonModules │ ├── SetPlatformToolchainTools.cmake │ ├── CMakePolicy.cmake │ ├── EnableLanguageNolink.cmake │ ├── SortSubset.cmake │ ├── ExtendPath.cmake │ ├── LLVMCheckCompilerLinkerFlag.cmake │ ├── GNUInstallPackageDir.cmake │ ├── FindPrefixFromConfig.cmake │ ├── FindLibEdit.cmake │ ├── HandleOutOfTreeLLVM.cmake │ ├── HandleCompilerRT.cmake │ └── FindGRPC.cmake ├── CilkThreadsConfig.cmake.in └── Modules │ ├── AllSupportedArchDefs.cmake │ ├── MacroEnsureOutOfSourceBuild.cmake │ ├── HandleCompilerRT.cmake │ ├── CheetahMockLLVMCMakeConfig.cmake │ ├── CheetahTests.cmake │ └── HandleCheetahFlags.cmake ├── Makefile ├── config.mk ├── LICENSE.TXT ├── .github └── workflows │ ├── handcomp-tests.yml │ └── small-cilkapps.yml ├── README.md └── doc └── REDUCER_PROTOCOL /runtime/.gitignore: -------------------------------------------------------------------------------- 1 | TAGS 2 | -------------------------------------------------------------------------------- /handcomp_test/ZERO.c: -------------------------------------------------------------------------------- 1 | #include 2 | size_t ZERO = 0; 3 | -------------------------------------------------------------------------------- /android/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(LOCAL_PATH)/libopencilk.mk 4 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | IndentWidth: 4 3 | ColumnLimit: 80 4 | UseTab: Never 5 | BreakBeforeBraces: Attach 6 | -------------------------------------------------------------------------------- /android/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := arm64-v8a x86_64 2 | 3 | APP_CFLAGS := \ 4 | -Wall \ 5 | -Werror \ 6 | -Wno-format 7 | 8 | APP_PLATFORM := android-28 -------------------------------------------------------------------------------- /include/cilk/cilk_stub.h: -------------------------------------------------------------------------------- 1 | #define cilk_for for 2 | #define cilk_spawn /* empty */ 3 | #define cilk_sync /* empty */ 4 | #define cilk_scope /* empty */ 5 | 6 | #define cilk_reducer(I,R) /* empty */ 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Exes 2 | handcomp_test/* 3 | !handcomp_test/*.* 4 | 5 | # Emacs backups 6 | *~ 7 | \#*# 8 | 9 | # Compilations 10 | *.o 11 | *.a 12 | 13 | # lib 14 | *.a 15 | *.so 16 | *.so.* 17 | -------------------------------------------------------------------------------- /runtime/pedigree_globals.cpp: -------------------------------------------------------------------------------- 1 | #include "pedigree-internal.h" 2 | 3 | // This variable needs to be accessed both from the external pedigree library 4 | // and the pedigree-extension code in the core runtime library. 5 | uint64_t *__pedigree_dprng_m_array = nullptr; 6 | -------------------------------------------------------------------------------- /include/cilk/cilk.h: -------------------------------------------------------------------------------- 1 | #ifndef _CILK_H 2 | #define _CILK_H 3 | 4 | #define cilk_spawn _Cilk_spawn 5 | #define cilk_sync _Cilk_sync 6 | #define cilk_for _Cilk_for 7 | #define cilk_scope _Cilk_scope 8 | 9 | #define cilk_reducer _Hyperobject 10 | 11 | #endif /* _CILK_H */ 12 | -------------------------------------------------------------------------------- /unittests/mock-local-hypertable-hash.h: -------------------------------------------------------------------------------- 1 | // Data type for indexing the hash table. This type is used for 2 | // hashes as well as the table's capacity. 3 | static const int32_t MIN_CAPACITY = 1; 4 | static const int32_t MIN_HT_CAPACITY = 1; 5 | 6 | // Mock hash function for unit-testing the logic behind local hypertables. 7 | static inline index_t hash(uintptr_t key_in) { 8 | return key_in; 9 | } 10 | -------------------------------------------------------------------------------- /unittests/mock-worker.c: -------------------------------------------------------------------------------- 1 | #include "../runtime/cilk-internal.h" 2 | #include "../runtime/global.h" 3 | 4 | __cilkrts_worker default_worker = { 5 | .self = 0, 6 | .hyper_table = NULL, 7 | .g = NULL, 8 | .l = NULL, 9 | .extension = NULL, 10 | .ext_stack = NULL, 11 | .tail = NULL, 12 | .exc = NULL, 13 | .head = NULL, 14 | .ltq_limit = NULL}; 15 | 16 | __thread __cilkrts_worker *__cilkrts_tls_worker = &default_worker; -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/SetPlatformToolchainTools.cmake: -------------------------------------------------------------------------------- 1 | get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) 2 | 3 | if(CMAKE_SYSTEM_NAME MATCHES "AIX") 4 | foreach(lang IN LISTS languages) 5 | set(CMAKE_${lang}_ARCHIVE_CREATE " -X32_64 qc ") 6 | set(CMAKE_${lang}_ARCHIVE_APPEND " -X32_64 q ") 7 | set(CMAKE_${lang}_ARCHIVE_FINISH " -X32_64 ") 8 | endforeach() 9 | endif() 10 | -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/CMakePolicy.cmake: -------------------------------------------------------------------------------- 1 | # CMake policy settings shared between LLVM projects 2 | 3 | # CMP0114: ExternalProject step targets fully adopt their steps. 4 | # New in CMake 3.19: https://cmake.org/cmake/help/latest/policy/CMP0114.html 5 | if(POLICY CMP0114) 6 | cmake_policy(SET CMP0114 OLD) 7 | endif() 8 | # CMP0116: Ninja generators transform `DEPFILE`s from `add_custom_command()` 9 | # New in CMake 3.20. https://cmake.org/cmake/help/latest/policy/CMP0116.html 10 | if(POLICY CMP0116) 11 | cmake_policy(SET CMP0116 OLD) 12 | endif() 13 | -------------------------------------------------------------------------------- /include/cilk/opadd_reducer.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPADD_REDUCER_H 2 | #define _OPADD_REDUCER_H 3 | 4 | #ifdef __cplusplus 5 | 6 | namespace cilk { 7 | 8 | template static void zero(void *v) { 9 | *static_cast(v) = static_cast(0); 10 | } 11 | 12 | template static void plus(void *l, void *r) { 13 | *static_cast(l) += *static_cast(r); 14 | } 15 | 16 | template using opadd_reducer = T _Hyperobject(zero, plus); 17 | 18 | } // namespace cilk 19 | 20 | #endif // #ifdef __cplusplus 21 | 22 | #endif // _OPADD_REDUCER_H 23 | -------------------------------------------------------------------------------- /include/cilk/holder.h: -------------------------------------------------------------------------------- 1 | #ifndef _HOLDER_H 2 | #define _HOLDER_H 3 | 4 | #ifdef __cplusplus 5 | 6 | #include 7 | 8 | namespace cilk { 9 | 10 | template static void init(void *view) { 11 | new(view) A; 12 | } 13 | template static void reduce(void *left, void *right) { 14 | if (std::is_destructible::value) 15 | static_cast(right)->~A(); 16 | } 17 | 18 | template 19 | using holder = A _Hyperobject(init, reduce); 20 | 21 | } // namespace cilk 22 | 23 | #endif // __cplusplus 24 | 25 | #endif // _HOLDER_H 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | $(MAKE) -C runtime 3 | $(MAKE) -C handcomp_test 4 | if [ -d bench ]; then $(MAKE) -C bench; fi 5 | if [ -d reducer_bench ]; then $(MAKE) -C reducer_bench; fi 6 | 7 | clean: 8 | $(MAKE) -C runtime clean 9 | $(MAKE) -C handcomp_test clean 10 | if [ -d bench ]; then $(MAKE) -C bench clean; fi 11 | if [ -d reducer_bench ]; then $(MAKE) -C reducer_bench clean; fi 12 | 13 | rebuild: clean all 14 | 15 | check: 16 | if [ -d bench ]; then $(MAKE) -C bench test; fi 17 | $(MAKE) -C handcomp_test check 18 | if [ -d reducer_bench ]; then $(MAKE) -C reducer_bench check; fi 19 | -------------------------------------------------------------------------------- /cmake/CilkThreadsConfig.cmake.in: -------------------------------------------------------------------------------- 1 | add_library(CilkThreads::Threads INTERFACE IMPORTED) 2 | set_property(TARGET CilkThreads::Threads PROPERTY INTERFACE_LINK_LIBRARIES "-lopencilk -lopencilk-personality-cpp -L@CHEETAH_LIBRARY_DIR@@CHEETHA_LIBRARY_HOST@") 3 | set_property(TARGET CilkThreads::Threads 4 | PROPERTY INTERFACE_COMPILE_OPTIONS "$<$:SHELL:-Xcompiler -lopencilk -lopencilk-personality-cpp -L@CHEETAH_LIBRARY_DIR@@CHEETHA_LIBRARY_HOST@>" 5 | "$<$>:-lopencilk -lopencilk-personality-cpp -L@CHEETAH_LIBRARY_DIR@@CHEETHA_LIBRARY_HOST@>") 6 | -------------------------------------------------------------------------------- /cmake/Modules/AllSupportedArchDefs.cmake: -------------------------------------------------------------------------------- 1 | set(ARM64 aarch64) 2 | set(ARM32 arm armhf) 3 | set(HEXAGON hexagon) 4 | set(X86 i386) 5 | set(X86_64 x86_64) 6 | set(MIPS32 mips mipsel) 7 | set(MIPS64 mips64 mips64el) 8 | set(PPC64 powerpc64 powerpc64le) 9 | set(RISCV32 riscv32) 10 | set(RISCV64 riscv64) 11 | set(S390X s390x) 12 | set(SPARC sparc) 13 | set(SPARCV9 sparcv9) 14 | set(WASM32 wasm32) 15 | set(WASM64 wasm64) 16 | 17 | if(APPLE) 18 | set(ARM64 arm64) 19 | set(ARM32 armv7 armv7s armv7k) 20 | set(X86_64 x86_64 x86_64h) 21 | endif() 22 | 23 | set(ALL_CHEETAH_SUPPORTED_ARCH ${X86_64} ${ARM64}) 24 | -------------------------------------------------------------------------------- /runtime/init.h: -------------------------------------------------------------------------------- 1 | #ifndef _CILK_INIT_H 2 | #define _CILK_INIT_H 3 | 4 | #include "cilk-internal.h" 5 | 6 | // For invoke, the global state is implied. 7 | // Exceptions never escape invoke but may escape exit. 8 | CHEETAH_API 9 | void __cilkrts_internal_invoke_cilkified_root(__cilkrts_stack_frame *sf) 10 | __CILKRTS_NOTHROW; 11 | CHEETAH_API 12 | void __cilkrts_internal_exit_cilkified_root(global_state *g, __cilkrts_stack_frame *sf); 13 | 14 | // Used by Cilksan to set nworkers to 1 and force reduction 15 | extern "C" 16 | void __cilkrts_internal_set_nworkers(unsigned int nworkers); 17 | 18 | #endif /* _CILK_INIT_H */ 19 | -------------------------------------------------------------------------------- /unittests/mock-local-hypertable-old-hash.h: -------------------------------------------------------------------------------- 1 | // Data type for indexing the hash table. This type is used for 2 | // hashes as well as the table's capacity. 3 | static const int32_t MIN_CAPACITY = 1; 4 | static const int32_t MIN_HT_CAPACITY = 1; 5 | 6 | static const uint64_t salt = 0x96b9af4f6a40de92UL; 7 | 8 | // Mock hash function for unit-testing the logic of local hypertables. 9 | static inline index_t hash(uintptr_t key_in) { 10 | uint64_t x = key_in ^ salt; 11 | // mix64 from SplitMix. 12 | x = (x ^ (x >> 33)) * 0xff51afd7ed558ccdUL; 13 | x = (x ^ (x >> 33)) * 0xc4ceb9fe1a85ec53UL; 14 | return x; 15 | } 16 | -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/EnableLanguageNolink.cmake: -------------------------------------------------------------------------------- 1 | macro(llvm_enable_language_nolink) 2 | # Set CMAKE_TRY_COMPILE_TARGET_TYPE to STATIC_LIBRARY to disable linking 3 | # in the compiler sanity checks. When bootstrapping the toolchain, 4 | # the toolchain itself is still incomplete and sanity checks that include 5 | # linking may fail. 6 | set(__SAVED_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE}) 7 | set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) 8 | enable_language(${ARGV}) 9 | set(CMAKE_TRY_COMPILE_TARGET_TYPE ${__SAVED_TRY_COMPILE_TARGET_TYPE}) 10 | unset(__SAVED_TRY_COMPILE_TARGET_TYPE) 11 | endmacro() 12 | -------------------------------------------------------------------------------- /unittests/Makefile: -------------------------------------------------------------------------------- 1 | TESTS = test-hypertable test-old-hash-hypertable 2 | 3 | .PHONY: clean 4 | 5 | all : $(TESTS) 6 | 7 | # Hypertable tests 8 | 9 | HYPERTABLE_SOURCES=../runtime/local-hypertable.c ../runtime/debug.c mock-worker.c 10 | %-hypertable : %-hypertable.c $(HYPERTABLE_SOURCES) test-hypertable-common.h 11 | $(CC) -o $@ $< $(HYPERTABLE_SOURCES) $(CFLAGS) $(MOCK_HASH_FLAG) -I./ $(LDFLAGS) $(LDLIBS) 12 | 13 | test-hypertable : mock-local-hypertable-hash.h 14 | test-hypertable : MOCK_HASH_FLAG = -DMOCK_HASH="\"mock-local-hypertable-hash.h\"" 15 | test-old-hash-hypertable : mock-local-hypertable-old-hash.h 16 | test-old-hash-hypertable : MOCK_HASH_FLAG = -DMOCK_HASH="\"mock-local-hypertable-old-hash.h\"" 17 | 18 | clean: 19 | rm -rf $(TESTS) *~ *.o 20 | -------------------------------------------------------------------------------- /cmake/Modules/MacroEnsureOutOfSourceBuild.cmake: -------------------------------------------------------------------------------- 1 | # MACRO_ENSURE_OUT_OF_SOURCE_BUILD() 2 | 3 | macro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage ) 4 | 5 | string( COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource ) 6 | if( _insource ) 7 | message( SEND_ERROR "${_errorMessage}" ) 8 | message( FATAL_ERROR 9 | "In-source builds are not allowed. 10 | CMake would overwrite the makefiles distributed with cheetah. 11 | Please create a directory and run cmake from there, passing the path 12 | to this source directory as the last argument. 13 | This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. 14 | Please delete them." 15 | ) 16 | endif( _insource ) 17 | 18 | endmacro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD ) 19 | -------------------------------------------------------------------------------- /handcomp_test/getoptions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Function to evaluate argv[]. specs is a 0 terminated array of command 3 | * line options and types an array that stores the type as one of 4 | */ 5 | #define INTARG 1 6 | #define DOUBLEARG 2 7 | #define LONGARG 3 8 | #define BOOLARG 4 9 | #define STRINGARG 5 10 | #define BENCHMARK 6 11 | /* 12 | * for each specifier. Benchmark is specific for cilk samples. 13 | * -benchmark or -benchmark medium sets integer to 2 14 | * -benchmark short returns 1 15 | * -benchmark long returns 2 16 | * a boolarg is set to 1 if the specifier appears in the option list ow. 0 17 | * The variables must be given in the same order as specified in specs. 18 | */ 19 | 20 | void get_options(int argc, char *argv[], const char *specs[], int *types,...); 21 | -------------------------------------------------------------------------------- /runtime/local-reducer-api.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOCAL_REDUCER_API_H 2 | #define _LOCAL_REDUCER_API_H 3 | 4 | #include "cilk-internal.h" 5 | #include "global.h" 6 | #include "local-hypertable.h" 7 | 8 | static inline hyper_table * 9 | get_local_hyper_table(__cilkrts_worker *w) { 10 | if (nullptr == w->hyper_table) { 11 | w->hyper_table = __cilkrts_local_hyper_table_alloc(); 12 | } 13 | return w->hyper_table; 14 | } 15 | 16 | __attribute__((always_inline)) static inline struct hyper_table * 17 | get_hyper_table() { 18 | return get_local_hyper_table(__cilkrts_get_tls_worker()); 19 | } 20 | 21 | static inline struct hyper_table * 22 | get_local_hyper_table_or_null(const __cilkrts_worker *w) { 23 | return w->hyper_table; 24 | } 25 | 26 | #endif // _LOCAL_REDUCER_API_H 27 | -------------------------------------------------------------------------------- /runtime/worker_coord.h: -------------------------------------------------------------------------------- 1 | #ifndef _WORKER_COORD_H 2 | #define _WORKER_COORD_H 3 | 4 | // Routines for coordinating workers, specifically, putting workers to sleep and 5 | // waking workers when execution enters and leaves cilkified regions. 6 | 7 | //========================================================= 8 | // Common internal interface for managing execution of workers. 9 | //========================================================= 10 | 11 | __attribute__((always_inline)) static inline void busy_loop_pause() { 12 | #ifdef __SSE__ 13 | __builtin_ia32_pause(); 14 | #endif 15 | #ifdef __aarch64__ 16 | __builtin_arm_yield(); 17 | #endif 18 | } 19 | 20 | __attribute__((always_inline)) static inline void busy_pause(void) { 21 | for (int i = 0; i < BUSY_PAUSE; ++i) 22 | busy_loop_pause(); 23 | } 24 | 25 | #endif /* _WORKER_COORD_H */ 26 | -------------------------------------------------------------------------------- /runtime/scheduler.h: -------------------------------------------------------------------------------- 1 | #ifndef _RSCHED_H 2 | #define _RSCHED_H 3 | 4 | #include "closure.h" 5 | #include "efficiency.h" 6 | 7 | #define SYNC_READY 0 8 | #define SYNC_NOT_READY 1 9 | 10 | #define EXCEPTION_INFINITY (__cilkrts_stack_frame **)(-1LL) 11 | 12 | CHEETAH_INTERNAL void do_what_it_says_boss(__cilkrts_worker *w, Closure *t); 13 | 14 | CHEETAH_INTERNAL void __cilkrts_set_tls_worker(__cilkrts_worker *w); 15 | 16 | CHEETAH_INTERNAL int Cilk_sync(__cilkrts_worker *const ws, 17 | __cilkrts_stack_frame *frame); 18 | 19 | CHEETAH_INTERNAL_NORETURN void longjmp_to_runtime(__cilkrts_worker *w); 20 | CHEETAH_INTERNAL void worker_scheduler(__cilkrts_worker *w, history_t *const history); 21 | CHEETAH_INTERNAL void *scheduler_thread_proc(worker_args *w_arg); 22 | 23 | CHEETAH_INTERNAL void promote_own_deque(__cilkrts_worker *w); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/SortSubset.cmake: -------------------------------------------------------------------------------- 1 | # Sort a subset of a list according to the ordering in the full list. 2 | # 3 | # Given a list and a subset of that list, this function sorts the subset 4 | # according to the order in the full list, and returns that in the given 5 | # output variable. 6 | # 7 | # full_list: 8 | # The list containing the desired order of elements in the sub-list. 9 | # 10 | # sub_list: 11 | # A subset of the elements in `full_list`. Those elements will be sorted 12 | # according to the order in `full_list`. 13 | # 14 | # out_var: 15 | # A variable to store the resulting sorted sub-list in. 16 | function(sort_subset full_list sub_list out_var) 17 | set(result "${full_list}") 18 | foreach(project IN LISTS full_list) 19 | if (NOT project IN_LIST sub_list) 20 | list(REMOVE_ITEM result ${project}) 21 | endif() 22 | endforeach() 23 | 24 | set(${out_var} "${result}" PARENT_SCOPE) 25 | endfunction() 26 | -------------------------------------------------------------------------------- /runtime/local.h: -------------------------------------------------------------------------------- 1 | #ifndef _CILK_LOCAL_H 2 | #define _CILK_LOCAL_H 3 | 4 | #include "fiber.h" 5 | #include "internal-malloc-impl.h" /* for cilk_im_desc */ 6 | #include "jmpbuf.h" 7 | #include "local-hypertable.h" 8 | 9 | enum __cilkrts_worker_state : unsigned char { 10 | WORKER_IDLE = 10, 11 | WORKER_SCHED, 12 | WORKER_STEAL, 13 | WORKER_RUN 14 | }; 15 | 16 | struct __attribute__((visibility("hidden"))) local_state { 17 | struct __cilkrts_stack_frame **shadow_stack; 18 | 19 | __cilkrts_worker_state state; 20 | bool provably_good_steal; 21 | bool exiting; 22 | bool returning; 23 | unsigned int rand_next; 24 | uint32_t wake_val; 25 | 26 | jmpbuf rts_ctx; 27 | hyper_table *lht; 28 | hyper_table *rht; 29 | struct cilk_fiber_pool fiber_pool; 30 | struct cilk_im_desc im_desc; 31 | struct sched_stats stats; 32 | 33 | void change_state(enum __cilkrts_worker_state to); 34 | }; 35 | 36 | #endif /* _CILK_LOCAL_H */ 37 | -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/ExtendPath.cmake: -------------------------------------------------------------------------------- 1 | # Extend the path in `base_path` with the path in `current_segment`, returning 2 | # the result in `joined_path`. If `current_segment` is an absolute path then 3 | # just return it, in effect overriding `base_path`, and issue a warning. 4 | # 5 | # Note that the code returns a relative path (avoiding introducing leading 6 | # slashes) if `base_path` is empty. 7 | function(extend_path joined_path base_path current_segment) 8 | if("${current_segment}" STREQUAL "") 9 | set(temp_path "${base_path}") 10 | elseif("${base_path}" STREQUAL "") 11 | set(temp_path "${current_segment}") 12 | elseif(IS_ABSOLUTE "${current_segment}") 13 | message(WARNING "Since \"${current_segment}\" is absolute, it overrides base path: \"${base_path}\".") 14 | set(temp_path "${current_segment}") 15 | else() 16 | set(temp_path "${base_path}/${current_segment}") 17 | endif() 18 | set(${joined_path} "${temp_path}" PARENT_SCOPE) 19 | endfunction() 20 | -------------------------------------------------------------------------------- /runtime/efficiency.h: -------------------------------------------------------------------------------- 1 | #ifndef _EFFICIENCY_H 2 | #define _EFFICIENCY_H 3 | 4 | #include 5 | 6 | // Information for histories of efficient and inefficient worker-count samples 7 | // and for sentinel counts. 8 | typedef uint32_t history_sample_t; 9 | #define HISTORY_LENGTH 32 10 | #define SENTINEL_COUNT_HISTORY 4 11 | 12 | // Threshold for number of consective failed steal attempts to declare a 13 | // thief as sentinel. Must be a power of 2. 14 | #define SENTINEL_THRESHOLD 128 15 | 16 | // Number of attempted steals the thief should do each time it copies the 17 | // worker state. ATTEMPTS must divide SENTINEL_THRESHOLD. 18 | #define ATTEMPTS 4 19 | 20 | typedef struct history_t { 21 | history_sample_t inefficient_history = 0; 22 | history_sample_t efficient_history = 0; 23 | unsigned int sentinel_count_history_tail = 0; 24 | unsigned int recent_sentinel_count = SENTINEL_COUNT_HISTORY; 25 | unsigned int fails = 0; // rts->init_fails(...); 26 | unsigned int sample_threshold = SENTINEL_THRESHOLD; 27 | unsigned int sentinel_count_history[SENTINEL_COUNT_HISTORY] = { 1 }; 28 | } history_t; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/cilk/reducer: -------------------------------------------------------------------------------- 1 | #ifndef _CILK_REDUCER_ 2 | #define _CILK_REDUCER_ 3 | 4 | #include 5 | #include 6 | 7 | typedef std::function __cilk_identity_fn; 8 | typedef std::function __cilk_reduce_fn; 9 | 10 | struct __reducer_base { 11 | __reducer_base(); 12 | virtual ~__reducer_base(); 13 | // All of the following methods may be called concurrently. 14 | virtual std::size_t size() const = 0; 15 | // Return the __reducer_base subobject of a newly constructed object. 16 | virtual __reducer_base *identity(void *view) = 0; 17 | // Merge r into l. The destructor for r will be called after reduce. 18 | virtual void reduce(__reducer_base *l, __reducer_base *r) = 0; 19 | }; 20 | 21 | struct __reducer_callbacks { 22 | std::size_t size; 23 | __cilk_identity_fn identity; 24 | __cilk_reduce_fn reduce; 25 | }; 26 | 27 | extern "C" __reducer_base *__hyper_lookup_class(__reducer_base *) 28 | __attribute__((nonnull, returns_nonnull)); 29 | 30 | extern "C" void *__hyper_lookup_internal_1(void *, const __reducer_callbacks &) 31 | __attribute__((nonnull, returns_nonnull)); 32 | 33 | #endif // _CILK_REDUCER_ 34 | -------------------------------------------------------------------------------- /runtime/hyperobject_base.h: -------------------------------------------------------------------------------- 1 | #ifndef _HYPEROBJECT_BASE 2 | #define _HYPEROBJECT_BASE 3 | 4 | #include // __cilk_reduce_fn 5 | #include 6 | 7 | // Reducer data. 8 | // 9 | // NOTE: Since the size and identity_fn are only used when a worker 10 | // looks up a reducer after a steal, we don't need to store these in 11 | // the reducer_data structure as long as the reducer_lookup function 12 | // gets them as parameters. 13 | // 14 | // TODO: For small reducer views of size less than sizeof(void *), 15 | // consider storing the view directly within the reducer_data 16 | // structure. 17 | // - Problem: A reducer_data structure may move around in the hash 18 | // table as other reducers are inserted. As a result, a pointer to 19 | // a view may be invalidated by other hyper_lookup operations. 20 | // - Problem: Need a way to keep track of whether the view in a 21 | // reducer_data is storing a pointer to the view or the view itself. 22 | 23 | struct reducer_data { 24 | void *view; 25 | std::variant< 26 | __reducer_base *, 27 | const __cilk_reduce_fn *, 28 | void (*)(void *, void *) 29 | > extra; 30 | }; 31 | 32 | #endif /* _HYPEROBJECT_BASE */ 33 | -------------------------------------------------------------------------------- /config.mk: -------------------------------------------------------------------------------- 1 | CONFIG_DIR:=$(dir $(realpath $(lastword $(MAKEFILE_LIST)))) 2 | 3 | -include $(CONFIG_DIR)../cheetah_config.mk 4 | 5 | COMPILER_BASE?= 6 | CC=$(COMPILER_BASE)clang 7 | CXX=$(COMPILER_BASE)clang++ --std=c++20 8 | LINK_CC=$(CC) 9 | LLVM_LINK=$(COMPILER_BASE)llvm-link 10 | LLVM_CONFIG=$(COMPILER_BASE)llvm-config 11 | AR=ar 12 | #AR=$(COMPILER_BASE)llvm-ar 13 | # 14 | ABI_DEF?=-DOPENCILK_ABI 15 | # If use cheetah 16 | RTS_DIR?=../runtime 17 | RTS_LIB?=libopencilk 18 | RTS_C_PERSONALITY_LIB?=libopencilk-personality-c 19 | RTS_CXX_PERSONALITY_LIB?=libopencilk-personality-cpp 20 | RTS_PEDIGREE_LIB?=libopencilk-pedigrees 21 | 22 | # All runtime libraries and associated files will be placed in 23 | # `/oath/to/cheetah/lib/`, so that the compiler can easily find 24 | # all of those files using the flag --opencilk-resource-dir=/path/to/cheetah. 25 | TARGET?=$(shell $(LLVM_CONFIG) --host-target) 26 | RTS_LIBDIR_NAME?=lib/$(TARGET) 27 | RESOURCE_DIR?=$(CONFIG_DIR) 28 | RTS_LIBDIR?=$(RESOURCE_DIR)/$(RTS_LIBDIR_NAME) 29 | RTS_OPT?=-fopencilk --opencilk-resource-dir=$(RESOURCE_DIR) 30 | #RTS_LIB_FLAG=-lcheetah 31 | 32 | #ARCH = -mavx 33 | OPT ?= -O3 34 | DBG ?= -g3 35 | # A large number of processors, system-dependent 36 | # TODO: There should be an additional value meaning "all cores" 37 | MANYPROC ?= 8 38 | 39 | -------------------------------------------------------------------------------- /android/jni/libopencilk.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | LIBOPENCILK_ROOT_REL := ../.. 3 | LIBOPENCILK_ROOT_ABS := $(LOCAL_PATH)/../.. 4 | 5 | # libopencilk.so 6 | 7 | include $(CLEAR_VARS) 8 | 9 | LOCAL_MODULE := libopencilk 10 | 11 | SRC_FILTER := pedigree_ext pedigree_lib personality-c 12 | LOCAL_SRC_FILES := $(filter-out $(patsubst %,$(LIBOPENCILK_ROOT_ABS)/runtime/%.c,$(SRC_FILTER)), $(wildcard $(LIBOPENCILK_ROOT_ABS)/runtime/*.c)) 13 | 14 | LOCAL_C_INCLUDES := $(LIBOPENCILK_ROOT_ABS)/include 15 | 16 | # include $(BUILD_STATIC_LIBRARY) 17 | include $(BUILD_SHARED_LIBRARY) 18 | 19 | # libopencilk-personality-c.so 20 | 21 | include $(CLEAR_VARS) 22 | 23 | LOCAL_MODULE := libopencilk-personality-c 24 | 25 | LOCAL_SRC_FILES := $(LIBOPENCILK_ROOT_ABS)/runtime/personality-c.c 26 | 27 | LOCAL_C_INCLUDES := $(LIBOPENCILK_ROOT_ABS)/include 28 | LOCAL_SHARED_LIBRARIES := libopencilk 29 | 30 | # include $(BUILD_STATIC_LIBRARY) 31 | include $(BUILD_SHARED_LIBRARY) 32 | 33 | # libopencilk-personality-cpp.so 34 | 35 | include $(CLEAR_VARS) 36 | 37 | LOCAL_MODULE := libopencilk-personality-cpp 38 | 39 | LOCAL_SRC_FILES := $(LIBOPENCILK_ROOT_ABS)/runtime/personality-cpp.cpp 40 | 41 | LOCAL_C_INCLUDES := $(LIBOPENCILK_ROOT_ABS)/include 42 | LOCAL_SHARED_LIBRARIES := libopencilk 43 | 44 | LOCAL_CPP_FEATURES := exceptions 45 | 46 | # include $(BUILD_STATIC_LIBRARY) 47 | include $(BUILD_SHARED_LIBRARY) -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/LLVMCheckCompilerLinkerFlag.cmake: -------------------------------------------------------------------------------- 1 | include(CMakePushCheckState) 2 | 3 | include(CheckCompilerFlag OPTIONAL) 4 | 5 | if(NOT COMMAND check_compiler_flag) 6 | include(CheckCCompilerFlag) 7 | include(CheckCXXCompilerFlag) 8 | endif() 9 | 10 | function(llvm_check_compiler_linker_flag lang flag out_var) 11 | # If testing a flag with check_c_compiler_flag, it gets added to the compile 12 | # command only, but not to the linker command in that test. If the flag 13 | # is vital for linking to succeed, the test would fail even if it would 14 | # have succeeded if it was included on both commands. 15 | # 16 | # Therefore, try adding the flag to CMAKE_REQUIRED_FLAGS, which gets 17 | # added to both compiling and linking commands in the tests. 18 | 19 | cmake_push_check_state() 20 | set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${flag}") 21 | if(COMMAND check_compiler_flag) 22 | check_compiler_flag("${lang}" "" ${out_var}) 23 | else() 24 | # Until the minimum CMAKE version is 3.19 25 | # cmake builtin compatible, except we assume lang is C or CXX 26 | if("${lang}" STREQUAL "C") 27 | check_c_compiler_flag("" ${out_var}) 28 | elseif("${lang}" STREQUAL "CXX") 29 | check_cxx_compiler_flag("" ${out_var}) 30 | else() 31 | message(FATAL_ERROR "\"${lang}\" is not C or CXX") 32 | endif() 33 | endif() 34 | cmake_pop_check_state() 35 | endfunction() 36 | -------------------------------------------------------------------------------- /LICENSE.TXT: -------------------------------------------------------------------------------- 1 | ============================================================================== 2 | The OpenCilk runtime is licensed under the MIT License: 3 | ============================================================================== 4 | Copyright (c) 2020 Massachusetts Institute of Technology and 5 | Washington University in St. Louis 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal with the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /include/cilk/cilk_api.h: -------------------------------------------------------------------------------- 1 | #ifndef _CILK_API_H 2 | #define _CILK_API_H 3 | 4 | #include /* size_t */ 5 | 6 | #ifdef __cplusplus 7 | #define __CILKRTS_NOTHROW noexcept 8 | extern "C" { 9 | #else 10 | #define __CILKRTS_NOTHROW __attribute__((nothrow)) 11 | #endif 12 | 13 | int __cilkrts_is_initialized(void) __CILKRTS_NOTHROW; 14 | int __cilkrts_atinit(void (*callback)(void)) __CILKRTS_NOTHROW; 15 | int __cilkrts_atexit(void (*callback)(void)) __CILKRTS_NOTHROW; 16 | unsigned __cilkrts_get_nworkers(void) __CILKRTS_NOTHROW; 17 | unsigned __cilkrts_get_worker_number(void) __attribute__((deprecated)); 18 | int __cilkrts_running_on_workers(void) __CILKRTS_NOTHROW; 19 | 20 | #include 21 | typedef struct __cilkrts_pedigree { 22 | uint64_t rank; 23 | struct __cilkrts_pedigree *parent; 24 | } __cilkrts_pedigree; 25 | __cilkrts_pedigree __cilkrts_get_pedigree(void) __CILKRTS_NOTHROW; 26 | void __cilkrts_bump_worker_rank(void) __CILKRTS_NOTHROW; 27 | void __cilkrts_dprand_set_seed(uint64_t seed) __CILKRTS_NOTHROW; 28 | void __cilkrts_init_dprng(void) __CILKRTS_NOTHROW; 29 | uint64_t __cilkrts_get_dprand(void) __CILKRTS_NOTHROW; 30 | 31 | void __cilkrts_reducer_register_2(void *key, void (*reduce)(void *, void *)) 32 | __CILKRTS_NOTHROW; 33 | 34 | __attribute__((deprecated)) 35 | void __cilkrts_reducer_unregister(void *key) __CILKRTS_NOTHROW; 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #endif /* _CILK_API_H */ 42 | -------------------------------------------------------------------------------- /handcomp_test/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | 3 | SRCS = $(wildcard *.cpp) 4 | HDRS = $(wildcard *.h) 5 | OBJS = $(patsubst %.cpp,%.o,$(SRCS)) 6 | 7 | DEFINES = $(ABI_DEF) 8 | 9 | TESTS = cilksort fib mm_dac nqueens 10 | INCLUDES = -I../include/ 11 | OPTIONS = $(OPT) $(ARCH) $(DBG) -Wall $(DEFINES) $(INCLUDES) -fno-omit-frame-pointer 12 | # dynamic linking 13 | # RTS_DLIBS = -L../runtime -Wl,-rpath -Wl,../runtime -lopencilk 14 | # RTS_LIBS = ../runtime/$(RTS_LIB).so 15 | # static linking 16 | RTS_LIBS = $(RTS_LIBDIR)/$(RTS_LIB).a 17 | TIMING_COUNT ?= 1 18 | 19 | .PHONY: all check memcheck clean 20 | 21 | all: $(TESTS) 22 | 23 | $(TESTS): %: %.o ktiming.o getoptions.o ZERO.o 24 | $(CXX) $^ -o $@ $(RTS_LIBS) -lrt -lpthread -lm 25 | 26 | %.o: %.c 27 | $(CC) -c $(OPTIONS) -DTIMING_COUNT=$(TIMING_COUNT) -o $@ $< 28 | 29 | %.o: %.cpp 30 | $(CXX) -c $(OPTIONS) -DTIMING_COUNT=$(TIMING_COUNT) -o $@ $< 31 | 32 | memcheck: 33 | $(MAKE) clean; $(MAKE) > /dev/null 34 | date 35 | CILK_NWORKERS=8 valgrind ./fib 26 36 | CILK_NWORKERS=8 valgrind ./mm_dac -n 512 37 | CILK_NWORKERS=8 valgrind ./cilksort -n 3000000 38 | CILK_NWORKERS=8 valgrind ./nqueens 10 39 | date 40 | 41 | check: 42 | $(MAKE) clean; $(MAKE) TIMING_COUNT=5 > /dev/null 43 | CILK_NWORKERS=$(MANYPROC) ./fib 40 44 | CILK_NWORKERS=$(MANYPROC) ./mm_dac -n 1024 -c 45 | CILK_NWORKERS=$(MANYPROC) ./cilksort -n 30000000 -c 46 | CILK_NWORKERS=$(MANYPROC) ./nqueens 14 47 | 48 | clean: 49 | rm -f *.o *~ $(TESTS) core.* 50 | -------------------------------------------------------------------------------- /.github/workflows/handcomp-tests.yml: -------------------------------------------------------------------------------- 1 | name: Hand-compiled tests 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | workflow_dispatch: 8 | push: 9 | pull_request: 10 | 11 | concurrency: 12 | # Skip intermediate builds: always. 13 | # Cancel intermediate builds: only if it is a pull request build. 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} 16 | 17 | jobs: 18 | handcomp_test: 19 | runs-on: ${{ matrix.os }} 20 | container: 21 | image: ${{(startsWith(matrix.os, 'ubuntu') && 'ghcr.io/llvm/ci-ubuntu-22.04:latest') || null}} 22 | volumes: 23 | - /mnt/:/mnt/ 24 | options: --user root 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | os: [ubuntu-latest] 29 | steps: 30 | - name: checkout 31 | uses: actions/checkout@v4 32 | - name: Setup OpenCilk compiler 33 | id: build-opencilk 34 | uses: OpenCilk/actions/build-opencilk-project@main 35 | with: 36 | projects: clang 37 | extra_cmake_args: -DLLVM_TARGETS_TO_BUILD=host 38 | os_list: '${{ matrix.os }}' 39 | - name: make 40 | shell: bash 41 | run: | 42 | opencilkdir=${{ steps.build-opencilk.outputs.opencilk-builddir }} 43 | COMPILER_BASE=$opencilkdir/bin/ make 44 | - name: make check 45 | shell: bash 46 | run: 47 | opencilkdir=${{ steps.build-opencilk.outputs.opencilk-builddir }} 48 | COMPILER_BASE=$opencilkdir/bin/ make -C handcomp_test check 49 | -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/GNUInstallPackageDir.cmake: -------------------------------------------------------------------------------- 1 | # Mimick `GNUInstallDirs` for one more install directory, the one where 2 | # project's installed cmake subdirs go. 3 | 4 | # These functions are internal functions vendored in from GNUInstallDirs (with 5 | # new names), so we don't depend on unstable implementation details. They are 6 | # also simplified to only handle the cases we need. 7 | # 8 | # The purpose would appear to be making `CACHE PATH` vars in a way that 9 | # bypasses the legacy oddity that `-D` gets canonicalized, despite 10 | # non-canonical `CACHE PATH`s being perfectly valid. 11 | 12 | macro(_GNUInstallPackageDir_cache_convert_to_path var description) 13 | get_property(_GNUInstallPackageDir_cache_type CACHE ${var} PROPERTY TYPE) 14 | if(_GNUInstallPackageDir_cache_type STREQUAL "UNINITIALIZED") 15 | file(TO_CMAKE_PATH "${${var}}" _GNUInstallPackageDir_cmakepath) 16 | set_property(CACHE ${var} PROPERTY TYPE PATH) 17 | set_property(CACHE ${var} PROPERTY VALUE "${_GNUInstallPackageDir_cmakepath}") 18 | set_property(CACHE ${var} PROPERTY HELPSTRING "${description}") 19 | unset(_GNUInstallPackageDir_cmakepath) 20 | endif() 21 | unset(_GNUInstallPackageDir_cache_type) 22 | endmacro() 23 | 24 | # Create a cache variable with default for a path. 25 | macro(_GNUInstallPackageDir_cache_path var default description) 26 | if(NOT DEFINED ${var}) 27 | set(${var} "${default}" CACHE PATH "${description}") 28 | endif() 29 | _GNUInstallPackageDir_cache_convert_to_path("${var}" "${description}") 30 | endmacro() 31 | 32 | _GNUInstallPackageDir_cache_path(CMAKE_INSTALL_PACKAGEDIR "lib${LLVM_LIBDIR_SUFFIX}/cmake" 33 | "Directories containing installed CMake modules (lib/cmake)") 34 | -------------------------------------------------------------------------------- /android/jni/libopencilk-abi.mk: -------------------------------------------------------------------------------- 1 | DIR?=$(shell pwd) 2 | LOCAL_PATH := $(DIR) 3 | LIBOPENCILK_ROOT_REL := ../.. 4 | LIBOPENCILK_ROOT_ABS := $(LOCAL_PATH)/../.. 5 | 6 | UNAME := $(shell uname -s) 7 | ifneq (,$(findstring Linux,$(UNAME))) 8 | HOST_OS := linux 9 | endif 10 | ifneq (,$(findstring Darwin,$(UNAME))) 11 | HOST_OS := darwin 12 | endif 13 | 14 | TOOLCHAIN=${NDK}/toolchains/llvm/prebuilt/$(HOST_OS)-x86_64 15 | CC=$(TOOLCHAIN)/bin/clang 16 | CXX=$(TOOLCHAIN)/bin/clang++ 17 | 18 | # libopencilk-abi.bc 19 | 20 | MODULE := libopencilk-abi 21 | OUT_DIR := $(LOCAL_PATH)/../libs 22 | TARGET_AARCH64_DIR := $(OUT_DIR)/arm64-v8a 23 | TARGET_X86_64_DIR := $(OUT_DIR)/x86_64 24 | TARGET_AARCH64 := $(TARGET_AARCH64_DIR)/$(MODULE).bc 25 | TARGET_X86_64 := $(TARGET_X86_64_DIR)/$(MODULE).bc 26 | API := 28 27 | 28 | all: $(TARGET_AARCH64) $(TARGET_X86_64) 29 | 30 | SRC_FILES := $(LIBOPENCILK_ROOT_ABS)/runtime/cilk2c_inlined.c 31 | CFLAGS += \ 32 | -DCHEETAH_API="" \ 33 | -DCHEETAH_INTERNAL_NORETURN='__attribute__((noreturn))' \ 34 | -DCHEETAH_INTERNAL="" \ 35 | -DCILK_DEBUG=0 \ 36 | -g -gdwarf-4 37 | 38 | C_INCLUDES := -I$(LIBOPENCILK_ROOT_ABS)/include 39 | 40 | ifeq (${DEBUG},1) 41 | CFLAGS += -O0 42 | else 43 | CFLAGS += -O3 44 | endif 45 | 46 | $(TARGET_AARCH64_DIR) $(TARGET_X86_64_DIR): 47 | @mkdir -p $@ 48 | 49 | $(TARGET_AARCH64) : $(TARGET_AARCH64_DIR) 50 | $(TARGET_X86_64) : $(TARGET_X86_64_DIR) 51 | 52 | $(TARGET_AARCH64) : $(SRC_FILES) 53 | $(CC) --target=aarch64-linux-android$(API) $(CFLAGS) $(C_INCLUDES) -c -emit-llvm -o $@ $< 54 | 55 | $(TARGET_X86_64) : $(SRC_FILES) 56 | $(CC) --target=x86_64-linux-android$(API) $(CFLAGS) $(C_INCLUDES) -c -emit-llvm -o $@ $< 57 | 58 | clean: 59 | rm $(TARGET_AARCH64) $(TARGET_X86_64) -------------------------------------------------------------------------------- /runtime/personality-cpp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef _Unwind_Reason_Code (*__personality_routine)( 5 | int version, _Unwind_Action actions, uint64_t exception_class, 6 | struct _Unwind_Exception *exception_object, 7 | struct _Unwind_Context *context); 8 | 9 | extern "C" { 10 | _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, 11 | uint64_t exception_class, 12 | struct _Unwind_Exception *ue_header, 13 | struct _Unwind_Context *context); 14 | 15 | _Unwind_Reason_Code __cilk_personality_internal( 16 | __personality_routine std_lib_personality, int version, 17 | _Unwind_Action actions, uint64_t exception_class, 18 | struct _Unwind_Exception *ue_header, struct _Unwind_Context *context); 19 | 20 | _Unwind_Reason_Code __cilk_personality_cpp_v0( 21 | int version, _Unwind_Action actions, uint64_t exception_class, 22 | struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) { 23 | return __cilk_personality_internal(__gxx_personality_v0, version, actions, 24 | exception_class, ue_header, context); 25 | } 26 | 27 | _Unwind_Reason_Code __cilk_personality_v0(int version, _Unwind_Action actions, 28 | uint64_t exception_class, 29 | struct _Unwind_Exception *ue_header, 30 | struct _Unwind_Context *context) { 31 | return __cilk_personality_cpp_v0(version, actions, exception_class, 32 | ue_header, context); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /handcomp_test/ktiming.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012 MIT License by 6.172 Staff 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | **/ 22 | 23 | #ifndef _KTIMING_H_ 24 | #define _KTIMING_H_ 25 | 26 | #include 27 | 28 | typedef uint64_t clockmark_t; 29 | 30 | uint64_t 31 | ktiming_diff_nsec(const clockmark_t* const start, const clockmark_t* const end); 32 | double 33 | ktiming_diff_sec(const clockmark_t* const start, const clockmark_t* const end); 34 | clockmark_t ktiming_getmark(void); 35 | void print_runtime(uint64_t *tm_elapsed, int size); 36 | void print_runtime_summary(uint64_t *tm_elapsed, int size); 37 | 38 | #endif // _KTIMING_H_ 39 | 40 | -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(cilk_header_files 2 | cilk/cilk.h 3 | cilk/cilk_api.h 4 | cilk/cilk_stub.h 5 | cilk/holder.h 6 | cilk/opadd_reducer.h 7 | cilk/ostream_reducer.h 8 | cilk/reducer) 9 | 10 | set(output_dir ${CHEETAH_OUTPUT_DIR}/include) 11 | set(out_files) 12 | 13 | function(copy_header_to_output_dir src_dir file) 14 | set(src ${src_dir}/${file}) 15 | set(dst ${output_dir}/${file}) 16 | add_custom_command(OUTPUT ${dst} 17 | DEPENDS ${src} 18 | COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst} 19 | COMMENT "Copying Cheetah's ${file}...") 20 | list(APPEND out_files ${dst}) 21 | set(out_files ${out_files} PARENT_SCOPE) 22 | endfunction(copy_header_to_output_dir) 23 | 24 | # Copy header files from the source directory to the build directory 25 | foreach( f ${cilk_header_files}) 26 | copy_header_to_output_dir(${CMAKE_CURRENT_SOURCE_DIR} ${f}) 27 | endforeach( f ) 28 | 29 | add_custom_target(cilk-headers ALL DEPENDS ${out_files}) 30 | add_dependencies(cheetah cilk-headers) 31 | set_target_properties(cilk-headers PROPERTIES FOLDER "Cheetah Misc") 32 | 33 | set(header_install_dir ${CHEETAH_INSTALL_PATH}/include) 34 | 35 | install( 36 | FILES ${cilk_header_files} 37 | DESTINATION ${header_install_dir}/cilk 38 | COMPONENT cilk-headers) 39 | 40 | if (NOT CMAKE_CONFIGURATION_TYPES AND CHEETAH_INSTALL_HEADERS) 41 | if(CHEETAH_INSTALL_HEADERS) 42 | set(header_install_target install-cheetah-headers) 43 | endif() 44 | add_custom_target(install-cilk-headers 45 | DEPENDS cilk-headers 46 | COMMAND "${CMAKE_COMMAND}" 47 | -DCMAKE_INSTALL_COMPONENT="cilk-headers" 48 | -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") 49 | endif() 50 | -------------------------------------------------------------------------------- /runtime/personality-c.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef _Unwind_Reason_Code (*__personality_routine)( 5 | int version, _Unwind_Action actions, uint64_t exception_class, 6 | struct _Unwind_Exception *exception_object, 7 | struct _Unwind_Context *context); 8 | 9 | _Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions, 10 | uint64_t exception_class, 11 | struct _Unwind_Exception *ue_header, 12 | struct _Unwind_Context *context); 13 | 14 | _Unwind_Reason_Code __cilk_personality_internal( 15 | __personality_routine std_lib_personality, int version, 16 | _Unwind_Action actions, uint64_t exception_class, 17 | struct _Unwind_Exception *ue_header, struct _Unwind_Context *context); 18 | 19 | _Unwind_Reason_Code __cilk_personality_c_v0(int version, _Unwind_Action actions, 20 | uint64_t exception_class, 21 | struct _Unwind_Exception *ue_header, 22 | struct _Unwind_Context *context) { 23 | return __cilk_personality_internal(__gcc_personality_v0, version, actions, 24 | exception_class, ue_header, context); 25 | } 26 | 27 | _Unwind_Reason_Code __cilk_personality_v0(int version, _Unwind_Action actions, 28 | uint64_t exception_class, 29 | struct _Unwind_Exception *ue_header, 30 | struct _Unwind_Context *context) { 31 | return __cilk_personality_c_v0(version, actions, exception_class, ue_header, 32 | context); 33 | } 34 | -------------------------------------------------------------------------------- /runtime/internal-malloc-impl.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTERAL_MALLOC_IMPL_H 2 | #define _INTERAL_MALLOC_IMPL_H 3 | 4 | #include "internal-malloc.h" 5 | 6 | #define NUM_BUCKETS 7 7 | 8 | /* struct for managing global memory pool; each memory block in mem_list starts 9 | out with size INTERNAL_MALLOC_CHUNK. We will allocate small pieces off the 10 | memory block and free the pieces into per-worker im_descriptor free list. */ 11 | struct global_im_pool { 12 | char *mem_begin; // beginning of the free memory block that we are using 13 | char *mem_end; // end of the free memory block that we are using 14 | char **mem_list; // list of memory blocks obtained from system 15 | unsigned mem_list_index; // index to the current mem block in use 16 | unsigned mem_list_size; // length of the mem_list 17 | size_t num_global_malloc; 18 | size_t allocated; // bytes allocated into the pool 19 | size_t wasted; // bytes at the end of a chunk that could not be used 20 | }; 21 | 22 | struct im_bucket { 23 | void *free_list; // beginning of free list 24 | unsigned free_list_size; // Current size of free list 25 | unsigned free_list_limit; // Maximum allowed size of free list 26 | // Allocation count and wasted space on a worker may be negative 27 | // if it frees blocks allocated elsewhere. In a global bucket 28 | // these fields should never be negative. 29 | int allocated; // Current allocations, in use or free 30 | int max_allocated; // high watermark of allocated 31 | long wasted; // in bytes 32 | }; 33 | 34 | /* One of these per worker, and one global */ 35 | struct cilk_im_desc { 36 | struct im_bucket buckets[NUM_BUCKETS]; 37 | long used; // local alloc - local free, may be negative 38 | long num_malloc[IM_NUM_TAGS]; 39 | }; 40 | 41 | #endif /* _INTERAL_MALLOC_IMPL_H */ 42 | -------------------------------------------------------------------------------- /runtime/worker.h: -------------------------------------------------------------------------------- 1 | #ifndef _CILK_WORKER_H 2 | #define _CILK_WORKER_H 3 | 4 | #include 5 | #include 6 | 7 | struct __cilkrts_stack_frame; 8 | struct local_state; 9 | struct global_state; 10 | struct hyper_table; 11 | 12 | typedef uint32_t worker_id; 13 | #define WORKER_ID_FMT PRIu32 14 | #define NO_WORKER worker_id(0xffffffffu) 15 | 16 | struct __cilkrts_worker { 17 | // Worker id, a small integer 18 | worker_id self; 19 | 20 | // 4 byte hole on 64 bit systems 21 | 22 | // Current hyperobject table 23 | struct hyper_table *hyper_table; 24 | 25 | // Global state of the runtime system, opaque to the client. 26 | struct global_state *g; 27 | 28 | // Additional per-worker state hidden from the client. 29 | struct local_state *l; 30 | 31 | // Cache line boundary on 64 bit systems with 64 byte cache lines 32 | 33 | // Optional state, only maintained if __cilkrts_use_extension == true. 34 | void *extension; 35 | void *ext_stack; 36 | 37 | // T, H, and E pointers in the THE protocol. 38 | // T and E are frequently accessed and should be in a hot cache line. 39 | // H could be moved elsewhere because it is only touched when stealing. 40 | std::atomic tail; 41 | std::atomic exc 42 | __attribute__((aligned(CILK_CACHE_LINE))); 43 | std::atomic head 44 | __attribute__((aligned(CILK_CACHE_LINE))); 45 | 46 | // Limit of the Lazy Task Queue, to detect queue overflow (debug only) 47 | struct __cilkrts_stack_frame **ltq_limit; 48 | 49 | } __attribute__((aligned(1024))); // This alignment reduces false sharing 50 | // induced by hardware prefetchers on some 51 | // systems, such as Intel CPUs. 52 | 53 | #endif /* _CILK_WORKER_H */ 54 | -------------------------------------------------------------------------------- /runtime/cilk2c.h: -------------------------------------------------------------------------------- 1 | #ifndef _CILK2C_H 2 | #define _CILK2C_H 3 | 4 | #include "cilk-internal.h" 5 | #include "frame.h" 6 | #include "rts-config.h" 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | // Returns 1 if the current exection is running on Cilk workers, 0 otherwise. 13 | CHEETAH_API int __cilkrts_running_on_workers(void) __CILKRTS_NOTHROW; 14 | 15 | // ABI functions inlined by the compiler (provided as a bitcode file after 16 | // compiling runtime) are declared in cilk2c_inline.h and defined in 17 | // cilk2c_inline.c. 18 | // ABI functions not inlined by the compiler are defined in cilk2c.c. 19 | 20 | // Check if the runtime is storing an exception we need to handle later, and 21 | // raises that exception if so. 22 | CHEETAH_API void __cilkrts_check_exception_raise(__cilkrts_stack_frame *sf); 23 | 24 | // Check if the runtime is storing an exception we need to handle later, and 25 | // resumes unwinding with that exception if so. 26 | CHEETAH_API void __cilkrts_check_exception_resume(__cilkrts_stack_frame *sf); 27 | 28 | // Implements a cilk_sync when the cilk_sync might produce an exception that 29 | // needs to be handled. 30 | CHEETAH_API void __cilkrts_sync(__cilkrts_stack_frame *sf); 31 | 32 | // Called from __cilkrts_enter_landingpad to optionally fix the current stack 33 | // pointer and cleanup a fiber that was previously saved for exception handling. 34 | CHEETAH_API void __cilkrts_cleanup_fiber(__cilkrts_stack_frame *, int32_t sel) 35 | __CILKRTS_NOTHROW; 36 | 37 | // Not marked as CHEETAH_API as it may be deprecated soon 38 | unsigned __cilkrts_get_nworkers(void) __CILKRTS_NOTHROW; 39 | 40 | CHEETAH_API void __cilkrts_set_return(__cilkrts_worker *const ws); 41 | CHEETAH_API void __cilkrts_exception_handler(__cilkrts_worker *w, char *exn); 42 | CHEETAH_API void __cilkrts_do_reductions(__cilkrts_stack_frame *sf); 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /runtime/fiber-header.h: -------------------------------------------------------------------------------- 1 | #ifndef _FIBER_HEADER_H 2 | #define _FIBER_HEADER_H 3 | 4 | #include "rts-config.h" 5 | 6 | struct __cilkrts_worker; 7 | struct __cilkrts_stack_frame; 8 | 9 | // Structure inserted at the top of a fiber, to implement fiber-local storage. 10 | // The stack begins just below this structure. See get_stack_start(). 11 | // This must be a standard layout class. 12 | struct cilk_fiber { 13 | // Worker currently executing on the fiber. 14 | struct __cilkrts_worker *worker; 15 | // Current stack frame executing on the fiber. 16 | struct __cilkrts_stack_frame *current_stack_frame; 17 | 18 | // NOTE: The current hyper_table can be stored in the fiber header, but we 19 | // don't currently observe any performance advantage or disadvantage to 20 | // storing the hyper_table here. 21 | 22 | // Pointer to AddressSanitizer's fake stack associated with this fiber, when 23 | // AddressSanitizer is being used. 24 | void *fake_stack_save; 25 | 26 | // These next two words are for internal library use and are 27 | // constant for the life of this structure. 28 | char *alloc_low; // lowest byte of mapped region 29 | char *stack_low; // lowest byte of stack region 30 | 31 | // Three unused words remain on 64 bit systems with 64 byte cache lines. 32 | 33 | char *get_fiber_start() { return alloc_low; } 34 | char *get_fiber_end() { return (char *)(this + 1); } 35 | char *get_stack_start() { return (char *)this; } 36 | 37 | bool in_fiber(void *addr) { 38 | void *stack_high = (char *)this; 39 | // One past the end is considered in the fiber. 40 | return addr >= stack_low && addr <= stack_high; 41 | } 42 | 43 | void clear() { 44 | worker = nullptr; 45 | current_stack_frame = nullptr; 46 | fake_stack_save = nullptr; 47 | } 48 | 49 | } __attribute__((aligned(CILK_CACHE_LINE))); 50 | 51 | #endif // _FIBER_HEADER_H 52 | -------------------------------------------------------------------------------- /runtime/mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef _CILK_MUTEX_H 2 | #define _CILK_MUTEX_H 3 | 4 | // Forward declaration 5 | typedef union cilk_mutex cilk_mutex; 6 | 7 | // Includes 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "rts-config.h" 13 | 14 | #ifndef __APPLE__ 15 | #define USE_SPINLOCK 1 16 | #endif 17 | 18 | #if USE_SPINLOCK 19 | union cilk_mutex { 20 | volatile int memory; 21 | pthread_spinlock_t posix; 22 | }; 23 | #else 24 | union cilk_mutex { 25 | volatile int memory; 26 | pthread_mutex_t posix; 27 | }; 28 | #endif 29 | 30 | #pragma clang diagnostic push 31 | #pragma clang diagnostic ignored "-Wthread-safety-analysis" 32 | 33 | static inline void cilk_mutex_init(cilk_mutex *lock) { 34 | #if USE_SPINLOCK 35 | int ret = pthread_spin_init(&(lock->posix), PTHREAD_PROCESS_PRIVATE); 36 | if (ret != 0) { 37 | errno = ret; 38 | perror("Pthread_spin_init failed"); 39 | exit(-1); 40 | } 41 | #else 42 | pthread_mutex_init(&(lock->posix), nullptr); 43 | #endif 44 | } 45 | 46 | static inline void cilk_mutex_lock(cilk_mutex *lock) { 47 | #if USE_SPINLOCK 48 | pthread_spin_lock(&(lock->posix)); 49 | #else 50 | pthread_mutex_lock(&(lock->posix)); 51 | #endif 52 | } 53 | 54 | static inline void cilk_mutex_unlock(cilk_mutex *lock) { 55 | #if USE_SPINLOCK 56 | pthread_spin_unlock(&(lock->posix)); 57 | #else 58 | pthread_mutex_unlock(&(lock->posix)); 59 | #endif 60 | } 61 | 62 | static inline int cilk_mutex_try(cilk_mutex *lock) { 63 | #if USE_SPINLOCK 64 | if (pthread_spin_trylock(&(lock->posix)) == 0) { 65 | return 1; 66 | } else { 67 | return 0; 68 | } 69 | #else 70 | if (pthread_mutex_trylock(&(lock->posix)) == 0) { 71 | return 1; 72 | } else { 73 | return 0; 74 | } 75 | #endif 76 | } 77 | 78 | #pragma clang diagnostic pop 79 | 80 | static inline void cilk_mutex_destroy(cilk_mutex *lock) { 81 | #if USE_SPINLOCK 82 | pthread_spin_destroy(&(lock->posix)); 83 | #else 84 | pthread_mutex_destroy(&(lock->posix)); 85 | #endif 86 | } 87 | #endif 88 | -------------------------------------------------------------------------------- /runtime/jmpbuf.h: -------------------------------------------------------------------------------- 1 | #ifndef _JMPBUF_H 2 | #define _JMPBUF_H 3 | 4 | #include "debug.h" 5 | 6 | #define JMPBUF_SIZE 5 7 | typedef void *jmpbuf[JMPBUF_SIZE]; 8 | 9 | #define JMPBUF_FP(ctx) (ctx)[0] // frame addr, i.e., %rbp 10 | #define JMPBUF_PC(ctx) (ctx)[1] // PC counter, i.e., %rip 11 | #define JMPBUF_SP(ctx) (ctx)[2] // stack addr, i.e., %rsp 12 | 13 | /** 14 | * @brief Get frame pointer from jump buffer in__cilkrts_stack_frame. 15 | */ 16 | #define FP(SF) JMPBUF_FP((SF)->ctx) 17 | 18 | /** 19 | * @brief Get program counter from jump buffer in__cilkrts_stack_frame. 20 | */ 21 | #define PC(SF) JMPBUF_PC((SF)->ctx) 22 | 23 | /** 24 | * @brief Get stack pointer from jump buffer in__cilkrts_stack_frame. 25 | */ 26 | #define SP(SF) JMPBUF_SP((SF)->ctx) 27 | 28 | #if defined __i386__ || defined __x86_64__ 29 | // We use an otherwise unused entry in the jmpbuf to store MXCSR 30 | #define JMPBUF_MXCSR(ctx) (ctx)[3] 31 | /** 32 | * @brief Get MXCSR from jump buffer in__cilkrts_stack_frame. X86 and X86_64 33 | * only. 34 | */ 35 | #define MXCSR(SF) JMPBUF_MXCSR((SF)->ctx) 36 | #endif 37 | 38 | #if defined __i386__ 39 | #define ASM_GET_SP(osp) __asm__ volatile("movl %%esp, %0" : "=r"(osp)) 40 | #elif defined __x86_64__ 41 | #define ASM_GET_SP(osp) __asm__ volatile("movq %%rsp, %0" : "=r"(osp)) 42 | #elif defined __aarch64__ 43 | #define ASM_GET_SP(osp) __asm__ volatile("mov %0, sp" : "=r"(osp)) 44 | #else 45 | #error "No defined method to get stack pointer on this architecture." 46 | #endif 47 | 48 | /* These macros are only for debugging. */ 49 | #define ASM_GET_FP(ofp) (ofp) = __builtin_frame_address(0) 50 | 51 | #define DUMP_STACK(lvl, w) \ 52 | { \ 53 | char *x_bp; \ 54 | char *x_sp; \ 55 | ASM_GET_FP(x_bp); \ 56 | ASM_GET_SP(x_sp); \ 57 | cilkrts_alert((lvl), "rbp %p rsp %p", x_bp, x_sp); \ 58 | } 59 | #endif 60 | -------------------------------------------------------------------------------- /runtime/pedigree_ext.cpp: -------------------------------------------------------------------------------- 1 | #include "pedigree-internal.h" 2 | 3 | // Pedigree-extension code, included in the runtime as part of the bitcode file. 4 | 5 | void __cilkrts_extend_spawn(__cilkrts_worker *w, void **parent_extension, 6 | void **child_extension) { 7 | // Copy the child extension into the parent, and create a new 8 | // __pedigree_frame for the child. 9 | *parent_extension = *child_extension; 10 | 11 | // Get a new pedigree frame for the child extension. 12 | __pedigree_frame *frame = push_pedigree_frame(w); 13 | *child_extension = frame; 14 | 15 | // Initialize the new frame. 16 | __pedigree_frame *parent_frame = (__pedigree_frame *)(*parent_extension); 17 | // Copy the parent's rank into the child frame's pedigree.rank. 18 | frame->pedigree.rank = parent_frame->rank; 19 | // Append the child frame's pedigree onto the linked list. 20 | frame->pedigree.parent = &(parent_frame->pedigree); 21 | // Initialize the child frame's rank to 0. 22 | frame->rank = 0; 23 | 24 | // Increment the dprng_depth in the child frame. 25 | frame->dprng_depth = parent_frame->dprng_depth + 1; 26 | // Update the child frame's dprng_dotproduct. 27 | uint64_t parent_dprng_dotproduct = parent_frame->dprng_dotproduct; 28 | frame->dprng_dotproduct = __cilkrts_dprng_sum_mod_p( 29 | parent_dprng_dotproduct, __pedigree_dprng_m_array[frame->dprng_depth]); 30 | 31 | // Update the rank and dprng_dotproduct in the parent frame. 32 | parent_frame->rank++; 33 | parent_frame->dprng_dotproduct = __cilkrts_dprng_sum_mod_p( 34 | parent_dprng_dotproduct, 35 | __pedigree_dprng_m_array[parent_frame->dprng_depth]); 36 | } 37 | 38 | void __cilkrts_extend_return_from_spawn(__cilkrts_worker *w, void **extension) { 39 | // Free the pedigree frame. 40 | pop_pedigree_frame(w); 41 | (void)extension; // TODO: Remove the parameter? 42 | } 43 | 44 | void __cilkrts_extend_sync(void **extension) { 45 | // Update the rank and dprng_dotproduct. 46 | __pedigree_frame *frame = (__pedigree_frame *)(*extension); 47 | frame->rank++; 48 | frame->dprng_dotproduct = __cilkrts_dprng_sum_mod_p( 49 | frame->dprng_dotproduct, __pedigree_dprng_m_array[frame->dprng_depth]); 50 | } 51 | -------------------------------------------------------------------------------- /runtime/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | 3 | # With reducers 4 | REDUCER_DEF = -DREDUCER_MODULE 5 | #ABI_DEF imported from ../config.mk 6 | #ALERT_DEF = -DALERT_LVL=0x000 7 | 8 | RESOURCE_DIR=$(realpath ..) 9 | MAIN = $(RTS_LIBDIR)/$(RTS_LIB) 10 | BITCODE_ABI = $(MAIN)-abi.bc 11 | SRCS = $(filter-out pedigree_ext.cpp $(PEDIGREE_LIB_SRC).cpp $(PERSON_C_SRC).c $(PERSON_CPP_SRC).cpp, $(wildcard *.cpp)) 12 | HDRS = $(wildcard *.h) 13 | OBJS = $(patsubst %.cpp,./build/%.o,$(SRCS)) 14 | INCLUDES = -I../include/ 15 | DEFINES = $(REDUCER_DEF) $(ABI_DEF) $(ALERT_DEF) 16 | OPTIONS = $(OPT) $(DBG) $(ARCH) -Werror -Wall -fpic $(DEFINES) $(INCLUDES) -gdwarf-4 17 | 18 | PERSON_C = $(RTS_LIBDIR)/$(RTS_C_PERSONALITY_LIB) 19 | PERSON_CPP = $(RTS_LIBDIR)/$(RTS_CXX_PERSONALITY_LIB) 20 | PERSON_C_SRC = personality-c 21 | PERSON_CPP_SRC = personality-cpp 22 | PEDIGREE_LIB = $(RTS_LIBDIR)/$(RTS_PEDIGREE_LIB) 23 | PEDIGREE_LIB_SRC = pedigree_lib 24 | 25 | .PHONY: all clean build 26 | 27 | all: build $(RTS_LIBDIR) $(MAIN).a $(MAIN).so $(PERSON_C).a $(PERSON_C).so $(PERSON_CPP).a $(PERSON_CPP).so $(BITCODE_ABI) 28 | 29 | $(MAIN).a: $(OBJS) 30 | $(AR) rcs $@ $^ 31 | 32 | $(MAIN).so: $(OBJS) 33 | $(CXX) -shared -o $@ $^ 34 | 35 | $(PERSON_C).a: build/$(PERSON_C_SRC).o 36 | $(AR) rcs $@ $^ 37 | 38 | $(PERSON_C).so: build/$(PERSON_C_SRC).o 39 | $(CC) -shared -o $@ $^ -L$(RTS_LIBDIR) -lopencilk 40 | 41 | $(PERSON_CPP).a: build/$(PERSON_CPP_SRC).o 42 | $(AR) rcs $@ $^ 43 | 44 | $(PERSON_CPP).so: ./build/$(PERSON_CPP_SRC).o 45 | $(CXX) -shared -o $@ $^ -L$(RTS_LIBDIR) -lopencilk 46 | 47 | $(PEDIGREE_LIB).a: build/$(PEDIGREE_LIB_SRC).o 48 | $(AR) rcs $@ $^ 49 | 50 | $(PEDIGREE_LIB).so: ./build/$(PEDIGREE_LIB_SRC).o 51 | $(CXX) -shared -o $@ $^ 52 | 53 | build: 54 | mkdir -p $@ 55 | 56 | $(RTS_LIBDIR): 57 | mkdir -p $@ 58 | 59 | build/%.o: %.cpp $(HDRS) 60 | $(CXX) -c $(OPTIONS) -o $@ $< 61 | 62 | build/%.o: %.c $(HDRS) 63 | $(CC) -c $(OPTIONS) -o $@ $< 64 | 65 | build/cilk2c_inlined.bc: cilk2c_inlined.cpp $(HDRS) 66 | $(CXX) $(OPT) -DCHEETAH_API_CONSUMER -DCILK_DEBUG=0 -c -emit-llvm $(INCLUDES) -gdwarf-4 -g -o $@ $< 67 | 68 | $(BITCODE_ABI) : build/cilk2c_inlined.bc 69 | cp $< $@ 70 | 71 | clean: 72 | rm -f $(OBJS) build/$(PERSON_C_SRC).o build/$(PERSON_CPP_SRC).o $(RTS_LIBDIR)/*.a $(RTS_LIBDIR)/*.so $(RTS_LIBDIR)/*.bc *~ 73 | rm -f build/cilk2c_inlined.bc 74 | -------------------------------------------------------------------------------- /runtime/pedigree-internal.h: -------------------------------------------------------------------------------- 1 | #ifndef _PEDIGREE_INTERNAL_H 2 | #define _PEDIGREE_INTERNAL_H 3 | 4 | #include "cilk-internal.h" 5 | #include 6 | #include 7 | 8 | static const uint64_t DPRNG_PRIME = (uint64_t)(-59); 9 | extern uint64_t *__pedigree_dprng_m_array; 10 | extern uint64_t __pedigree_dprng_seed; 11 | 12 | typedef struct __pedigree_frame { 13 | __cilkrts_pedigree pedigree; // Fields for pedigrees. 14 | int64_t rank; 15 | uint64_t dprng_dotproduct; 16 | int64_t dprng_depth; 17 | } __pedigree_frame; 18 | 19 | /////////////////////////////////////////////////////////////////////////// 20 | // Helper methods 21 | 22 | static inline __attribute__((malloc)) __pedigree_frame * 23 | push_pedigree_frame(__cilkrts_worker *w) { 24 | #if ENABLE_EXTENSION 25 | return static_cast<__pedigree_frame*> 26 | (__cilkrts_push_ext_stack(w, sizeof(__pedigree_frame))); 27 | #else 28 | return nullptr; 29 | #endif 30 | } 31 | 32 | static inline void pop_pedigree_frame(__cilkrts_worker *w) { 33 | #if ENABLE_EXTENSION 34 | __cilkrts_pop_ext_stack(w, sizeof(__pedigree_frame)); 35 | #endif 36 | } 37 | 38 | static inline uint64_t __cilkrts_dprng_swap_halves(uint64_t x) { 39 | return (x >> (4 * sizeof(uint64_t))) | (x << (4 * sizeof(uint64_t))); 40 | } 41 | 42 | static inline uint64_t __cilkrts_dprng_mix(uint64_t x) { 43 | for (int i = 0; i < 4; i++) { 44 | x = x * (2*x+1); 45 | x = __cilkrts_dprng_swap_halves(x); 46 | } 47 | return x; 48 | } 49 | 50 | static inline uint64_t __cilkrts_dprng_mix_mod_p(uint64_t x) { 51 | x = __cilkrts_dprng_mix(x); 52 | return x - (DPRNG_PRIME & -(x >= DPRNG_PRIME)); 53 | } 54 | 55 | static inline uint64_t __cilkrts_dprng_sum_mod_p(uint64_t a, uint64_t b) { 56 | uint64_t z = a + b; 57 | if ((z < a) || (z >= DPRNG_PRIME)) { 58 | z -= DPRNG_PRIME; 59 | } 60 | return z; 61 | } 62 | 63 | // Helper method to advance the pedigree and dprng states. 64 | static inline __attribute__((always_inline)) __pedigree_frame * 65 | bump_worker_rank(void) { 66 | #if ENABLE_EXTENSION 67 | __pedigree_frame *frame = (__pedigree_frame *)(__cilkrts_get_extension()); 68 | frame->rank++; 69 | frame->dprng_dotproduct = __cilkrts_dprng_sum_mod_p( 70 | frame->dprng_dotproduct, __pedigree_dprng_m_array[frame->dprng_depth]); 71 | return frame; 72 | #else 73 | return nullptr; 74 | #endif 75 | } 76 | 77 | #endif // _PEDIGREE_INTERNAL_H 78 | -------------------------------------------------------------------------------- /runtime/internal-malloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTERAL_MALLOC_H 2 | #define _INTERAL_MALLOC_H 3 | 4 | #include "rts-config.h" 5 | #include 6 | 7 | typedef struct __cilkrts_worker __cilkrts_worker; 8 | 9 | CHEETAH_INTERNAL extern int cheetah_page_shift; 10 | 11 | enum im_tag { 12 | IM_UNCLASSIFIED, 13 | IM_CLOSURE, 14 | IM_FIBER, 15 | IM_REDUCER_MAP, 16 | IM_NUM_TAGS 17 | }; 18 | 19 | CHEETAH_INTERNAL const char *name_for_im_tag(enum im_tag); 20 | 21 | /* Helper routine to round sizes to alignments, for use with cilk_aligned_alloc. 22 | */ 23 | static inline size_t round_size_to_alignment(size_t alignment, size_t size) { 24 | return (size + alignment - 1) & -alignment; 25 | } 26 | 27 | /* Custom implementation of aligned_alloc. */ 28 | static inline void *cilk_aligned_alloc(size_t alignment, size_t size) { 29 | #if (defined(__linux__) && (__STDC_VERSION__ >= 201112L)) || \ 30 | defined(_ISOC11_SOURCE) || __FreeBSD__ >= 10 || \ 31 | __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101500 32 | return aligned_alloc(alignment, size); 33 | #else 34 | void *ptr; 35 | if (posix_memalign(&ptr, alignment, size) == 0) 36 | return ptr; 37 | return nullptr; 38 | #endif 39 | } 40 | 41 | // public functions (external to source file, internal to library) 42 | CHEETAH_INTERNAL void cilk_internal_malloc_global_init(struct global_state *g); 43 | CHEETAH_INTERNAL void internal_malloc_global_check(global_state *g); 44 | CHEETAH_INTERNAL void 45 | cilk_internal_malloc_global_terminate(struct global_state *g); 46 | CHEETAH_INTERNAL void 47 | cilk_internal_malloc_global_destroy(struct global_state *g); 48 | CHEETAH_INTERNAL void cilk_internal_malloc_per_worker_init(__cilkrts_worker *w); 49 | CHEETAH_INTERNAL void 50 | cilk_internal_malloc_per_worker_destroy(__cilkrts_worker *w); 51 | CHEETAH_INTERNAL void 52 | cilk_internal_malloc_per_worker_terminate(__cilkrts_worker *w); 53 | __attribute__((alloc_size(2), assume_aligned(32), malloc)) 54 | CHEETAH_INTERNAL void * 55 | cilk_internal_malloc(__cilkrts_worker *w, size_t size, enum im_tag tag); 56 | CHEETAH_INTERNAL void cilk_internal_free(__cilkrts_worker *w, void *p, 57 | size_t size, enum im_tag tag); 58 | /* Release memory to the global pool after workers have stopped. */ 59 | CHEETAH_INTERNAL void cilk_internal_free_global(struct global_state *, void *p, 60 | size_t size, enum im_tag tag); 61 | 62 | #endif // _INTERAL_MALLOC_H 63 | -------------------------------------------------------------------------------- /.github/workflows/small-cilkapps.yml: -------------------------------------------------------------------------------- 1 | name: Small Cilk application tests 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | workflow_dispatch: 8 | push: 9 | pull_request: 10 | 11 | concurrency: 12 | # Skip intermediate builds: always. 13 | # Cancel intermediate builds: only if it is a pull request build. 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} 16 | 17 | jobs: 18 | small-apps: 19 | runs-on: ${{ matrix.os }} 20 | container: 21 | image: ${{(startsWith(matrix.os, 'ubuntu') && 'ghcr.io/llvm/ci-ubuntu-22.04:latest') || null}} 22 | volumes: 23 | - /mnt/:/mnt/ 24 | options: --user root 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | os: [ubuntu-latest, macOS-latest] 29 | steps: 30 | - name: checkout 31 | uses: actions/checkout@v4 32 | - name: Setup OpenCilk compiler 33 | id: build-opencilk 34 | uses: OpenCilk/actions/build-opencilk-project@main 35 | with: 36 | projects: clang 37 | extra_cmake_args: -DLLVM_TARGETS_TO_BUILD=host 38 | os_list: '${{ matrix.os }}' 39 | - name: Build cheetah 40 | id: build-cheetah 41 | shell: bash 42 | run: | 43 | builddir="$(pwd)"/build 44 | opencilkdir='${{ steps.build-opencilk.outputs.opencilk-builddir }}' 45 | mkdir -p $builddir 46 | cmake -G Ninja \ 47 | -B "$builddir" \ 48 | -DCMAKE_BUILD_TYPE=Release \ 49 | -DCMAKE_C_COMPILER=$opencilkdir/bin/clang \ 50 | -DCMAKE_CXX_COMPILER=$opencilkdir/bin/clang++ \ 51 | -DLLVM_CMAKE_DIR=$opencilkdir 52 | ninja -C "$builddir" 53 | - name: Checkout small application tests 54 | uses: actions/checkout@v4 55 | with: 56 | repository: OpenCilk/smallapps 57 | path: smallapps 58 | - name: make check 59 | shell: bash 60 | run: | 61 | cheetahdir="$(pwd)"/build 62 | opencilkdir='${{ steps.build-opencilk.outputs.opencilk-builddir }}' 63 | make_prefix="" 64 | if [ "${{ runner.os }}" == "macOS" ]; then 65 | # Use xcrun to build benchmarks on macOS. 66 | make_prefix="xcrun" 67 | fi 68 | $make_prefix make -C smallapps check \ 69 | CC=$opencilkdir/bin/clang \ 70 | CXX=$opencilkdir/bin/clang++ \ 71 | EXTRA_CFLAGS="--opencilk-resource-dir=$cheetahdir" \ 72 | EXTRA_LDFLAGS="--opencilk-resource-dir=$cheetahdir" 73 | -------------------------------------------------------------------------------- /handcomp_test/fib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../runtime/cilk2c.h" 5 | #include "../runtime/cilk2c_inlined.cpp" 6 | #include "ktiming.h" 7 | 8 | 9 | #ifndef TIMING_COUNT 10 | #define TIMING_COUNT 1 11 | #endif 12 | 13 | /* 14 | * fib 39: 63245986 15 | * fib 40: 102334155 16 | * fib 41: 165580141 17 | * fib 42: 267914296 18 | 19 | int fib(int n) { 20 | int x, y, _tmp; 21 | 22 | if(n < 2) { 23 | return n; 24 | } 25 | 26 | x = cilk_spawn fib(n - 1); 27 | y = fib(n - 2); 28 | cilk_sync; 29 | 30 | return x+y; 31 | } 32 | */ 33 | 34 | extern size_t ZERO; 35 | void __attribute__((weak)) dummy(void *p) { return; } 36 | 37 | static void __attribute__ ((noinline)) fib_spawn_helper(int *x, int n, 38 | __cilkrts_stack_frame *parent); 39 | 40 | int fib(int n) { 41 | int x = 0, y, _tmp; 42 | 43 | if(n < 2) 44 | return n; 45 | 46 | dummy(alloca(ZERO)); 47 | __cilkrts_stack_frame sf; 48 | __cilkrts_enter_frame(&sf); 49 | 50 | /* x = spawn fib(n-1) */ 51 | if (!__cilk_prepare_spawn(&sf)) { 52 | fib_spawn_helper(&x, n-1, &sf); 53 | } 54 | 55 | y = fib(n - 2); 56 | 57 | /* cilk_sync */ 58 | __cilk_sync_nothrow(&sf); 59 | _tmp = x + y; 60 | 61 | __cilk_parent_epilogue(&sf); 62 | 63 | return _tmp; 64 | } 65 | 66 | static void __attribute__ ((noinline)) fib_spawn_helper(int *x, int n, 67 | __cilkrts_stack_frame *parent) { 68 | 69 | __cilkrts_stack_frame sf; 70 | __cilkrts_enter_frame_helper(&sf, parent, false); 71 | __cilkrts_detach(&sf, parent); 72 | *x = fib(n); 73 | __cilk_helper_epilogue(&sf, parent, false); 74 | } 75 | 76 | int main(int argc, char * args[]) { 77 | int i; 78 | int n, res; 79 | clockmark_t begin, end; 80 | uint64_t running_time[TIMING_COUNT]; 81 | 82 | if(argc != 2) { 83 | fprintf(stderr, "Usage: fib [] \n"); 84 | exit(1); 85 | } 86 | 87 | n = atoi(args[1]); 88 | 89 | for(i = 0; i < TIMING_COUNT; i++) { 90 | begin = ktiming_getmark(); 91 | res = fib(n); 92 | end = ktiming_getmark(); 93 | running_time[i] = ktiming_diff_nsec(&begin, &end); 94 | } 95 | printf("Result: %d\n", res); 96 | print_runtime(running_time, TIMING_COUNT); 97 | 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /include/cilk/ostream_reducer.h: -------------------------------------------------------------------------------- 1 | #ifndef _OSTREAM_REDUCER_H 2 | #define _OSTREAM_REDUCER_H 3 | 4 | #ifdef __cplusplus 5 | 6 | #include 7 | #include 8 | 9 | /* Adapted from Intel Cilk Plus */ 10 | 11 | namespace cilk { 12 | 13 | template 14 | class ostream_view : public std::basic_ostream 15 | { 16 | typedef std::basic_ostream base; 17 | typedef std::basic_ostream ostream_type; 18 | 19 | // A non-leftmost view is associated with a private string buffer. (The 20 | // leftmost view is associated with the buffer of the reducer's associated 21 | // ostream, so its private buffer is unused.) 22 | // 23 | std::basic_stringbuf m_buffer; 24 | 25 | public: 26 | void reduce(ostream_view* other) 27 | { 28 | // Writing an empty buffer results in failure. Testing `sgetc()` is the 29 | // easiest way of checking for an empty buffer. 30 | if (other->m_buffer.sgetc() != Traits::eof()) { 31 | *this << (&other->m_buffer); 32 | } 33 | } 34 | 35 | static void reduce(void *left_v, void *right_v) { 36 | ostream_view *left = 37 | static_cast *>(left_v); 38 | ostream_view *right = 39 | static_cast *>(right_v); 40 | left->reduce(right); 41 | right->~ostream_view(); 42 | } 43 | 44 | static void identity(void *view) { 45 | new (view) ostream_view(); 46 | } 47 | 48 | /** Non-leftmost (identity) view constructor. The view is associated with 49 | * its internal buffer. Required by @ref monoid_base. 50 | */ 51 | ostream_view() : base(&m_buffer) {} 52 | 53 | /** Leftmost view constructor. The view is associated with an existing 54 | * ostream. 55 | */ 56 | ostream_view(const ostream_type& os) : base(0) 57 | { 58 | base::rdbuf(os.rdbuf()); // Copy stream buffer 59 | base::flags(os.flags()); // Copy formatting flags 60 | base::setstate(os.rdstate()); // Copy error state 61 | } 62 | 63 | }; 64 | 65 | template> 66 | using ostream_reducer = ostream_view 67 | _Hyperobject(&ostream_view>::identity, 68 | &ostream_view>::reduce); 69 | 70 | } // namespace cilk 71 | 72 | #endif // __cplusplus 73 | 74 | #endif // _OSTREAM_REDUCER_H 75 | -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/FindPrefixFromConfig.cmake: -------------------------------------------------------------------------------- 1 | # Find the prefix from the `*Config.cmake` file being generated. 2 | # 3 | # When generating an installed `*Config.cmake` file, we often want to be able 4 | # to refer to the ancestor directory which contains all the installed files. 5 | # 6 | # We want to do this without baking in an absolute path when the config file is 7 | # generated, in order to allow for a "relocatable" binary distribution that 8 | # doesn't need to know what path it ends up being installed at when it is 9 | # built. 10 | # 11 | # The solution that we know the relative path that the config file will be at 12 | # within that prefix, like `"${prefix_var}/lib/cmake/${project}"`, so we count 13 | # the number of components in that path to figure out how many parent dirs we 14 | # need to traverse from the location of the config file to get to the prefix 15 | # dir. 16 | # 17 | # out_var: 18 | # variable to set the "return value" of the function, which is the code to 19 | # include in the config file under construction. 20 | # 21 | # prefix_var: 22 | # Name of the variable to define in the returned code (not directory for the 23 | # faller!) that will contain the prefix path. 24 | # 25 | # path_to_leave: 26 | # Path from the prefix to the config file, a relative path which we wish to 27 | # go up and out from to find the prefix directory. 28 | function(find_prefix_from_config out_var prefix_var path_to_leave) 29 | if(IS_ABSOLUTE "${path_to_leave}") 30 | # Because the path is absolute, we don't care about `path_to_leave` 31 | # because we can just "jump" to the absolute path rather than work 32 | # our way there relatively. 33 | set(config_code 34 | "# Installation prefix is fixed absolute path" 35 | "set(${prefix_var} \"${CMAKE_INSTALL_PREFIX}\")") 36 | else() 37 | # `path_to_leave` is relative. Relative to what? The install prefix. 38 | # We therefore go up enough parent directories to get back to the 39 | # install prefix, and avoid hard-coding any absolute paths. 40 | set(config_code 41 | "# Compute the installation prefix from this LLVMConfig.cmake file location." 42 | "get_filename_component(${prefix_var} \"\${CMAKE_CURRENT_LIST_FILE}\" PATH)") 43 | # Construct the proper number of get_filename_component(... PATH) 44 | # calls to compute the installation prefix. 45 | string(REGEX REPLACE "/" ";" _count "${path_to_leave}") 46 | foreach(p ${_count}) 47 | list(APPEND config_code 48 | "get_filename_component(${prefix_var} \"\${${prefix_var}}\" PATH)") 49 | endforeach(p) 50 | endif() 51 | string(REPLACE ";" "\n" config_code "${config_code}") 52 | set("${out_var}" "${config_code}" PARENT_SCOPE) 53 | endfunction() 54 | -------------------------------------------------------------------------------- /handcomp_test/getoptions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "getoptions.h" 6 | 7 | /* Used by example programs to evaluate command line options */ 8 | 9 | void get_options(int argc, char *argv[], const char *specs[], int *types,...) 10 | { 11 | va_list ap; 12 | int type, i; 13 | int *intval; 14 | double *doubleval; 15 | long *longval; 16 | char * stringval; 17 | 18 | va_start(ap, types); 19 | 20 | while (((type = *types++) != 0) && (specs != 0)) { 21 | switch (type) { 22 | case INTARG: 23 | intval = (int *) va_arg(ap, int *); 24 | for (i = 1; i < (argc - 1); i++) 25 | if (!(strcmp(argv[i], specs[0]))) { 26 | *intval = atoi(argv[i + 1]); 27 | argv[i][0] = 0; 28 | argv[i + 1][0] = 0; 29 | } 30 | break; 31 | case DOUBLEARG: 32 | doubleval = (double *) va_arg(ap, double *); 33 | for (i = 1; i < (argc - 1); i++) 34 | if (!(strcmp(argv[i], specs[0]))) { 35 | *doubleval = atof(argv[i + 1]); 36 | argv[i][0] = 0; 37 | argv[i + 1][0] = 0; 38 | } 39 | break; 40 | case LONGARG: 41 | longval = (long *) va_arg(ap, long *); 42 | for (i = 1; i < (argc - 1); i++) 43 | if (!(strcmp(argv[i], specs[0]))) { 44 | *longval = atol(argv[i + 1]); 45 | argv[i][0] = 0; 46 | argv[i + 1][0] = 0; 47 | } 48 | break; 49 | case BOOLARG: 50 | intval = (int *) va_arg(ap, int *); 51 | *intval = 0; 52 | for (i = 1; i < argc; i++) 53 | if (!(strcmp(argv[i], specs[0]))) { 54 | *intval = 1; 55 | argv[i][0] = 0; 56 | } 57 | break; 58 | case STRINGARG: 59 | stringval = (char *) va_arg(ap, char *); 60 | for (i = 1; i < (argc - 1); i++) 61 | if (!(strcmp(argv[i], specs[0]))) { 62 | strcpy(stringval, (char *)argv[i + 1]); 63 | argv[i][0] = 0; 64 | argv[i + 1][0] = 0; 65 | } 66 | break; 67 | case BENCHMARK: 68 | intval = (int *) va_arg(ap, int *); 69 | *intval = 0; 70 | for (i = 1; i < argc; i++) { 71 | if (!(strcmp(argv[i], specs[0]))) { 72 | *intval = 2; 73 | if ((i + 1) < argc) { 74 | if (!(strcmp(argv[i + 1], "short"))) 75 | *intval = 1; 76 | if (!(strcmp(argv[i + 1], "medium"))) 77 | *intval = 2; 78 | if (!(strcmp(argv[i + 1], "long"))) 79 | *intval = 3; 80 | argv[i + 1][0] = 0; 81 | } 82 | argv[i][0] = 0; 83 | } 84 | } 85 | break; 86 | } 87 | specs++; 88 | } 89 | va_end(ap); 90 | 91 | for (i = 1; i < argc; i++) 92 | if (argv[i][0] != 0) 93 | printf("\nInvalid option: %s\n", argv[i]); 94 | 95 | } 96 | -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/FindLibEdit.cmake: -------------------------------------------------------------------------------- 1 | #.rst: 2 | # FindLibEdit 3 | # ----------- 4 | # 5 | # Find libedit library and headers 6 | # 7 | # The module defines the following variables: 8 | # 9 | # :: 10 | # 11 | # LibEdit_FOUND - true if libedit was found 12 | # LibEdit_INCLUDE_DIRS - include search path 13 | # LibEdit_LIBRARIES - libraries to link 14 | # LibEdit_VERSION_STRING - version number 15 | 16 | find_package(PkgConfig QUIET) 17 | pkg_check_modules(PC_LIBEDIT QUIET libedit) 18 | 19 | find_path(LibEdit_INCLUDE_DIRS NAMES histedit.h HINTS ${PC_LIBEDIT_INCLUDE_DIRS}) 20 | find_library(LibEdit_LIBRARIES NAMES edit HINTS ${PC_LIBEDIT_LIBRARY_DIRS}) 21 | 22 | include(CheckIncludeFile) 23 | if(LibEdit_INCLUDE_DIRS AND EXISTS "${LibEdit_INCLUDE_DIRS}/histedit.h") 24 | include(CMakePushCheckState) 25 | cmake_push_check_state() 26 | list(APPEND CMAKE_REQUIRED_INCLUDES ${LibEdit_INCLUDE_DIRS}) 27 | list(APPEND CMAKE_REQUIRED_LIBRARIES ${LibEdit_LIBRARIES}) 28 | check_include_file(histedit.h HAVE_HISTEDIT_H) 29 | cmake_pop_check_state() 30 | if (HAVE_HISTEDIT_H) 31 | file(STRINGS "${LibEdit_INCLUDE_DIRS}/histedit.h" 32 | libedit_major_version_str 33 | REGEX "^#define[ \t]+LIBEDIT_MAJOR[ \t]+[0-9]+") 34 | string(REGEX REPLACE "^#define[ \t]+LIBEDIT_MAJOR[ \t]+([0-9]+)" "\\1" 35 | libedit_major_version "${libedit_major_version_str}") 36 | 37 | file(STRINGS "${LibEdit_INCLUDE_DIRS}/histedit.h" 38 | libedit_minor_version_str 39 | REGEX "^#define[ \t]+LIBEDIT_MINOR[ \t]+[0-9]+") 40 | string(REGEX REPLACE "^#define[ \t]+LIBEDIT_MINOR[ \t]+([0-9]+)" "\\1" 41 | libedit_minor_version "${libedit_minor_version_str}") 42 | 43 | set(LibEdit_VERSION_STRING "${libedit_major_version}.${libedit_minor_version}") 44 | else() 45 | set(LibEdit_INCLUDE_DIRS "") 46 | set(LibEdit_LIBRARIES "") 47 | endif() 48 | endif() 49 | 50 | include(FindPackageHandleStandardArgs) 51 | find_package_handle_standard_args(LibEdit 52 | FOUND_VAR 53 | LibEdit_FOUND 54 | REQUIRED_VARS 55 | LibEdit_INCLUDE_DIRS 56 | LibEdit_LIBRARIES 57 | VERSION_VAR 58 | LibEdit_VERSION_STRING) 59 | mark_as_advanced(LibEdit_INCLUDE_DIRS LibEdit_LIBRARIES) 60 | 61 | if (LibEdit_FOUND AND NOT TARGET LibEdit::LibEdit) 62 | add_library(LibEdit::LibEdit UNKNOWN IMPORTED) 63 | set_target_properties(LibEdit::LibEdit PROPERTIES 64 | IMPORTED_LOCATION ${LibEdit_LIBRARIES} 65 | INTERFACE_INCLUDE_DIRECTORIES ${LibEdit_INCLUDE_DIRS}) 66 | endif() 67 | -------------------------------------------------------------------------------- /android/README.md: -------------------------------------------------------------------------------- 1 | # Building the OpenCilk runtime system for Android 2 | 3 | These instructions describe how to build the OpenCilk runtime system for Android. This process uses `ndk-build` to build shared libraries that can be [incorporated into an Android project](https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs). 4 | 5 | > [!NOTE] 6 | > At this time, OpenCilk requires Android API 28 or newer and only supports the `arm64-v8a` and `x86_64` [Android ABIs](https://developer.android.com/ndk/guides/abis). 7 | 8 | ## Setup Android Studio and NDK 9 | 10 | > [!TIP] 11 | > Save the `clang-` binary distributed with NDK before replacing it with the OpenCilk version, so you can restore it if anything goes wrong. 12 | 13 | 1. Install [Android Studio](https://developer.android.com/studio) with [NDK](https://developer.android.com/studio/projects/install-ndk) onto your system. 14 | 2. Replace [NDK's copy of `clang-`](https://developer.android.com/ndk/guides/other_build_systems#overview) with OpenCilk's `clang-` binary. For example, for NDK version 28, which includes a prebuilt LLVM toolchain based on LLVM 19, replace the `clang-19` binary in that NDK with OpenCilk's `clang-19` binary. 15 | 16 | ## Build the runtime system 17 | 18 | 1. Export the `NDK` environment variable set to the path to the NDK in Android Studio. 19 | 2. Run `$NDK/ndk-build` inside the `android/jni` subdirectory of this repository. 20 | 3. Run `make -f libopencilk-abi.mk` inside the `android/jni` subdirectory. 21 | 22 | ## Use OpenCilk in your Android project 23 | 24 | 1. Make sure your Android project contains a `jniLibs` subdirectory in the [correct place](https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs), for example, as a subdirectory within `src/main`. 25 | 2. Copy `android/libs/*` in your copy of this repository into the `jniLibs` subdirectory of your Android project. 26 | 3. To compile the Cilk parts of your Android project, add these flags to `CMAKE_C_FLAGS` or `CMAKE_CXX_FLAGS`: 27 | 28 | ```cmake 29 | -fopencilk --opencilk-abi-bitcode=${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libopencilk-abi.bc -femulated-tls 30 | ``` 31 | 32 | 4. To link your Android project with Cilk code, add these flags to `CMAKE_SHARED_LINKER_FLAGS`: 33 | 34 | ```cmake 35 | -fopencilk -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI} 36 | ``` 37 | 38 | 5. [Optional] To use OpenCilk runtime headers, first copy the contents of the `include/cilk` subdirectory in this repository into an `include/cilk` subdirectory in your Android project, such as in `app/src/main/cpp/include/cilk`. Then use `include_directories()` to add that `include` directory, such as via `include_directories(${CMAKE_SOURCE_DIR}/include)`. 39 | -------------------------------------------------------------------------------- /cmake/Modules/HandleCompilerRT.cmake: -------------------------------------------------------------------------------- 1 | function(find_compiler_rt_library name dest) 2 | if (NOT DEFINED CHEETAH_COMPILE_FLAGS) 3 | message(FATAL_ERROR "CHEETAH_COMPILE_FLAGS must be defined when using this function") 4 | endif() 5 | set(dest "" PARENT_SCOPE) 6 | set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${CHEETAH_COMPILE_FLAGS} 7 | "--rtlib=compiler-rt" "--print-libgcc-file-name") 8 | if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET) 9 | list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}") 10 | endif() 11 | get_property(CHEETAH_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE) 12 | string(REPLACE " " ";" CHEETAH_CXX_FLAGS "${CHEETAH_CXX_FLAGS}") 13 | list(APPEND CLANG_COMMAND ${CHEETAH_CXX_FLAGS}) 14 | execute_process( 15 | COMMAND ${CLANG_COMMAND} 16 | RESULT_VARIABLE HAD_ERROR 17 | OUTPUT_VARIABLE LIBRARY_FILE 18 | ) 19 | string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) 20 | file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) 21 | string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}") 22 | if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}") 23 | message(STATUS "Found compiler-rt library: ${LIBRARY_FILE}") 24 | set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE) 25 | else() 26 | message(STATUS "Failed to find compiler-rt library") 27 | endif() 28 | endfunction() 29 | 30 | function(find_compiler_rt_dir dest) 31 | if (NOT DEFINED CHEETAH_COMPILE_FLAGS) 32 | message(FATAL_ERROR "CHEETAH_COMPILE_FLAGS must be defined when using this function") 33 | endif() 34 | set(dest "" PARENT_SCOPE) 35 | if (APPLE) 36 | set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${CHEETAH_COMPILE_FLAGS} 37 | "-print-file-name=lib") 38 | execute_process( 39 | COMMAND ${CLANG_COMMAND} 40 | RESULT_VARIABLE HAD_ERROR 41 | OUTPUT_VARIABLE LIBRARY_DIR 42 | ) 43 | string(STRIP "${LIBRARY_DIR}" LIBRARY_DIR) 44 | file(TO_CMAKE_PATH "${LIBRARY_DIR}" LIBRARY_DIR) 45 | set(LIBRARY_DIR "${LIBRARY_DIR}/darwin") 46 | else() 47 | set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${CHEETAH_COMPILE_FLAGS} 48 | "--rtlib=compiler-rt" "--print-libgcc-file-name") 49 | execute_process( 50 | COMMAND ${CLANG_COMMAND} 51 | RESULT_VARIABLE HAD_ERROR 52 | OUTPUT_VARIABLE LIBRARY_FILE 53 | ) 54 | string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) 55 | file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) 56 | get_filename_component(LIBRARY_DIR "${LIBRARY_FILE}" DIRECTORY) 57 | endif() 58 | if (NOT HAD_ERROR AND EXISTS "${LIBRARY_DIR}") 59 | message(STATUS "Found compiler-rt directory: ${LIBRARY_DIR}") 60 | set(${dest} "${LIBRARY_DIR}" PARENT_SCOPE) 61 | else() 62 | message(STATUS "Failed to find compiler-rt directory") 63 | endif() 64 | endfunction() 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The OpenCilk runtime system 2 | 3 | This repository contains the source code of the OpenCilk runtime system. This library is intended to be used with the [OpenCilk compiler](https://github.com/OpenCilk/opencilk-project) and can either be built [together with the compiler](https://www.opencilk.org/doc/users-guide/build-opencilk-from-source/) or as a standalone library. 4 | 5 | ## Building a standalone copy of the OpenCilk runtime 6 | 7 | These instructions assume that you are building the OpenCilk runtime system using the OpenCilk compiler. 8 | 9 | ### Using Makefiles 10 | 11 | 1. If necessary, update the `COMPILER_BASE` variable in `config.mk` to point to the directory containing the OpenCilk compiler binaries, e.g., `/path/to/opencilk-project/build/bin/`. When it executes `clang` and other OpenCilk compiler binaries, the Makefile prepends this path to those binaries. 12 | 2. Run `make`. 13 | 14 | To clean the build, run `make clean`. 15 | 16 | ### Using CMake 17 | 18 | 1. Make a build directory at the top level and enter it: 19 | 20 | ```console 21 | mkdir build 22 | cd build 23 | ``` 24 | 25 | 2. Configure CMake. Make sure to specify `CMAKE_C_COMPILER`, `CMAKE_CXX_COMPILER`, and `LLVM_CMAKE_DIR` to point to the corresponding build or installation of the OpenCilk compiler binaries. In addition, set `CMAKE_BUILD_TYPE` to specify the build type, such as: 26 | 27 | - `Debug`, for an unoptimized build with all assertions enabled (default); 28 | - `Release`, for an fully optimized build with assertions disabled; or 29 | - `RelWithDebInfo`, to enable some optimizations and assertions. 30 | 31 | ```console 32 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/path/to/opencilk-project/build/bin/clang -DCMAKE_CXX_COMPILER=/path/to/opencilk-project/build/bin/clang++ -DLLVM_CMAKE_DIR=/path/to/opencilk-project/build ../ 33 | ``` 34 | 35 | 3. Build the runtime: 36 | 37 | ```console 38 | cmake --build . -- -j 39 | ``` 40 | 41 | To clean the build, run `cmake --build . --target clean` from the build directory. 42 | 43 | ## Using a standalone build of the OpenCilk runtime 44 | 45 | The OpenCilk compiler accepts the flag `--opencilk-resource-dir=/path/to/cheetah` to specify where to find all relevant OpenCilk runtime files, including the runtime library, the bitcode ABI file, and associated header files. This resource directory should have `include/` and `lib/` as subdirectories. For example, if you built the standalone OpenCilk runtime using CMake, then pass the flag `--opencilk-resource-dir=/path/to/cheetah/build` to the OpenCilk compiler to link against that standalone build as follows: 46 | 47 | ```console 48 | /path/to/opencilk-project/build/bin/clang -o fib fib.c -fopencilk -O3 --opencilk-resource-dir=/path/to/cheetah/build 49 | ``` 50 | -------------------------------------------------------------------------------- /runtime/local-reducer-api.cpp: -------------------------------------------------------------------------------- 1 | #include "cilk-internal.h" 2 | #include "cilk2c_inlined.h" 3 | #include "local-hypertable.h" 4 | #include "local-reducer-api.h" 5 | #include "rts-config.h" 6 | 7 | #pragma clang diagnostic push 8 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 9 | 10 | __reducer_base::__reducer_base() 11 | { 12 | // This would be a great place to register the reducer, 13 | // but doing so would break the equivalence between 14 | // leftmost view and dynamic views. The derived class 15 | // identity operation would need to pass a flag to this 16 | // constructor to suppress registration. 17 | } 18 | 19 | __reducer_base::~__reducer_base() 20 | { 21 | } 22 | 23 | static void reducer_register(struct bucket &b) 24 | __CILKRTS_NOTHROW 25 | { 26 | struct hyper_table *table = 27 | get_local_hyper_table(__cilkrts_get_tls_worker()); 28 | bool success = insert_hyperobject(table, b); 29 | CILK_ASSERT(success && "Failed to register reducer."); 30 | (void)success; 31 | } 32 | 33 | void __cilkrts_reducer_register_0(__reducer_base *key) 34 | __CILKRTS_NOTHROW 35 | { 36 | struct bucket b { 37 | .key = (uintptr_t)key, 38 | .data = { .view = nullptr, .extra = key } 39 | }; 40 | reducer_register(b); 41 | } 42 | 43 | void __cilkrts_reducer_register_1(void *key, __reducer_callbacks *cb) 44 | __CILKRTS_NOTHROW 45 | { 46 | struct bucket b { 47 | .key = (uintptr_t)key, 48 | .data = { .view = key, .extra = &cb->reduce }, 49 | }; 50 | reducer_register(b); 51 | } 52 | 53 | void __cilkrts_reducer_register_2(void *key, void (*reduce)(void *, void *)) 54 | __CILKRTS_NOTHROW 55 | { 56 | struct bucket b { 57 | .key = (uintptr_t)key, 58 | .data = { .view = key, .extra = reduce }, 59 | }; 60 | reducer_register(b); 61 | } 62 | 63 | void __cilkrts_reducer_unregister(void *key) noexcept { 64 | if (struct hyper_table *table = get_hyper_table()) { 65 | bool success = remove_hyperobject(table, (uintptr_t)key); 66 | /* CILK_ASSERT(success && "Failed to unregister reducer."); */ 67 | (void)success; 68 | } 69 | } 70 | 71 | #pragma clang diagnostic pop 72 | 73 | CHEETAH_INTERNAL 74 | __reducer_base *internal_reducer_lookup(__cilkrts_worker *w, 75 | __reducer_base *key) { 76 | struct hyper_table *table = get_local_hyper_table(w); 77 | struct bucket *b = find_hyperobject(table, (uintptr_t)key); 78 | if (__builtin_expect(!!b, true)) { 79 | CILK_ASSERT_POINTER_EQUAL(key, (void *)b->key); 80 | // Return the existing view. 81 | return std::get<__reducer_base *>(b->data.extra); 82 | } 83 | 84 | return __cilkrts_insert_new_view_0(table, key); 85 | } 86 | 87 | CHEETAH_INTERNAL 88 | void internal_reducer_remove(__cilkrts_worker *w, void *key) { 89 | struct hyper_table *table = get_local_hyper_table(w); 90 | bool success = remove_hyperobject(table, (uintptr_t)key); 91 | (void)success; 92 | } 93 | -------------------------------------------------------------------------------- /runtime/rts-config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_H 2 | #define _CONFIG_H 3 | 4 | #ifdef CHEETAH_API_CONSUMER 5 | 6 | #define CHEETAH_API extern "C" 7 | #define CHEETAH_INTERNAL /* empty */ 8 | #define CHEETAH_INTERNAL_NORETURN __attribute__((noreturn, nothrow)) 9 | 10 | #else 11 | 12 | /* Functions defined in the library and visible outside the library. 13 | On ELF systems the definitions can be marked protected. */ 14 | #ifdef __ELF__ 15 | #define CHEETAH_API extern "C" __attribute((visibility("protected"))) 16 | #else 17 | #define CHEETAH_API extern "C" 18 | #endif 19 | 20 | /* Functions defined in the library and not visible outside the library. */ 21 | #define CHEETAH_INTERNAL __attribute((visibility("hidden"))) 22 | #define CHEETAH_INTERNAL_NORETURN \ 23 | __attribute((noreturn, nothrow, visibility("hidden"))) 24 | 25 | #endif /* CHEETAH_API_CONSUMER */ 26 | 27 | #define CHEETAH_COLD [[gnu::cold]] 28 | 29 | #ifndef __CILKRTS_VERSION 30 | #define __CILKRTS_VERSION 0x0 31 | #endif 32 | 33 | #ifndef __CILKRTS_ABI_VERSION 34 | #define __CILKRTS_ABI_VERSION 4 35 | #endif 36 | 37 | #ifndef CILK_DEBUG 38 | #define CILK_DEBUG 1 39 | #endif 40 | 41 | #ifndef CILK_ENABLE_ASAN_HOOKS 42 | #define CILK_ENABLE_ASAN_HOOKS 0 43 | #endif 44 | 45 | #ifndef CILK_STATS 46 | #define CILK_STATS 0 47 | #endif 48 | 49 | #ifndef CILK_CACHE_LINE 50 | // Use 128-bit cache lines to account for adjacent-cache-line prefetchers. 51 | #define CILK_CACHE_LINE 128 52 | #endif 53 | 54 | #ifndef BUSY_PAUSE 55 | #define BUSY_PAUSE 1 56 | #endif 57 | 58 | #ifndef BUSY_LOOP_SPIN 59 | #define BUSY_LOOP_SPIN 4096 / BUSY_PAUSE 60 | #endif 61 | 62 | #ifndef ENABLE_THIEF_SLEEP 63 | #define ENABLE_THIEF_SLEEP 1 64 | #endif 65 | 66 | #ifndef ENABLE_EXTENSION 67 | #define ENABLE_EXTENSION 1 68 | #endif 69 | 70 | #ifndef ENABLE_WORKER_PINNING 71 | #define ENABLE_WORKER_PINNING 0 72 | #endif 73 | 74 | #ifndef MIN_NUM_PAGES_PER_STACK 75 | #define MIN_NUM_PAGES_PER_STACK 4 // must be greater than 1 76 | #endif 77 | 78 | _Static_assert(MIN_NUM_PAGES_PER_STACK >= 2, "Invalid Cheetah RTS config: MIN_NUM_PAGES_PER_STACK must be at least 2"); 79 | 80 | #ifndef MAX_NUM_PAGES_PER_STACK 81 | #define MAX_NUM_PAGES_PER_STACK 2000 82 | #endif 83 | 84 | _Static_assert(MAX_NUM_PAGES_PER_STACK >= MIN_NUM_PAGES_PER_STACK, "Invalid Cheetah RTS config: MAX_NUM_PAGES_PER_STACK must be at least MIN_NUM_PAGES_PER_STACK"); 85 | 86 | #ifndef DEFAULT_NPROC 87 | #define DEFAULT_NPROC 0 // 0 for # of cores available 88 | #endif 89 | 90 | #ifndef DEFAULT_DEQ_DEPTH 91 | #define DEFAULT_DEQ_DEPTH 1024 92 | #endif 93 | 94 | #ifndef LG_STACK_SIZE 95 | #define LG_STACK_SIZE 20 // 1 MBytes 96 | #endif 97 | 98 | #ifndef DEFAULT_STACK_SIZE 99 | #define DEFAULT_STACK_SIZE (1U << LG_STACK_SIZE) // 1 MBytes 100 | #endif 101 | 102 | #ifndef DEFAULT_FIBER_POOL_CAP 103 | #define DEFAULT_FIBER_POOL_CAP 8 // initial per-worker fiber pool capacity 104 | #endif 105 | 106 | #ifndef MAX_CALLBACKS 107 | #define MAX_CALLBACKS 32 // Maximum number of init or exit callbacks 108 | #endif 109 | 110 | #endif // _CONFIG_H 111 | -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/HandleOutOfTreeLLVM.cmake: -------------------------------------------------------------------------------- 1 | if (NOT DEFINED LLVM_PATH) 2 | set(LLVM_PATH ${CMAKE_CURRENT_LIST_DIR}/../../llvm CACHE PATH "" FORCE) 3 | endif() 4 | 5 | if(NOT IS_DIRECTORY ${LLVM_PATH}) 6 | message(FATAL_ERROR 7 | "The provided LLVM_PATH (${LLVM_PATH}) is not a valid directory. Note that " 8 | "building libc++ outside of the monorepo is not supported anymore. Please " 9 | "use a Standalone build against the monorepo, a Runtimes build or a classic " 10 | "monorepo build.") 11 | endif() 12 | 13 | set(LLVM_INCLUDE_DIR ${LLVM_PATH}/include CACHE PATH "Path to llvm/include") 14 | set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree") 15 | set(LLVM_MAIN_SRC_DIR ${LLVM_PATH}) 16 | set(LLVM_CMAKE_DIR "${LLVM_PATH}/cmake/modules") 17 | set(LLVM_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) 18 | set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_CURRENT_BINARY_DIR}/lib") 19 | 20 | if (EXISTS "${LLVM_CMAKE_DIR}") 21 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 22 | elseif (EXISTS "${LLVM_MAIN_SRC_DIR}/cmake/modules") 23 | list(APPEND CMAKE_MODULE_PATH "${LLVM_MAIN_SRC_DIR}/cmake/modules") 24 | else() 25 | message(FATAL_ERROR "Neither ${LLVM_CMAKE_DIR} nor ${LLVM_MAIN_SRC_DIR}/cmake/modules found. " 26 | "This is not a supported configuration.") 27 | endif() 28 | 29 | message(STATUS "Configuring for standalone build.") 30 | 31 | # By default, we target the host, but this can be overridden at CMake invocation time. 32 | include(GetHostTriple) 33 | get_host_triple(LLVM_INFERRED_HOST_TRIPLE) 34 | set(LLVM_HOST_TRIPLE "${LLVM_INFERRED_HOST_TRIPLE}" CACHE STRING "Host on which LLVM binaries will run") 35 | set(LLVM_DEFAULT_TARGET_TRIPLE "${LLVM_HOST_TRIPLE}" CACHE STRING "Target triple used by default.") 36 | 37 | # Add LLVM Functions -------------------------------------------------------- 38 | if (WIN32) 39 | set(LLVM_ON_UNIX 0) 40 | set(LLVM_ON_WIN32 1) 41 | else() 42 | set(LLVM_ON_UNIX 1) 43 | set(LLVM_ON_WIN32 0) 44 | endif() 45 | 46 | include(AddLLVM OPTIONAL) 47 | 48 | # LLVM Options -------------------------------------------------------------- 49 | if (NOT DEFINED LLVM_INCLUDE_TESTS) 50 | set(LLVM_INCLUDE_TESTS ON) 51 | endif() 52 | if (NOT DEFINED LLVM_INCLUDE_DOCS) 53 | set(LLVM_INCLUDE_DOCS ON) 54 | endif() 55 | if (NOT DEFINED LLVM_ENABLE_SPHINX) 56 | set(LLVM_ENABLE_SPHINX OFF) 57 | endif() 58 | 59 | if (LLVM_INCLUDE_TESTS) 60 | # Required LIT Configuration ------------------------------------------------ 61 | # Define the default arguments to use with 'lit', and an option for the user 62 | # to override. 63 | set(LLVM_DEFAULT_EXTERNAL_LIT "${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py") 64 | set(LIT_ARGS_DEFAULT "-sv --show-xfail --show-unsupported") 65 | if (MSVC OR XCODE) 66 | set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") 67 | endif() 68 | set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") 69 | endif() 70 | 71 | # Required doc configuration 72 | if (LLVM_ENABLE_SPHINX) 73 | find_package(Sphinx REQUIRED) 74 | endif() 75 | 76 | if (LLVM_ON_UNIX AND NOT APPLE) 77 | set(LLVM_HAVE_LINK_VERSION_SCRIPT 1) 78 | else() 79 | set(LLVM_HAVE_LINK_VERSION_SCRIPT 0) 80 | endif() 81 | -------------------------------------------------------------------------------- /runtime/pedigree_lib.cpp: -------------------------------------------------------------------------------- 1 | #include "pedigree-internal.h" 2 | 3 | // External pedigree library code. Linking this code with a Cilk program 4 | // enables pedigrees. 5 | 6 | //////////////////////////////////////////////////////////////////////////////// 7 | // Global variables local to the library. 8 | 9 | uint64_t __pedigree_dprng_seed = 0x8c679c168e6bf733ul; 10 | uint64_t __pedigree_dprng_m_X = 0; 11 | CHEETAH_INTERNAL 12 | __pedigree_frame root_frame = {.pedigree = {.rank = 0, .parent = nullptr}, 13 | .rank = 0, 14 | .dprng_dotproduct = 0, 15 | .dprng_depth = 0}; 16 | 17 | //////////////////////////////////////////////////////////////////////////////// 18 | // Initialization and deinitialization 19 | 20 | CHEETAH_INTERNAL 21 | void __cilkrts_deinit_dprng(void) { 22 | if (__pedigree_dprng_m_array) { 23 | free(__pedigree_dprng_m_array); 24 | __pedigree_dprng_m_array = nullptr; 25 | } 26 | } 27 | 28 | void __cilkrts_init_dprng(void) noexcept { 29 | // TODO: Disallow __cilkrts_init_dprng() from being called in parallel. 30 | if (!__pedigree_dprng_m_array) { 31 | __pedigree_dprng_m_array = 32 | (uint64_t *)malloc(sizeof(uint64_t *) * 4096); 33 | atexit(__cilkrts_deinit_dprng); 34 | } 35 | 36 | for (int i = 0; i < 4096; i++) { 37 | __pedigree_dprng_m_array[i] = 38 | __cilkrts_dprng_mix_mod_p(__pedigree_dprng_seed + i); 39 | } 40 | __pedigree_dprng_m_X = 41 | __cilkrts_dprng_mix_mod_p(__pedigree_dprng_seed + 4096); 42 | } 43 | 44 | CHEETAH_INTERNAL 45 | void __pedigree_init(void) { 46 | root_frame.dprng_dotproduct = __pedigree_dprng_m_X; 47 | 48 | __cilkrts_register_extension(&root_frame); 49 | } 50 | 51 | CHEETAH_INTERNAL 52 | __attribute__((constructor)) void __pedigree_startup(void) { 53 | __cilkrts_init_dprng(); 54 | 55 | if (!__cilkrts_is_initialized()) 56 | __cilkrts_atinit(__pedigree_init); 57 | else 58 | __pedigree_init(); 59 | } 60 | 61 | //////////////////////////////////////////////////////////////////////////////// 62 | // API methods, callable from user code. 63 | // 64 | // These methods are included here so that, if a Cilk program attempts to use 65 | // one of these routines without incorporating this library, the user will get 66 | // sensible-looking linker errors. 67 | 68 | // Helper method to advance the pedigree and dprng states. 69 | void __cilkrts_bump_worker_rank(void) __CILKRTS_NOTHROW { bump_worker_rank(); } 70 | 71 | // Set the seed for the dprand DPRNG. 72 | void __cilkrts_dprand_set_seed(uint64_t seed) noexcept { 73 | __pedigree_dprng_seed = seed; 74 | __cilkrts_init_dprng(); 75 | } 76 | 77 | // Get the current value of the dprand DPRNG. 78 | uint64_t __cilkrts_get_dprand(void) noexcept { 79 | __pedigree_frame *frame = bump_worker_rank(); 80 | return __cilkrts_dprng_mix_mod_p(frame->dprng_dotproduct); 81 | } 82 | 83 | // Get the current pedigree, in the form of a pointer to its leaf node. 84 | __cilkrts_pedigree __cilkrts_get_pedigree(void) noexcept { 85 | __cilkrts_pedigree ret_ped; 86 | __pedigree_frame *frame = (__pedigree_frame *)(__cilkrts_get_extension()); 87 | ret_ped.parent = &(frame->pedigree); 88 | ret_ped.rank = frame->rank; 89 | return ret_ped; 90 | } 91 | -------------------------------------------------------------------------------- /cmake/Modules/CheetahMockLLVMCMakeConfig.cmake: -------------------------------------------------------------------------------- 1 | # This macro mocks enough of the changes `LLVMConfig.cmake` makes so that 2 | # cilktools can successfully configure itself when a LLVM toolchain is 3 | # available but the corresponding CMake build files are not. 4 | # 5 | # The motivation for this is to be able to generate the cilktools 6 | # lit tests suites and run them against an arbitrary LLVM toolchain 7 | # which doesn't ship the LLVM CMake build files. 8 | macro(cheetah_mock_llvm_cmake_config) 9 | message(STATUS "Attempting to mock the changes made by LLVMConfig.cmake") 10 | cheetah_mock_llvm_cmake_config_set_cmake_path() 11 | cheetah_mock_llvm_cmake_config_set_target_triple() 12 | cheetah_mock_llvm_cmake_config_include_cmake_files() 13 | endmacro() 14 | 15 | macro(cheetah_mock_llvm_cmake_config_set_cmake_path) 16 | # Point `LLVM_CMAKE_DIR` at the source tree in the monorepo. 17 | set(LLVM_CMAKE_DIR "${LLVM_MAIN_SRC_DIR}/cmake/modules") 18 | if (NOT EXISTS "${LLVM_CMAKE_DIR}") 19 | message(FATAL_ERROR "LLVM_CMAKE_DIR (${LLVM_CMAKE_DIR}) does not exist") 20 | endif() 21 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 22 | message(STATUS "LLVM_CMAKE_DIR: \"${LLVM_CMAKE_DIR}\"") 23 | endmacro() 24 | 25 | function(cheetah_mock_llvm_cmake_config_set_target_triple) 26 | # Various bits of cilktools depend on the `LLVM_TARGET_TRIPLE` variable 27 | # being defined. This function tries to set a sensible value for the 28 | # variable. This is a function rather than a macro to avoid polluting the 29 | # variable namespace. 30 | set(COMPILER_OUTPUT "") 31 | 32 | # If the user provides `CILKTOOLS_DEFAULT_TARGET_ONLY` and `CMAKE_C_COMPILER_TARGET` 33 | # (see `construct_cilktools_default_triple`) then prefer that to examining the 34 | # compiler. 35 | if (CILKTOOLS_DEFAULT_TARGET_ONLY) 36 | if (NOT "${CMAKE_C_COMPILER_TARGET}" STREQUAL "") 37 | message(STATUS 38 | "Using CMAKE_C_COMPILER_TARGET (${CMAKE_C_COMPILER_TARGET}) as LLVM_TARGET_TRIPLE") 39 | endif() 40 | set(COMPILER_OUTPUT "${CMAKE_C_COMPILER_TARGET}") 41 | endif() 42 | 43 | # Try asking the compiler for its default target triple. 44 | set(HAD_ERROR FALSE) 45 | if ("${COMPILER_OUTPUT}" STREQUAL "") 46 | if ("${CMAKE_C_COMPILER_ID}" MATCHES "Clang|GNU") 47 | # Note: Clang also supports `-print-target-triple` but gcc doesn't 48 | # support this flag. 49 | execute_process( 50 | COMMAND "${CMAKE_C_COMPILER}" -dumpmachine 51 | RESULT_VARIABLE HAD_ERROR 52 | OUTPUT_VARIABLE COMPILER_OUTPUT 53 | OUTPUT_STRIP_TRAILING_WHITESPACE) 54 | else() 55 | message(FATAL_ERROR 56 | "Fetching target triple from compiler \"${CMAKE_C_COMPILER_ID}\" " 57 | "is not implemented.") 58 | endif() 59 | endif() 60 | 61 | if (HAD_ERROR) 62 | message(FATAL_ERROR "Fetching target triple from compiler failed") 63 | endif() 64 | set(LLVM_TARGET_TRIPLE "${COMPILER_OUTPUT}") 65 | message(STATUS "TARGET_TRIPLE: \"${LLVM_TARGET_TRIPLE}\"") 66 | if ("${LLVM_TARGET_TRIPLE}" STREQUAL "") 67 | message(FATAL_ERROR "TARGET_TRIPLE cannot be empty") 68 | endif() 69 | set(LLVM_TARGET_TRIPLE "${LLVM_TARGET_TRIPLE}" PARENT_SCOPE) 70 | endfunction() 71 | 72 | macro(cheetah_mock_llvm_cmake_config_include_cmake_files) 73 | # Some cilktools CMake code needs to call code in this file. 74 | include("${LLVM_CMAKE_DIR}/AddLLVM.cmake") 75 | endmacro() 76 | -------------------------------------------------------------------------------- /runtime/sched_stats.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCHED_STATS_HEADER__ 2 | #define __SCHED_STATS_HEADER__ 3 | 4 | #include "rts-config.h" 5 | #include 6 | 7 | typedef struct __cilkrts_worker __cilkrts_worker; 8 | 9 | #define SCHED_STATS CILK_STATS 10 | 11 | enum timing_type { 12 | INTERVAL_WORK = 0, // work time 13 | INTERVAL_SCHED, // scheduling time 14 | INTERVAL_IDLE, // idle time 15 | INTERVAL_SLEEP, // spleeing time in work-stealing loop 16 | INTERVAL_SLEEP_UNCILK, // spleeing time outside of work-stealing loop 17 | INTERVAL_CILKIFY_ENTER, // time entering cilkified regions 18 | INTERVAL_CILKIFY_EXIT, // time exiting cilkified regions 19 | NUMBER_OF_STATS // must be the very last entry 20 | }; 21 | 22 | struct sched_stats { 23 | uint64_t time[NUMBER_OF_STATS]; // Total time measured for all stats 24 | uint64_t count[NUMBER_OF_STATS]; 25 | uint64_t begin[NUMBER_OF_STATS]; // Begin time of current measurement 26 | uint64_t end[NUMBER_OF_STATS]; // End time of current measurement 27 | 28 | uint64_t steals; 29 | uint64_t repos; 30 | uint64_t reeng_rqsts; 31 | uint64_t onesen_rqsts; 32 | }; 33 | 34 | struct global_sched_stats { 35 | // Stats for the boss thread 36 | uint64_t boss_waiting; 37 | uint64_t boss_wait_count; 38 | uint64_t boss_begin; 39 | uint64_t exit_time; 40 | uint64_t boss_end; 41 | uint64_t steals; 42 | uint64_t repos; 43 | uint64_t reeng_rqsts; 44 | uint64_t onesen_rqsts; 45 | double time[NUMBER_OF_STATS]; // Total time measured for all stats 46 | uint64_t count[NUMBER_OF_STATS]; 47 | }; 48 | 49 | #if SCHED_STATS 50 | CHEETAH_INTERNAL 51 | void cilk_global_sched_stats_init(struct global_sched_stats *s); 52 | CHEETAH_INTERNAL 53 | void cilk_sched_stats_init(struct sched_stats *s); 54 | CHEETAH_INTERNAL 55 | void cilk_start_timing(__cilkrts_worker *w, enum timing_type t); 56 | CHEETAH_INTERNAL 57 | void cilk_stop_timing(__cilkrts_worker *w, enum timing_type t); 58 | CHEETAH_INTERNAL 59 | void cilk_switch_timing(__cilkrts_worker *w, enum timing_type t1, 60 | enum timing_type t2); 61 | CHEETAH_INTERNAL 62 | void cilk_drop_timing(__cilkrts_worker *w, enum timing_type t); 63 | CHEETAH_INTERNAL 64 | void cilk_boss_start_timing(struct global_state *g); 65 | CHEETAH_INTERNAL 66 | void cilk_boss_stop_timing(struct global_state *g); 67 | CHEETAH_INTERNAL 68 | void cilk_exit_worker_timing(struct global_state *g); 69 | CHEETAH_INTERNAL 70 | void cilk_sched_stats_print(struct global_state *g); 71 | // void cilk_reset_timing(__cilkrts_worker *w, enum timing_type t); 72 | // FIXME: should have a header file that's user-code interfacing 73 | // void __cilkrts_reset_timing(); // user-code facing 74 | 75 | #define WHEN_SCHED_STATS(ex) ex 76 | #define CILK_START_TIMING(w, t) cilk_start_timing(w, t) 77 | #define CILK_STOP_TIMING(w, t) cilk_stop_timing(w, t) 78 | #define CILK_SWITCH_TIMING(w, t1, t2) cilk_switch_timing(w, t1, t2) 79 | #define CILK_DROP_TIMING(w, t) cilk_drop_timing(w, t) 80 | #define CILK_BOSS_START_TIMING(g) cilk_boss_start_timing(g) 81 | #define CILK_BOSS_STOP_TIMING(g) cilk_boss_stop_timing(g) 82 | #define CILK_EXIT_WORKER_TIMING(g) cilk_exit_worker_timing(g) 83 | 84 | #else 85 | #define cilk_global_sched_stats_init(s) 86 | #define cilk_sched_stats_init(s) 87 | #define cilk_sched_stats_print(g) 88 | // #define cilk_reset_timing() 89 | 90 | #define WHEN_SCHED_STATS(ex) 91 | #define CILK_START_TIMING(w, t) 92 | #define CILK_STOP_TIMING(w, t) 93 | #define CILK_SWITCH_TIMING(w, t1, t2) 94 | #define CILK_DROP_TIMING(w, t) 95 | #define CILK_BOSS_START_TIMING(g) 96 | #define CILK_BOSS_STOP_TIMING(g) 97 | #define CILK_EXIT_WORKER_TIMING(g) 98 | #endif // SCHED_STATS 99 | 100 | #endif // __SCHED_STATS_HEADER__ 101 | -------------------------------------------------------------------------------- /handcomp_test/ktiming.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012 MIT License by 6.172 Staff 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | **/ 22 | 23 | /** 24 | * Linux kernel-assisted timing library -- provides high-precision time 25 | * measurements for the execution time of your algorithms. 26 | * 27 | * You shouldn't need to modify this file. More importantly, you should not 28 | * depend on any modifications you make here, as we will replace it with a 29 | * fresh copy when we test your code. 30 | **/ 31 | 32 | #include "./ktiming.h" 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #define NSEC_TO_SEC(x) ((double)(x)*1.0e-9) 40 | 41 | clockmark_t ktiming_getmark(void) { 42 | struct timespec temp = {0, 0}; 43 | uint64_t nanos; 44 | 45 | int stat = clock_gettime(CLOCK_MONOTONIC, &temp); 46 | if (stat != 0) { 47 | perror("ktiming_getmark()"); 48 | exit(-1); 49 | } 50 | nanos = temp.tv_nsec; 51 | nanos += ((uint64_t)temp.tv_sec) * 1000 * 1000 * 1000; 52 | return nanos; 53 | } 54 | 55 | uint64_t ktiming_diff_nsec(const clockmark_t *const start, 56 | const clockmark_t *const end) { 57 | return *end - *start; 58 | } 59 | 60 | double ktiming_diff_sec(const clockmark_t *const start, 61 | const clockmark_t *const end) { 62 | return NSEC_TO_SEC(ktiming_diff_nsec(start, end)); 63 | } 64 | 65 | static void print_runtime_helper(uint64_t *nsec_elapsed, int size, 66 | int summary) { 67 | 68 | int i; 69 | uint64_t total = 0; 70 | double ave, std_dev = 0, dev_sq_sum = 0; 71 | 72 | for (i = 0; i < size; i++) { 73 | total += nsec_elapsed[i]; 74 | if (!summary) { 75 | printf("Running time %d: %gs\n", (i + 1), 76 | NSEC_TO_SEC(nsec_elapsed[i])); 77 | } 78 | } 79 | ave = total / size; 80 | 81 | if (size > 1) { 82 | for (i = 0; i < size; i++) { 83 | double diff = (double)nsec_elapsed[i] - ave; 84 | dev_sq_sum += diff * diff; 85 | } 86 | std_dev = sqrt(dev_sq_sum / (size - 1)); 87 | } 88 | 89 | printf("Running time average: %g s\n", NSEC_TO_SEC(ave)); 90 | if (std_dev != 0) { 91 | printf("Std. dev: %g s (%2.3f%%)\n", NSEC_TO_SEC(std_dev), 92 | 100.0 * std_dev / ave); 93 | } 94 | } 95 | 96 | void print_runtime(uint64_t *tm_elapsed, int size) { 97 | print_runtime_helper(tm_elapsed, size, 0); 98 | } 99 | 100 | void print_runtime_summary(uint64_t *tm_elapsed, int size) { 101 | print_runtime_helper(tm_elapsed, size, 1); 102 | } 103 | -------------------------------------------------------------------------------- /handcomp_test/nqueens.cpp: -------------------------------------------------------------------------------- 1 | #ifndef TIMING_COUNT 2 | #define TIMING_COUNT 0 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../runtime/cilk2c.h" 10 | #include "../runtime/cilk2c_inlined.cpp" 11 | #include "ktiming.h" 12 | 13 | extern size_t ZERO; 14 | void __attribute__((weak)) dummy(void *p) { return; } 15 | 16 | // int * count; 17 | 18 | /* 19 | * nqueen 4 = 2 20 | * nqueen 5 = 10 21 | * nqueen 6 = 4 22 | * nqueen 7 = 40 23 | * nqueen 8 = 92 24 | * nqueen 9 = 352 25 | * nqueen 10 = 724 26 | * nqueen 11 = 2680 27 | * nqueen 12 = 14200 28 | * nqueen 13 = 73712 29 | * nqueen 14 = 365596 30 | * nqueen 15 = 2279184 31 | */ 32 | 33 | /* 34 | * contains array of queen positions. Returns 1 35 | * if none of the queens conflict, and returns 0 otherwise. 36 | */ 37 | static int ok (int n, char *a) { 38 | 39 | int i, j; 40 | char p, q; 41 | 42 | for (i = 0; i < n; i++) { 43 | p = a[i]; 44 | for (j = i + 1; j < n; j++) { 45 | q = a[j]; 46 | if (q == p || q == p - (j - i) || q == p + (j - i)) 47 | return 0; 48 | } 49 | } 50 | 51 | return 1; 52 | } 53 | 54 | static void __attribute__ ((noinline)) 55 | nqueens_spawn_helper(int *count, int n, int j, char *a, 56 | __cilkrts_stack_frame *parent); 57 | 58 | static int nqueens(int n, int j, char *a) { 59 | 60 | char *b; 61 | int i; 62 | int *count; 63 | int solNum = 0; 64 | 65 | if (n == j) { 66 | return 1; 67 | } 68 | 69 | count = (int *) alloca(n * sizeof(int)); 70 | (void) memset(count, 0, n * sizeof (int)); 71 | 72 | dummy(alloca(ZERO)); 73 | __cilkrts_stack_frame sf; 74 | __cilkrts_enter_frame(&sf); 75 | 76 | for (i = 0; i < n; i++) { 77 | 78 | /*** 79 | * Strictly speaking, this (alloca after spawn) is frowned 80 | * up on, but in this case, this is ok, because b returned by 81 | * alloca is only used in this iteration; later spawns don't 82 | * need to be able to access copies of b from previous iterations 83 | ***/ 84 | b = (char *) alloca((j + 1) * sizeof (char)); 85 | memcpy(b, a, j * sizeof (char)); 86 | b[j] = i; 87 | 88 | if(ok (j + 1, b)) { 89 | 90 | /* count[i] = cilk_spawn nqueens(n, j + 1, b); */ 91 | if (!__cilk_prepare_spawn(&sf)) { 92 | nqueens_spawn_helper(&(count[i]), n, j+1, b, &sf); 93 | } 94 | } 95 | } 96 | /* cilk_sync */ 97 | __cilk_sync_nothrow(&sf); 98 | 99 | for(i = 0; i < n; i++) { 100 | solNum += count[i]; 101 | } 102 | 103 | __cilk_parent_epilogue(&sf); 104 | 105 | return solNum; 106 | } 107 | 108 | static void __attribute__ ((noinline)) 109 | nqueens_spawn_helper(int *count, int n, int j, char *a, 110 | __cilkrts_stack_frame *parent) { 111 | 112 | __cilkrts_stack_frame sf; 113 | __cilkrts_enter_frame_helper(&sf, parent, false); 114 | __cilkrts_detach(&sf, parent); 115 | *count = nqueens(n, j, a); 116 | __cilk_helper_epilogue(&sf, parent, false); 117 | } 118 | 119 | int main(int argc, char *argv[]) { 120 | 121 | int n = 13; 122 | char *a; 123 | int res; 124 | 125 | if(argc < 2) { 126 | fprintf (stderr, "Usage: %s \n", argv[0]); 127 | fprintf (stderr, "Use default board size, n = 13.\n"); 128 | exit(0); 129 | } else { 130 | n = atoi (argv[1]); 131 | printf ("Running %s with n = %d.\n", argv[0], n); 132 | } 133 | 134 | a = (char *) alloca (n * sizeof (char)); 135 | res = 0; 136 | 137 | #if TIMING_COUNT 138 | clockmark_t begin, end; 139 | uint64_t elapsed[TIMING_COUNT]; 140 | 141 | for(int i=0; i < TIMING_COUNT; i++) { 142 | begin = ktiming_getmark(); 143 | res = nqueens(n, 0, a); 144 | end = ktiming_getmark(); 145 | elapsed[i] = ktiming_diff_nsec(&begin, &end); 146 | } 147 | print_runtime(elapsed, TIMING_COUNT); 148 | #else 149 | res = nqueens(n, 0, a); 150 | #endif 151 | 152 | if (res == 0) { 153 | printf("No solution found.\n"); 154 | } else { 155 | printf("Total number of solutions : %d\n", res); 156 | } 157 | 158 | return 0; 159 | } 160 | -------------------------------------------------------------------------------- /unittests/test-old-hash-hypertable.c: -------------------------------------------------------------------------------- 1 | #include "test-hypertable-common.h" 2 | 3 | // Test cases derived from traces that led to errors. 4 | 5 | void test0(void) { 6 | table_command test[] = { 7 | {TABLE_INSERT, 0x7f2a10bfe050}, 8 | {TABLE_INSERT, 0x7f2a10bff968}, 9 | {TABLE_INSERT, 0x7f2a10bfe8a8}, 10 | {TABLE_INSERT, 0x7f2a10bfece0}, 11 | {TABLE_INSERT, 0x7f2a10bff538}, 12 | {TABLE_INSERT, 0x7f2a10bff108}, 13 | {TABLE_INSERT, 0x7f2a10bff540}, 14 | {TABLE_INSERT, 0x7f2a10bff970}, 15 | {TABLE_INSERT, 0x7f2a10bfe8b0}, 16 | {TABLE_INSERT, 0x7f2a10bfe478}, 17 | {TABLE_INSERT, 0x7f2a10bfe480}, 18 | {TABLE_INSERT, 0x7f2a10bff110}, 19 | {TABLE_INSERT, 0x7f2a10bffda0}, 20 | {TABLE_INSERT, 0x562edc97d0c0}, 21 | {TABLE_INSERT, 0x7f2a10bfe048}, 22 | 23 | {TABLE_INSERT, 0x7f2a10bfe478}, 24 | {TABLE_INSERT, 0x7f2a10bff110}, 25 | 26 | {TABLE_DELETE, 0x7f2a10bfe048}, 27 | {TABLE_DELETE, 0x7f2a10bfe050}, 28 | {TABLE_DELETE, 0x7f2a10bfe478}, 29 | {TABLE_DELETE, 0x7f2a10bfe480}, 30 | {TABLE_DELETE, 0x7f2a10bfe8a8}, 31 | {TABLE_DELETE, 0x7f2a10bfe8b0}, 32 | 33 | {TABLE_INSERT, 0x7f2a10bfe8b0}, 34 | {TABLE_INSERT, 0x7f2a10bfe8a8}, 35 | {TABLE_INSERT, 0x7f2a10bfe480}, 36 | {TABLE_INSERT, 0x7f2a10bfe478}, 37 | {TABLE_INSERT, 0x7f2a10bfe050}, 38 | {TABLE_INSERT, 0x7f2a10bfe048}, 39 | 40 | {TABLE_DELETE, 0x7f2a10bfe048}, 41 | {TABLE_DELETE, 0x7f2a10bfe050}, 42 | {TABLE_DELETE, 0x7f2a10bfe478}, 43 | {TABLE_DELETE, 0x7f2a10bfe480}, 44 | 45 | {TABLE_INSERT, 0x7f2a10bfe480}, 46 | {TABLE_INSERT, 0x7f2a10bfe478}, 47 | 48 | {TABLE_INSERT, 0x7f2a10bfe480}, 49 | }; 50 | test_insert_remove(test, sizeof(test)/sizeof(table_command)); 51 | } 52 | 53 | void test1(void) { 54 | table_command test[] = { 55 | {TABLE_INSERT, 0xfffff4e82ed0}, 56 | {TABLE_INSERT, 0xfffff4e82d40}, 57 | {TABLE_INSERT, 0xfffff4e82bb0}, 58 | {TABLE_INSERT, 0xfffff4e82a90}, 59 | {TABLE_INSERT, 0xfffff4e82900}, 60 | {TABLE_INSERT, 0xfffff4e82770}, 61 | {TABLE_INSERT, 0xfffff4e82650}, 62 | {TABLE_INSERT, 0xfffff4e82530}, 63 | 64 | {TABLE_DELETE, 0xfffff4e82530}, 65 | {TABLE_DELETE, 0xfffff4e82650}, 66 | {TABLE_DELETE, 0xfffff4e82770}, 67 | 68 | {TABLE_DELETE, 0xfffff4e82bb0}, 69 | 70 | // Check that insert succeeds when an element has a larger hash than 71 | // any elements currently in the table. 72 | {TABLE_INSERT, 0xfffff4e827e0}, 73 | }; 74 | test_insert_remove(test, sizeof(test)/sizeof(table_command)); 75 | } 76 | 77 | void test2(void) { 78 | // Test case derived from trace that led to errors. 79 | uintptr_t keys[] = { 80 | 0x7f84b33fef40, 81 | 0x7f84b33fed90, 82 | KEY_DELETED, 83 | KEY_DELETED, 84 | 0x7f84b33fee30, 85 | 0x7f84b33fecf0, 86 | KEY_DELETED, 87 | KEY_DELETED, 88 | }; 89 | table_command test[] = { 90 | {TABLE_LOOKUP, 0x7f84b33fee30}, 91 | 92 | {TABLE_INSERT, 0x7f84b33fec50}, 93 | {TABLE_LOOKUP, 0x7f84b33fec50}, 94 | 95 | {TABLE_INSERT, 0x3}, 96 | {TABLE_LOOKUP, 0x7f84b33fee30}, 97 | 98 | {TABLE_INSERT, 0x4}, 99 | {TABLE_INSERT, 0x1}, 100 | 101 | {TABLE_LOOKUP, 0x7f84b33fee30}, 102 | {TABLE_LOOKUP, 0x7f84b33fecf0}, 103 | {TABLE_LOOKUP, 0x7f84b33fec50}, 104 | {TABLE_LOOKUP, 0x7f84b33fef40}, 105 | {TABLE_LOOKUP, 0x7f84b33fed90}, 106 | {TABLE_LOOKUP, 0x3}, 107 | {TABLE_LOOKUP, 0x4}, 108 | {TABLE_LOOKUP, 0x1}, 109 | }; 110 | test_set_insert_remove(keys, sizeof(keys) / sizeof(uintptr_t), test, 111 | sizeof(test) / sizeof(table_command)); 112 | } 113 | 114 | int main(int argc, char *argv[]) { 115 | int to_run = -1; 116 | if (argc > 1) 117 | to_run = atoi(argv[1]); 118 | 119 | if (to_run < 0 || to_run == 0) { 120 | test0(); 121 | printf("test0 PASSED\n"); 122 | } 123 | if (to_run < 0 || to_run == 1) { 124 | test1(); 125 | printf("test1 PASSED\n"); 126 | } 127 | if (to_run < 0 || to_run == 2) { 128 | test2(); 129 | printf("test2 PASSED\n"); 130 | } 131 | return 0; 132 | } 133 | -------------------------------------------------------------------------------- /cmake/Modules/CheetahTests.cmake: -------------------------------------------------------------------------------- 1 | include(CMakeCheckCompilerFlagCommonPatterns) 2 | 3 | # Test compiler can compile simple C/C++/Objective-C program without invoking 4 | # the linker. 5 | # 6 | # try_compile_only( 7 | # OUTPUT_VAR 8 | # [SOURCE source_text] 9 | # [FLAGS flag_0 [ flag_1 ]] 10 | # ) 11 | # 12 | # OUTPUT_VAR - The variable name to store the result. The result is a boolean 13 | # `True` or `False`. 14 | # 15 | # SOURCE - Optional. If specified use source the source text string 16 | # specified. If not specified source code will be used that is C, 17 | # C++, and Objective-C compatible. 18 | # 19 | # FLAGS - Optional. If specified pass the one or more specified flags to 20 | # the compiler. 21 | # 22 | # EXAMPLES: 23 | # 24 | # try_compile_only(HAS_F_NO_RTTI FLAGS "-fno-rtti") 25 | # 26 | # try_compile_only(HAS_CXX_AUTO_TYPE_DECL 27 | # SOURCE "int foo(int x) { auto y = x + 1; return y;}" 28 | # FLAGS "-x" "c++" "-std=c++11" "-Werror=c++11-extensions" 29 | # ) 30 | # 31 | function(try_compile_only output) 32 | # NOTE: `SOURCE` needs to be a multi-argument because source code 33 | # often contains semicolons which happens to be CMake's list separator 34 | # which confuses `cmake_parse_arguments()`. 35 | cmake_parse_arguments(ARG "" "" "SOURCE;FLAGS" ${ARGN}) 36 | if (ARG_UNPARSED_ARGUMENTS) 37 | message(FATAL_ERROR "Unexpected arguments \"${ARG_UNPARSED_ARGUMENTS}\"") 38 | endif() 39 | if(NOT ARG_SOURCE) 40 | set(ARG_SOURCE "int foo(int x, int y) { return x + y; }\n") 41 | endif() 42 | set(SIMPLE_C ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/src.c) 43 | file(WRITE ${SIMPLE_C} "${ARG_SOURCE}\n") 44 | string(REGEX MATCHALL "<[A-Za-z0-9_]*>" substitutions 45 | ${CMAKE_C_COMPILE_OBJECT}) 46 | 47 | set(TRY_COMPILE_FLAGS "${ARG_FLAGS}") 48 | if(CMAKE_C_COMPILER_ID MATCHES Clang AND CMAKE_C_COMPILER_TARGET) 49 | list(APPEND TRY_COMPILE_FLAGS "--target=${CMAKE_C_COMPILER_TARGET}") 50 | endif() 51 | 52 | string(REPLACE ";" " " extra_flags "${TRY_COMPILE_FLAGS}") 53 | 54 | set(test_compile_command "${CMAKE_C_COMPILE_OBJECT}") 55 | foreach(substitution ${substitutions}) 56 | if(substitution STREQUAL "") 57 | string(REPLACE "" 58 | "${CMAKE_C_COMPILER}" test_compile_command ${test_compile_command}) 59 | elseif(substitution STREQUAL "") 60 | string(REPLACE "" 61 | "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/test.o" 62 | test_compile_command ${test_compile_command}) 63 | elseif(substitution STREQUAL "") 64 | string(REPLACE "" "${SIMPLE_C}" test_compile_command 65 | ${test_compile_command}) 66 | elseif(substitution STREQUAL "") 67 | string(REPLACE "" "${CMAKE_C_FLAGS} ${extra_flags}" 68 | test_compile_command ${test_compile_command}) 69 | else() 70 | string(REPLACE "${substitution}" "" test_compile_command 71 | ${test_compile_command}) 72 | endif() 73 | endforeach() 74 | 75 | # Strip quotes from the compile command, as the compiler is not expecting 76 | # quoted arguments (see discussion on D62063 for when this can come up). If 77 | # the quotes were there for arguments with spaces in them, the quotes were 78 | # not going to help since the string gets split on spaces below. 79 | string(REPLACE "\"" "" test_compile_command "${test_compile_command}") 80 | 81 | string(REPLACE " " ";" test_compile_command "${test_compile_command}") 82 | 83 | execute_process( 84 | COMMAND ${test_compile_command} 85 | RESULT_VARIABLE result 86 | OUTPUT_VARIABLE TEST_OUTPUT 87 | ERROR_VARIABLE TEST_ERROR 88 | ) 89 | 90 | CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckCCompilerFlag_COMMON_PATTERNS) 91 | set(ERRORS_FOUND OFF) 92 | foreach(var ${_CheckCCompilerFlag_COMMON_PATTERNS}) 93 | if("${var}" STREQUAL "FAIL_REGEX") 94 | continue() 95 | endif() 96 | if("${TEST_ERROR}" MATCHES "${var}" OR "${TEST_OUTPUT}" MATCHES "${var}") 97 | set(ERRORS_FOUND ON) 98 | endif() 99 | endforeach() 100 | 101 | if(result EQUAL 0 AND NOT ERRORS_FOUND) 102 | set(${output} True PARENT_SCOPE) 103 | else() 104 | file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log 105 | "Testing compiler for supporting " ${ARGN} ":\n" 106 | "Command: ${test_compile_command}\n" 107 | "${TEST_OUTPUT}\n${TEST_ERROR}\n${result}\n") 108 | set(${output} False PARENT_SCOPE) 109 | endif() 110 | endfunction() 111 | -------------------------------------------------------------------------------- /runtime/closure.h: -------------------------------------------------------------------------------- 1 | #ifndef _CLOSURE_TYPE_H 2 | #define _CLOSURE_TYPE_H 3 | 4 | #include "cilk-internal.h" 5 | #include "local-hypertable.h" 6 | #include 7 | 8 | // Forward declaration 9 | typedef struct Closure Closure; 10 | 11 | enum ClosureStatus : unsigned char { 12 | /* Closure.status == 0 is invalid */ 13 | CLOSURE_RUNNING = 42, 14 | CLOSURE_SUSPENDED, 15 | CLOSURE_RETURNING, 16 | CLOSURE_READY, 17 | CLOSURE_PRE_INVALID, /* before first real use */ 18 | CLOSURE_POST_INVALID /* after destruction */ 19 | }; 20 | 21 | /* 22 | * the list of children is not distributed among 23 | * the children themselves, in order to avoid extra protocols 24 | * and locking. 25 | */ 26 | struct __attribute__((visibility("hidden"))) Closure { 27 | __cilkrts_stack_frame *frame; /* rest of the closure */ 28 | 29 | void clear_frame() { frame = nullptr; } 30 | void set_frame(__cilkrts_stack_frame *sf) { 31 | CILK_ASSERT(!frame); 32 | frame = sf; 33 | } 34 | struct cilk_fiber *fiber = nullptr; 35 | struct cilk_fiber *fiber_child = nullptr; 36 | 37 | struct cilk_fiber *ext_fiber = nullptr; 38 | struct cilk_fiber *ext_fiber_child = nullptr; 39 | 40 | worker_id owner_ready_deque = NO_WORKER; /* debug only */ 41 | 42 | enum ClosureStatus status = CLOSURE_PRE_INVALID; 43 | bool has_cilk_callee = false; 44 | bool exception_pending = false; 45 | unsigned int join_counter = 0; /* number of outstanding spawned children */ 46 | char *orig_rsp = nullptr; /* rsp one should use when sync successfully */ 47 | 48 | Closure *callee = nullptr; 49 | 50 | Closure *call_parent = nullptr; /* the "parent" closure that called */ 51 | Closure *spawn_parent = nullptr; /* the "parent" closure that spawned */ 52 | 53 | Closure *left_sib = nullptr; // left *spawned* sibling in the closure tree 54 | Closure *right_sib = nullptr; // right *spawned* sibling in the closur tree 55 | // right most *spawned* child in the closure tree 56 | Closure *right_most_child = nullptr; 57 | 58 | /* 59 | * stuff related to ready deque. 60 | * 61 | * ANGE: for top of the ReadyDeque, prev_ready = NULL 62 | * for bottom of the ReadyDeque, next_ready = NULL 63 | * next_ready pointing downward, prev_ready pointing upward 64 | * 65 | * top 66 | * next | ^ 67 | * | | prev 68 | * v | 69 | * ... 70 | * next | ^ 71 | * | | prev 72 | * v | 73 | * bottom 74 | */ 75 | Closure *next_ready = nullptr; 76 | Closure *prev_ready = nullptr; 77 | 78 | hyper_table *right_ht = nullptr; 79 | hyper_table *child_ht = nullptr; 80 | hyper_table *user_ht = nullptr; 81 | 82 | std::atomic mutex_owner 83 | __attribute__((aligned(CILK_CACHE_LINE))) 84 | = NO_WORKER; 85 | 86 | bool has_children() const { 87 | return (has_cilk_callee || join_counter != 0); 88 | } 89 | 90 | void set_status(enum ClosureStatus to) { 91 | status = to; 92 | } 93 | void change_status(enum ClosureStatus from, enum ClosureStatus to) { 94 | CILK_ASSERT(status == from); 95 | (void)from; // unused if assertions disabled 96 | status = to; 97 | } 98 | 99 | bool trylock(worker_id self); 100 | 101 | void make_ready() { 102 | status = CLOSURE_READY; 103 | } 104 | 105 | const char *status_to_string() const; 106 | 107 | Closure(__cilkrts_stack_frame *sf); 108 | ~Closure(); 109 | 110 | void lock(worker_id self); 111 | void unlock(worker_id self); 112 | 113 | static Closure *create(struct __cilkrts_worker *, __cilkrts_stack_frame *); 114 | static void destroy(Closure *, struct __cilkrts_worker *); 115 | static void destroy(Closure *, struct global_state *); 116 | 117 | // This method is used for sync. 118 | void suspend(struct ReadyDeque *deques, worker_id self); 119 | // This method is used for steal. 120 | void suspend_victim(struct ReadyDeque *deques, worker_id thief, 121 | worker_id victim); 122 | 123 | void add_callee(Closure *new_callee); 124 | void remove_callee(); 125 | void add_child(worker_id self, Closure *child); 126 | void remove_child(worker_id self, Closure *child); 127 | 128 | void assert_ownership(worker_id self); 129 | void assert_alienation(worker_id self); 130 | void checkmagic(); 131 | 132 | private: 133 | static void double_link_children(Closure *left, Closure *right); 134 | void unlink_child(); 135 | 136 | } __attribute__((aligned(CILK_CACHE_LINE))); 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /runtime/cilk2c_inlined.h: -------------------------------------------------------------------------------- 1 | // Runtime functions that are known to the compiler. 2 | // All of these use C linkage. 3 | 4 | #include "cilk/cilk_api.h" 5 | #include 6 | 7 | struct __cilkrts_stack_frame; 8 | struct __cilkrts_worker; 9 | struct __reducer_base; 10 | struct __reducer_callbacks; 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | // Inserted at the entry of a spawning function that is not itself a spawn 17 | // helper. Initializes the stack frame sf allocated for that function. 18 | void __cilkrts_enter_frame(struct __cilkrts_stack_frame *sf) __CILKRTS_NOTHROW; 19 | // Inserted at the entry of a spawn helper, i.e., a function that must have been 20 | // spawned. Initializes the stack frame sf allocated for that function. 21 | void __cilkrts_enter_frame_helper(struct __cilkrts_stack_frame *sf, 22 | struct __cilkrts_stack_frame *parent, 23 | bool spawner) __CILKRTS_NOTHROW; 24 | 25 | // Prepare to perform a spawn. This function may return once or twice, 26 | // returning 0 the first time and 1 the second time. This function is intended 27 | // to be used follows: 28 | // 29 | // if (0 == __cilk_spawn_prepare(sf)) { 30 | // spawn_helper(args); 31 | // } 32 | int __cilk_prepare_spawn(struct __cilkrts_stack_frame *sf) __CILKRTS_NOTHROW; 33 | 34 | // Called in the spawn helper immediately before the spawned computation. 35 | // Enables the parent function to be stollen. 36 | void __cilkrts_detach(struct __cilkrts_stack_frame *sf, 37 | struct __cilkrts_stack_frame *parent) __CILKRTS_NOTHROW; 38 | 39 | // Inserted on return from a spawning function that is not itself a spawn 40 | // helper. Performs Cilk's return protocol for such functions. 41 | // Marked API because it is used inside the library by personality.cpp. 42 | CHEETAH_API 43 | void __cilkrts_leave_frame(struct __cilkrts_stack_frame *sf); 44 | // Inserted on return from a spawn-helper function. Performs Cilk's return 45 | // protocol for such functions. 46 | void __cilkrts_leave_frame_helper(struct __cilkrts_stack_frame *sf, 47 | struct __cilkrts_stack_frame *parent, 48 | bool spawner); 49 | 50 | // Performs all necessary operations on return from a spawning function that is 51 | // not itself a spawn helper. 52 | void __cilk_parent_epilogue(struct __cilkrts_stack_frame *sf); 53 | // Performs all necessary operations on return from a spawn-helper function. 54 | __attribute__((always_inline)) 55 | void __cilk_helper_epilogue(struct __cilkrts_stack_frame *sf, 56 | struct __cilkrts_stack_frame *parent, 57 | bool spawner); 58 | void __cilk_helper_epilogue_exn(struct __cilkrts_stack_frame *sf, 59 | struct __cilkrts_stack_frame *parent, 60 | char *exn, bool spawner); 61 | 62 | void __cilkrts_enter_landingpad(struct __cilkrts_stack_frame *sf, int32_t sel); 63 | // Performs Cilk's return protocol on an exceptional return (i.e., a resume) 64 | // from a spawn-helper function. 65 | void __cilkrts_pause_frame(struct __cilkrts_stack_frame *sf, 66 | struct __cilkrts_stack_frame *parent, 67 | char *exn, bool spawner); 68 | 69 | // Compute the grainsize for a cilk_for loop at runtime, based on the number n 70 | // of loop iterations. 71 | uint8_t __cilkrts_cilk_for_grainsize_8(uint8_t n) __CILKRTS_NOTHROW; 72 | uint16_t __cilkrts_cilk_for_grainsize_16(uint16_t n) __CILKRTS_NOTHROW; 73 | uint32_t __cilkrts_cilk_for_grainsize_32(uint32_t n) __CILKRTS_NOTHROW; 74 | uint64_t __cilkrts_cilk_for_grainsize_64(uint64_t n) __CILKRTS_NOTHROW; 75 | 76 | // Performs runtime operations to handle a cilk_sync. 77 | void __cilk_sync(struct __cilkrts_stack_frame *sf); 78 | 79 | // Implements a cilk_sync when the cilk_sync is guaranteed not to produce an 80 | // exception that needs to be handled locally. 81 | void __cilk_sync_nothrow(struct __cilkrts_stack_frame *sf); 82 | 83 | __reducer_base *__cilkrts_reducer_lookup_0(__reducer_base *key) 84 | __attribute__((nonnull, returns_nonnull)); 85 | void *__cilkrts_reducer_lookup_1(void *key, const struct __reducer_callbacks &) 86 | __attribute__((nonnull, returns_nonnull)); 87 | void *__cilkrts_reducer_lookup_2(void *key, size_t size, 88 | void (*id)(void *), 89 | void (*reduce)(void *, void *)) 90 | __attribute__((nonnull, returns_nonnull)); 91 | 92 | void __cilkrts_reducer_register_0(__reducer_base *key) 93 | __CILKRTS_NOTHROW; 94 | void __cilkrts_reducer_register_1(void *key, __reducer_callbacks *) 95 | __CILKRTS_NOTHROW; 96 | void __cilkrts_reducer_register_2(void *key, void (*reduce)(void *, void *)) 97 | __CILKRTS_NOTHROW; 98 | 99 | void __cilkrts_reducer_unregister(void *key) __CILKRTS_NOTHROW; 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | -------------------------------------------------------------------------------- /runtime/cilk-internal.h: -------------------------------------------------------------------------------- 1 | #ifndef _CILK_INTERNAL_H 2 | #define _CILK_INTERNAL_H 3 | 4 | #include "debug.h" 5 | #include "fiber-header.h" 6 | #include "frame.h" 7 | #include "internal-malloc.h" 8 | #include "rts-config.h" 9 | #include "sched_stats.h" 10 | #include "worker.h" 11 | #include 12 | #include 13 | #include 14 | 15 | #if defined __i386__ || defined __x86_64__ 16 | #ifdef __SSE__ 17 | #define CHEETAH_SAVE_MXCSR 18 | #endif 19 | #endif 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | struct global_state; 26 | typedef struct global_state global_state; 27 | typedef struct local_state local_state; 28 | 29 | struct cilkrts_callbacks { 30 | unsigned last_init; 31 | unsigned last_exit; 32 | bool after_init; 33 | void (*init[MAX_CALLBACKS])(void); 34 | void (*exit[MAX_CALLBACKS])(void); 35 | }; 36 | 37 | extern CHEETAH_INTERNAL struct cilkrts_callbacks cilkrts_callbacks; 38 | 39 | struct __cilkrts_status { 40 | bool need_to_cilkify; 41 | bool use_extension; 42 | }; 43 | 44 | extern struct __cilkrts_status __cilkrts_status; 45 | 46 | #if ENABLE_EXTENSION 47 | #define USE_EXTENSION __cilkrts_status.use_extension 48 | #else 49 | #define USE_EXTENSION false 50 | #endif 51 | 52 | struct __cilkrts_tls { 53 | __cilkrts_worker *worker; 54 | struct cilk_fiber *fh; 55 | }; 56 | 57 | extern __thread struct __cilkrts_tls __cilkrts_tls; 58 | 59 | static inline __attribute__((always_inline,nothrow)) __cilkrts_worker * 60 | __cilkrts_get_tls_worker(void) { 61 | return __cilkrts_tls.worker; 62 | } 63 | 64 | static inline __attribute__((always_inline,nothrow)) __cilkrts_worker * 65 | get_worker_from_stack(const __cilkrts_stack_frame *sf) { 66 | // Although we can get the current worker by calling 67 | // __cilkrts_get_tls_worker(), that method accesses the worker via TLS, 68 | // which can be slow on some systems. This method gets the current worker 69 | // from the given __cilkrts_stack_frame, which is more efficient than a TLS 70 | // access on those systems. 71 | return sf->fh->worker; 72 | } 73 | 74 | CHEETAH_INTERNAL 75 | __reducer_base * 76 | internal_reducer_lookup(__cilkrts_worker *w, __reducer_base *key); 77 | CHEETAH_INTERNAL 78 | void internal_reducer_remove(__cilkrts_worker *w, void *key); 79 | 80 | void __cilkrts_register_extension(void *extension); 81 | void *__cilkrts_get_extension(void); 82 | void __cilkrts_extend_spawn(__cilkrts_worker *w, void **parent_extension, 83 | void **child_extension); 84 | void __cilkrts_extend_return_from_spawn(__cilkrts_worker *w, void **extension); 85 | void __cilkrts_extend_sync(void **extension); 86 | 87 | static inline __attribute__((always_inline)) void * 88 | __cilkrts_push_ext_stack(__cilkrts_worker *w, size_t size) { 89 | uint8_t *ext_stack_ptr = ((uint8_t *)w->ext_stack) - size; 90 | w->ext_stack = (void *)ext_stack_ptr; 91 | return ext_stack_ptr; 92 | } 93 | 94 | static inline __attribute__((always_inline)) void * 95 | __cilkrts_pop_ext_stack(__cilkrts_worker *w, size_t size) { 96 | uint8_t *ext_stack_ptr = ((uint8_t *)w->ext_stack) + size; 97 | w->ext_stack = (void *)ext_stack_ptr; 98 | return ext_stack_ptr; 99 | } 100 | 101 | /* 102 | * All the data needed to properly handle a thrown exception. 103 | */ 104 | struct closure_exception final : public __reducer_base { 105 | char *exn = nullptr; 106 | /* Canonical frame address (CFA) of the call-stack frame from which an 107 | exception was rethrown. Used to ensure that the rethrown exception 108 | appears to be rethrown from the correct frame and to avoid repeated calls 109 | to __cilkrts_leave_frame during stack unwinding. */ 110 | char *reraise_cfa = nullptr; 111 | /* Stack pointer for the parent fiber. Used to restore the stack pointer 112 | properly after entering a landingpad. */ 113 | char *parent_rsp = nullptr; 114 | /* Fiber holding the stack frame of a call to _Unwind_RaiseException that is 115 | currently running. */ 116 | struct cilk_fiber *throwing_fiber = nullptr; 117 | 118 | virtual __reducer_base *identity(void *) override; 119 | virtual void reduce(__reducer_base *, __reducer_base *) override; 120 | virtual std::size_t size() const override { return sizeof *this; } 121 | }; 122 | 123 | // Reducer structure for handling exceptions thrown in parallel. 124 | // Retrieve the exception stored in the local view of the exception reducer. 125 | CHEETAH_INTERNAL struct closure_exception * 126 | get_exception_reducer(__cilkrts_worker *w) noexcept; 127 | // Retrieve the exception stored in the local view of the exception reducer, or 128 | // NULL if there is no local view.. 129 | CHEETAH_INTERNAL struct closure_exception * 130 | get_exception_reducer_or_null(__cilkrts_worker *w) noexcept; 131 | // Free resources used for a local view of the exception reducer. This method 132 | // does not deallocate the exception 133 | CHEETAH_INTERNAL void clear_exception_reducer(__cilkrts_worker *w, 134 | struct closure_exception *exn_r) 135 | noexcept; 136 | CHEETAH_INTERNAL bool exception_reducer_is_empty() noexcept; 137 | 138 | #ifdef __cplusplus 139 | } 140 | #endif 141 | 142 | #endif // _CILK_INTERNAL_H 143 | -------------------------------------------------------------------------------- /doc/REDUCER_PROTOCOL: -------------------------------------------------------------------------------- 1 | Reducer protocol: 2 | 3 | Each closure should contains three reducer maps (rmap): 4 | lchild_rmap 5 | right_sib_rmap 6 | user_rmap 7 | 8 | These are just place holders: 9 | lchild_rmap: holding the rmap deposited by the returning closure who is the 10 | left-most spawned child at the time of return. 11 | right_sib_rmap: holding the rmap deposited by the right sibling closure who is 12 | unlinking from the Closure tree. 13 | user_rmap: this is really a place holder, holding only views accumulated from 14 | the trace that leading up to the failed sync on the closure. 15 | 16 | This is because, whenever a worker fails to sync on a closure t, we need to 17 | deposit the w->user_map somewhere. We could have done it in 18 | t->right_most_child->right_sib_rmap, but then the right_most_child could 19 | change as t's spawned children return, and we don't want to hold lock on t 20 | whild doing reduction (may need to reduce user_map into 21 | t->right_most_child->right_sib_rmap). So it's just easier having a user_map 22 | as a place holder for this particular purpose to make things simpler. 23 | 24 | The worker also has a rmap: 25 | user_rmap, which holds the view accumulated when executing user code --- 26 | should be initialized with empty rmap at the beginning of a trace (upon a 27 | successful steal), and deposited at the end of a trace (before going for the 28 | next steal) 29 | 30 | - Upon a successful steal, the worker should create an empty user_rmap 31 | - Upon a sync, it should leave its user_rmap in the closure tree if it were to 32 | suspend. The question is, where in the closure tree. 33 | Call the syncing closure t; we hold lock on t at the moment. 34 | (Note that we must hold lock on a closure whenever we read its fields 35 | but w->user_rmap is only accessed by the worker w) 36 | 37 | - if t's join counter != 0 (still has spawned children), 38 | assert(t->user_rmap == NULL); // t->user_rmap is set once per sync 39 | t->user_rmap = w->user_rmap; 40 | w->user_rmap = NULL 41 | unlock(t); 42 | 43 | - Otherwise, t has no outstanding spawned children, and sync must succeed 44 | tmp = t->lchild_rmap; 45 | orig_lchild_rmap = t->lchild_rmap; // used for debugging purpose only 46 | unlock(t) 47 | tmp = tmp REDUCE_OP w->user_rmap 48 | w->user_rmap = NULL; 49 | lock(t) 50 | assert(orig_lchild_rmap == t->lchild_rmap); 51 | // this must be true as t->join_counter == 0 (assuming join_counter 52 | // is decremented after the reduction necessary for returning from 53 | // a spawned child 54 | t->lchild_rmap = tmp; 55 | 56 | assert(t->user_rmap == NULL); 57 | t->lchild_rmap = NULL; 58 | assert(w->user_rmap == NULL); 59 | w->user_rmap = t->lchild_rmap 60 | unlock(t) 61 | continue execution after sync with w->user_rmap 62 | 63 | - Upon a spawned child returning, say worker w returning from closure t to 64 | closure parent when we first enter the Closure_return, we hold no locks 65 | but t is off the deque 66 | 67 | - for t, assert t->lchild_rmap == NULL and t->user_rmap == NULL 68 | (this should be true since we should have passed a sync successfully 69 | without spawning more) 70 | w->user_rmap may not be NULL 71 | 72 | bool not_done = true; 73 | 74 | // need a loop as multiple siblings can return while we 75 | // are performing reductions 76 | while(not_done) { 77 | // always lock from top to bottom 78 | lock(parent) 79 | lock(t) 80 | 81 | cilk_redmap **left_ptr; // ptr to a ptr to reducer map 82 | // invariant: a closure cannot unlink itself w/out lock on parent 83 | // so what this points to cannot change while we have lock on parent 84 | 85 | right = t->right_sib_rmap; 86 | t->right_sib_rmap = NULL 87 | if(t has left_sibling) { 88 | left_ptr = &(t->left_sib->right_sib_rmap); 89 | } else { 90 | left_ptr = &(parent->lchild_rmap); 91 | } 92 | left = *left_ptr; 93 | *left_ptr = NULL; 94 | 95 | if(left == NULL && right == NULL) { 96 | *left_ptr = w->usr_rmap; // deposite views 97 | w->usr_rmap = NULL; 98 | Closure_remove_child(w, parent, t); // unlink t from the tree 99 | // we have deposited our views and unlinked; we can quit now 100 | // invariant: we can only decide to quit when we see no more maps 101 | // from the right, we have deposited our own rmap, and unlink from the 102 | // tree. All these are done while holding lock on the parent. 103 | // Before, another worker could deposit more rmap into our 104 | // right_rmap slot after we decide to quit, but now this cannot 105 | // occur as the worker depositing the rmap to our right_rmap also must 106 | // hold lock on the parent to do so. 107 | unlock(t); 108 | unlock(parent) 109 | not_done = false; 110 | } else { 111 | unlock(t); 112 | unlock(parent) 113 | if(left) { w->user_rmap = left REDUCE_OP w->usr_rmap; } 114 | if(right) { w->user_rmap = w->usr_rmap REDUCE_OP right; } 115 | } 116 | } 117 | 118 | - Now we can provably good steal 119 | lock(parent); 120 | parent->join_counter--; 121 | success = provably_good_steal(...); 122 | if(success) { 123 | assert(w->usr_rmap == NULL); 124 | w->usr_rmap = parent->lchild_rmap; 125 | if(parent->user_rmap) { 126 | tmp = parent->usr_rmap; 127 | parent->usr_rmap = NULL; 128 | } 129 | } 130 | unlock(parent); 131 | 132 | -------------------------------------------------------------------------------- /runtime/frame.h: -------------------------------------------------------------------------------- 1 | #ifndef _CILK_FRAME_H 2 | #define _CILK_FRAME_H 3 | 4 | #include "rts-config.h" 5 | #include "jmpbuf.h" 6 | #include 7 | #include 8 | 9 | struct __cilkrts_worker; 10 | struct __cilkrts_stack_frame; 11 | 12 | /** 13 | * Every spawning function has a frame descriptor. A spawning function 14 | * is a function that spawns or detaches. Only spawning functions 15 | * are visible to the Cilk runtime. 16 | */ 17 | struct __cilkrts_stack_frame { 18 | // Flags is a bitfield with values defined below. Client code 19 | // initializes flags to 0 before the first Cilk operation. 20 | uint32_t flags; 21 | // The magic number includes the ABI version and a hash of the 22 | // layout of this structure. 23 | uint32_t magic; 24 | 25 | // Pointer to the fiber header of the worker currently executing with this 26 | // stack frame. 27 | // 28 | // This pointer is redundant with the __cilkrts_tls.fh TLS variable, but 29 | // accessing TLS is expensive on some systems, such as macOS. It is 30 | // therefore faster to use this variable when possible. 31 | struct cilk_fiber *fh; 32 | 33 | // call_parent points to the __cilkrts_stack_frame of the closest ancestor 34 | // spawning function, including spawn helpers, of this frame. For each 35 | // worker, these pointers form a singly-linked list ending at the first 36 | // __cilkrts_stack_frame. 37 | struct __cilkrts_stack_frame *call_parent; 38 | 39 | // Before every spawn and nontrivial sync the client function 40 | // saves its continuation here. 41 | jmpbuf ctx; 42 | 43 | // Optional state for an extension, only maintained if 44 | // __cilkrts_use_extension == true. 45 | void *extension; 46 | }; 47 | 48 | //=========================================================== 49 | // Value defines for the flags field in cilkrts_stack_frame 50 | //=========================================================== 51 | 52 | /* CILK_FRAME_STOLEN is set if the frame has ever been stolen. */ 53 | #define CILK_FRAME_STOLEN 0x001 54 | 55 | /* CILK_FRAME_UNSYNCHED is set if the frame has been stolen and 56 | is has not yet executed _Cilk_sync. It is technically a misnomer in that a 57 | frame can have this flag set even if all children have returned. */ 58 | #define CILK_FRAME_UNSYNCHED 0x002 59 | 60 | /* Is this frame detached (spawned)? If so the runtime needs 61 | to undo-detach in the slow path epilogue. */ 62 | #define CILK_FRAME_DETACHED 0x004 63 | 64 | /* CILK_FRAME_EXCEPTION_PENDING is set if the frame has an exception 65 | to handle after syncing. */ 66 | #define CILK_FRAME_EXCEPTION_PENDING 0x008 67 | 68 | /* Is this frame throwing, specifically, from a stolen continuation? */ 69 | #define CILK_FRAME_THROWING 0x010 70 | 71 | /* Is this the last (oldest) Cilk frame? */ 72 | #define CILK_FRAME_LAST 0x080 73 | 74 | /* Is this frame handling an exception? */ 75 | // TODO: currently only used when throwing an exception from the continuation 76 | // (i.e. from the personality function). Used in scheduler.c to disable 77 | // asserts that fail if trying to longjmp back to the personality 78 | // function. 79 | #define CILK_FRAME_SYNC_READY 0x200 80 | 81 | static const uint32_t frame_magic = 82 | (((((((((((__CILKRTS_ABI_VERSION * 13) + 83 | offsetof(struct __cilkrts_stack_frame, ctx)) * 84 | 13) + 85 | offsetof(struct __cilkrts_stack_frame, magic)) * 86 | 13) + 87 | offsetof(struct __cilkrts_stack_frame, flags)) * 88 | 13) + 89 | offsetof(struct __cilkrts_stack_frame, call_parent)) * 90 | 13) + 91 | offsetof(struct __cilkrts_stack_frame, extension))); 92 | 93 | #define CHECK_CILK_FRAME_MAGIC(G, F) (frame_magic == (F)->magic) 94 | 95 | //=========================================================== 96 | // Helper functions for the flags field in cilkrts_stack_frame 97 | //=========================================================== 98 | 99 | /* A frame is set to be stolen as long as it has a corresponding Closure */ 100 | static inline void __cilkrts_set_stolen(struct __cilkrts_stack_frame *sf) { 101 | sf->flags |= CILK_FRAME_STOLEN; 102 | } 103 | 104 | /* A frame is set to be unsynced only if it has parallel subcomputation 105 | * underneathe, i.e., only if it has spawned children executing on a different 106 | * worker 107 | */ 108 | static inline void __cilkrts_set_unsynced(struct __cilkrts_stack_frame *sf) { 109 | sf->flags |= CILK_FRAME_UNSYNCHED; 110 | } 111 | 112 | static inline void __cilkrts_set_synced(struct __cilkrts_stack_frame *sf) { 113 | sf->flags &= ~CILK_FRAME_UNSYNCHED; 114 | } 115 | 116 | /* Returns nonzero if the frame has been stolen. 117 | Only used in assertions. */ 118 | static inline int __cilkrts_stolen(struct __cilkrts_stack_frame *sf) { 119 | return (sf->flags & CILK_FRAME_STOLEN); 120 | } 121 | 122 | /* Returns nonzero if the frame is synched. Only used in assertions. */ 123 | static inline int __cilkrts_synced(struct __cilkrts_stack_frame *sf) { 124 | return ((sf->flags & CILK_FRAME_UNSYNCHED) == 0); 125 | } 126 | 127 | /* Returns nonzero if the frame has never been stolen. */ 128 | static inline int __cilkrts_not_stolen(struct __cilkrts_stack_frame *sf) { 129 | return ((sf->flags & CILK_FRAME_STOLEN) == 0); 130 | } 131 | 132 | /* Returns nonzero if the frame is throwing an exception. */ 133 | static inline int __cilkrts_throwing(struct __cilkrts_stack_frame *sf) { 134 | return (sf->flags & CILK_FRAME_THROWING); 135 | } 136 | 137 | #endif /* _CILK_FRAME_H */ 138 | -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/HandleCompilerRT.cmake: -------------------------------------------------------------------------------- 1 | # Check if the compiler-rt library file path exists. 2 | # If found, cache the path in: 3 | # COMPILER_RT_LIBRARY-- 4 | # If err_flag is true OR path not found, emit a message and set: 5 | # COMPILER_RT_LIBRARY-- to NOTFOUND 6 | function(cache_compiler_rt_library err_flag name target library_file) 7 | if(err_flag OR NOT EXISTS "${library_file}") 8 | message(STATUS "Failed to find compiler-rt ${name} library for ${target}") 9 | set(COMPILER_RT_LIBRARY_${name}_${target} "NOTFOUND" CACHE INTERNAL 10 | "compiler-rt ${name} library for ${target}") 11 | else() 12 | message(STATUS "Found compiler-rt ${name} library: ${library_file}") 13 | set(COMPILER_RT_LIBRARY_${name}_${target} "${library_file}" CACHE INTERNAL 14 | "compiler-rt ${name} library for ${target}") 15 | endif() 16 | endfunction() 17 | 18 | function(get_component_name name variable) 19 | if(APPLE) 20 | if(NOT name MATCHES "builtins.*") 21 | set(component_name "${name}_") 22 | endif() 23 | if (CMAKE_OSX_SYSROOT MATCHES ".+MacOSX.+") 24 | set(component_name "${component_name}osx") 25 | 26 | elseif (CMAKE_OSX_SYSROOT MATCHES ".+iPhoneOS.+") 27 | set(component_name "${component_name}ios") 28 | elseif (CMAKE_OSX_SYSROOT MATCHES ".+iPhoneSimulator.+") 29 | set(component_name "${component_name}iossim") 30 | 31 | elseif (CMAKE_OSX_SYSROOT MATCHES ".+AppleTVOS.+") 32 | set(component_name "${component_name}tvos") 33 | elseif (CMAKE_OSX_SYSROOT MATCHES ".+AppleTVSimulator.+") 34 | set(component_name "${component_name}tvossim") 35 | 36 | elseif (CMAKE_OSX_SYSROOT MATCHES ".+WatchOS.+") 37 | set(component_name "${component_name}watchos") 38 | elseif (CMAKE_OSX_SYSROOT MATCHES ".+WatchSimulator.+") 39 | set(component_name "${component_name}watchossim") 40 | else() 41 | message(WARNING "Unknown Apple SDK ${CMAKE_OSX_SYSROOT}, we don't know which compiler-rt library suffix to use.") 42 | endif() 43 | else() 44 | set(component_name "${name}") 45 | endif() 46 | set(${variable} "${component_name}" PARENT_SCOPE) 47 | endfunction() 48 | 49 | # Find the path to compiler-rt library `name` (e.g. "builtins") for the 50 | # specified `TARGET` (e.g. "x86_64-linux-gnu") and return it in `variable`. 51 | # This calls cache_compiler_rt_library that caches the path to speed up 52 | # repeated invocations with the same `name` and `target`. 53 | function(find_compiler_rt_library name variable) 54 | cmake_parse_arguments(ARG "" "TARGET;FLAGS" "" ${ARGN}) 55 | # While we can use compiler-rt runtimes with other compilers, we need to 56 | # query the compiler for runtime location and thus we require Clang. 57 | if(NOT CMAKE_CXX_COMPILER_ID MATCHES Clang) 58 | set(${variable} "NOTFOUND" PARENT_SCOPE) 59 | return() 60 | endif() 61 | set(target "${ARG_TARGET}") 62 | if(NOT target AND CMAKE_CXX_COMPILER_TARGET) 63 | set(target "${CMAKE_CXX_COMPILER_TARGET}") 64 | endif() 65 | if(NOT DEFINED COMPILER_RT_LIBRARY_builtins_${target}) 66 | # If the cache variable is not defined, invoke Clang and then 67 | # set it with cache_compiler_rt_library. 68 | set(clang_command ${CMAKE_CXX_COMPILER} "${ARG_FLAGS}") 69 | if(target) 70 | list(APPEND clang_command "--target=${target}") 71 | endif() 72 | get_property(cxx_flags CACHE CMAKE_CXX_FLAGS PROPERTY VALUE) 73 | string(REPLACE " " ";" cxx_flags "${cxx_flags}") 74 | list(APPEND clang_command ${cxx_flags}) 75 | set(cmd_prefix "") 76 | if(MSVC AND ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") 77 | set(cmd_prefix "/clang:") 78 | endif() 79 | execute_process( 80 | COMMAND ${clang_command} "${cmd_prefix}--rtlib=compiler-rt" "${cmd_prefix}-print-libgcc-file-name" 81 | RESULT_VARIABLE had_error 82 | OUTPUT_VARIABLE library_file 83 | ) 84 | string(STRIP "${library_file}" library_file) 85 | file(TO_CMAKE_PATH "${library_file}" library_file) 86 | get_filename_component(dirname ${library_file} DIRECTORY) 87 | if(APPLE) 88 | execute_process( 89 | COMMAND ${clang_command} "--print-resource-dir" 90 | RESULT_VARIABLE had_error 91 | OUTPUT_VARIABLE resource_dir 92 | ) 93 | string(STRIP "${resource_dir}" resource_dir) 94 | set(dirname "${resource_dir}/lib/darwin") 95 | endif() 96 | get_filename_component(basename ${library_file} NAME) 97 | if(basename MATCHES ".*clang_rt\.([a-z0-9_\-]+)\.(a|lib)") 98 | set(from_name ${CMAKE_MATCH_1}) 99 | get_component_name(${CMAKE_MATCH_1} to_name) 100 | string(REPLACE "${from_name}" "${to_name}" basename "${basename}") 101 | set(library_file "${dirname}/${basename}") 102 | cache_compiler_rt_library(${had_error} builtins "${target}" "${library_file}") 103 | endif() 104 | endif() 105 | if(NOT COMPILER_RT_LIBRARY_builtins_${target}) 106 | set(${variable} "NOTFOUND" PARENT_SCOPE) 107 | return() 108 | endif() 109 | if(NOT DEFINED COMPILER_RT_LIBRARY_${name}_${target}) 110 | # Clang gives only the builtins library path. Other library paths are 111 | # obtained by substituting "builtins" with ${name} in the builtins 112 | # path and then checking if the resultant path exists. The result of 113 | # this check is also cached by cache_compiler_rt_library. 114 | set(library_file "${COMPILER_RT_LIBRARY_builtins_${target}}") 115 | if(library_file MATCHES ".*clang_rt\.([a-z0-9_\-]+)\.(a|lib)") 116 | set(from_name ${CMAKE_MATCH_0}) 117 | get_component_name(${name} to_name) 118 | string(REPLACE "${from_name}" "${to_name}" library_file "${library_file}") 119 | cache_compiler_rt_library(FALSE "${name}" "${target}" "${library_file}") 120 | endif() 121 | endif() 122 | set(${variable} "${COMPILER_RT_LIBRARY_${name}_${target}}" PARENT_SCOPE) 123 | endfunction() 124 | -------------------------------------------------------------------------------- /runtime/fiber.h: -------------------------------------------------------------------------------- 1 | #ifndef _FIBER_H 2 | #define _FIBER_H 3 | 4 | #include "cilk-internal.h" 5 | #include "debug.h" 6 | #include "fiber-header.h" 7 | #include "frame.h" 8 | #include "mutex.h" 9 | #include "rts-config.h" 10 | #include "worker.h" 11 | 12 | //=============================================================== 13 | // Struct defs used by fibers, fiber pools 14 | //=============================================================== 15 | 16 | // Statistics on active fibers that were allocated from this pool, 17 | struct fiber_pool_stats { 18 | int in_use; // number of fibers allocated - freed from / into the pool 19 | int max_in_use; // high watermark for in_use 20 | unsigned max_free; // high watermark for number of free fibers in the pool 21 | }; 22 | 23 | struct cilk_fiber_pool { 24 | worker_id mutex_owner; 25 | int shared; 26 | size_t stack_size; // Size of stacks for fibers in this pool. 27 | struct cilk_fiber_pool *parent; // Parent pool. 28 | // If this pool is empty, get from parent 29 | // Describes inactive fibers stored in the pool. 30 | struct cilk_fiber **fibers; // Array of max_size fiber pointers 31 | unsigned int capacity; // Limit on number of fibers in pool 32 | unsigned int size; // Number of fibers currently in the pool 33 | struct fiber_pool_stats stats; 34 | 35 | cilk_mutex lock __attribute__((aligned(CILK_CACHE_LINE))); 36 | }; 37 | 38 | //=============================================================== 39 | // Supported functions 40 | //=============================================================== 41 | 42 | static inline __attribute__((always_inline,nothrow)) void 43 | sysdep_save_fp_ctrl_state(__cilkrts_stack_frame *sf) { 44 | #ifdef CHEETAH_SAVE_MXCSR 45 | #if 1 46 | __asm__("stmxcsr %0" : "=m"(MXCSR(sf))); 47 | #else 48 | /* Disabled because LLVM's implementation is bad. */ 49 | sf->mxcsr = __builtin_ia32_stmxcsr(); /* aka _mm_setcsr */ 50 | #endif 51 | #else 52 | (void)sf; // intentionally unused 53 | #endif 54 | } 55 | 56 | /* 57 | * Restore the floating point state that is stored in a stack frame at each 58 | * spawn. This should be called each time a frame is resumed. OpenCilk 59 | * only saves MXCSR. The 80387 status word is obsolete. 60 | */ 61 | static inline __attribute__((always_inline,nothrow)) void 62 | sysdep_restore_fp_state(__cilkrts_stack_frame *sf) { 63 | /* TODO: Find a way to do this only when using floating point. */ 64 | #ifdef CHEETAH_SAVE_MXCSR 65 | #if 1 66 | __asm__ volatile("ldmxcsr %0" : : "m"(MXCSR(sf))); 67 | #else 68 | /* Disabled because LLVM's implementation is bad. */ 69 | __builtin_ia32_ldmxcsr(sf->mxcsr); /* aka _mm_getcsr */ 70 | #endif 71 | #else 72 | (void)sf; // intentionally unused 73 | #endif 74 | 75 | #ifdef __AVX__ 76 | /* VZEROUPPER improves performance when mixing SSE and AVX code. 77 | VZEROALL would work as well here because vector registers are 78 | dead but takes about 10 cycles longer. */ 79 | __builtin_ia32_vzeroupper(); 80 | #endif 81 | } 82 | 83 | static inline char *sysdep_reset_stack_for_resume(struct cilk_fiber *fiber, 84 | __cilkrts_stack_frame *sf) { 85 | CILK_ASSERT(fiber); 86 | char *sp = fiber->get_stack_start(); 87 | /* Debugging: make sure stack is accessible. */ 88 | ((volatile char *)sp)[-1]; 89 | SP(sf) = sp; 90 | 91 | return sp; 92 | } 93 | 94 | static inline __attribute__((noreturn)) 95 | void sysdep_longjmp_to_sf(__cilkrts_stack_frame *sf) { 96 | cilkrts_alert(FIBER, 97 | "longjmp to sf, BP/SP/PC: %p/%p/%p", FP(sf), SP(sf), PC(sf)); 98 | 99 | #if defined CHEETAH_SAVE_MXCSR 100 | // Restore the floating point state that was set in this frame at the 101 | // last spawn. 102 | sysdep_restore_fp_state(sf); 103 | #endif 104 | __builtin_longjmp(sf->ctx, 1); 105 | } 106 | 107 | CHEETAH_INTERNAL void cilk_fiber_pool_global_init(global_state *g); 108 | CHEETAH_INTERNAL void cilk_fiber_pool_global_terminate(global_state *g); 109 | CHEETAH_INTERNAL void cilk_fiber_pool_global_destroy(global_state *g); 110 | CHEETAH_INTERNAL void cilk_fiber_pool_per_worker_zero_init(__cilkrts_worker *w); 111 | CHEETAH_INTERNAL void cilk_fiber_pool_per_worker_init(__cilkrts_worker *w); 112 | CHEETAH_INTERNAL void cilk_fiber_pool_per_worker_terminate(__cilkrts_worker *w); 113 | CHEETAH_INTERNAL void cilk_fiber_pool_per_worker_destroy(__cilkrts_worker *w); 114 | 115 | // allocate / deallocate one fiber from / back to OS 116 | CHEETAH_INTERNAL 117 | struct cilk_fiber *cilk_fiber_allocate(size_t stacksize); 118 | CHEETAH_INTERNAL 119 | void cilk_fiber_deallocate(struct cilk_fiber *fiber); 120 | CHEETAH_INTERNAL 121 | void cilk_fiber_deallocate_global(global_state *, struct cilk_fiber *fiber); 122 | // allocate / deallocate one fiber from / back to per-worker pool 123 | CHEETAH_INTERNAL 124 | struct cilk_fiber *cilk_fiber_allocate_from_pool(__cilkrts_worker *w); 125 | CHEETAH_INTERNAL 126 | void cilk_fiber_deallocate_to_pool(__cilkrts_worker *w, 127 | struct cilk_fiber *fiber); 128 | 129 | #if CILK_ENABLE_ASAN_HOOKS 130 | void sanitizer_start_switch_fiber(struct cilk_fiber *fiber) __CILKRTS_NOTHROW; 131 | void sanitizer_finish_switch_fiber(void) __CILKRTS_NOTHROW; 132 | CHEETAH_INTERNAL void sanitizer_poison_fiber(struct cilk_fiber *fiber); 133 | CHEETAH_INTERNAL void sanitizer_unpoison_fiber(struct cilk_fiber *fiber); 134 | #else 135 | static inline void sanitizer_start_switch_fiber(struct cilk_fiber *fiber) { 136 | (void)fiber; 137 | } 138 | static inline void sanitizer_finish_switch_fiber() {} 139 | static inline void sanitizer_poison_fiber(struct cilk_fiber *fiber) { 140 | (void)fiber; 141 | } 142 | static inline void sanitizer_unpoison_fiber(struct cilk_fiber *fiber) { 143 | (void)fiber; 144 | } 145 | #endif // CILK_ENABLE_ASAN_HOOKS 146 | #endif 147 | -------------------------------------------------------------------------------- /runtime/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEBUG_H 2 | #define _DEBUG_H 3 | 4 | #include "rts-config.h" 5 | #include 6 | 7 | // forward declaration for using struct global_stat 8 | struct global_state; 9 | struct __cilkrts_worker; 10 | 11 | #define CILK_CHECK(g, cond, complain, ...) \ 12 | ((cond) ? (void)0 : cilk_die_internal(g, complain, __VA_ARGS__)) 13 | 14 | #ifndef ALERT_LVL 15 | #define ALERT_LVL 0x3d03 16 | #endif 17 | #define ALERT_NONE 0x0000 18 | #define ALERT_FIBER 0x0001 19 | #define ALERT_FIBER_SUMMARY 0x0002 20 | #define ALERT_MEMORY 0x0004 21 | #define ALERT_SYNC 0x0010 22 | #define ALERT_SCHED 0x0020 23 | #define ALERT_STEAL 0x0040 24 | #define ALERT_RETURN 0x0080 25 | #define ALERT_EXCEPT 0x0100 26 | #define ALERT_CFRAME 0x0200 27 | #define ALERT_REDUCE 0x0400 28 | #define ALERT_REDUCE_ID 0x0800 29 | #define ALERT_BOOT 0x1000 30 | #define ALERT_START 0x2000 31 | #define ALERT_CLOSURE 0x4000 32 | #define ALERT_NOBUF 0x80000000 33 | 34 | #if ALERT_LVL & (ALERT_CFRAME|ALERT_RETURN) 35 | extern unsigned int alert_level; 36 | #else 37 | extern CHEETAH_INTERNAL unsigned int alert_level; 38 | #endif 39 | #define ALERT_ENABLED(flag) (alert_level & (ALERT_LVL & ALERT_##flag)) 40 | 41 | #ifndef DEBUG_LVL 42 | #define DEBUG_LVL 0xff 43 | #endif 44 | 45 | #define DEBUG_MEMORY 0x01 46 | #define DEBUG_MEMORY_SLOW 0x02 47 | #define DEBUG_FIBER 0x04 48 | #define DEBUG_REDUCER 0x08 49 | #define DEBUG_DISENGAGE 0x10 50 | extern CHEETAH_INTERNAL unsigned int debug_level; 51 | #define DEBUG_ENABLED(flag) (debug_level & (DEBUG_LVL & DEBUG_##flag)) 52 | #define DEBUG_ENABLED_STATIC(flag) (DEBUG_LVL & DEBUG_##flag) 53 | 54 | // Unused: compiler inlines the stack frame creation 55 | // #define CILK_STACKFRAME_MAGIC 0xCAFEBABE 56 | 57 | CHEETAH_INTERNAL void set_alert_level_from_str(const char *const); 58 | CHEETAH_INTERNAL void set_alert_level(unsigned int); 59 | CHEETAH_INTERNAL void set_debug_level(unsigned int); 60 | CHEETAH_INTERNAL void flush_alert_log(void); 61 | 62 | __attribute__((__format__(__printf__, 1, 2))) 63 | CHEETAH_INTERNAL_NORETURN CHEETAH_COLD 64 | void cilkrts_bug(const char *fmt, ...); 65 | CHEETAH_INTERNAL_NORETURN CHEETAH_COLD 66 | void cilk_die_internal(struct global_state *const g, const char *fmt, ...); 67 | 68 | #if ALERT_LVL != 0 69 | __attribute__((__format__(__printf__, 2, 3))) void 70 | cilkrts_alert(int lvl, const char *fmt, ...); 71 | #pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" 72 | #define cilkrts_alert(CODE, FMT, ...) \ 73 | (alert_level & ((ALERT_##CODE) & ALERT_LVL)) \ 74 | ? cilkrts_alert(ALERT_##CODE, FMT, ##__VA_ARGS__) \ 75 | : (void)0 76 | #else 77 | #define cilkrts_alert(lvl, fmt, ...) 78 | #endif 79 | 80 | #if CILK_DEBUG 81 | 82 | #define WHEN_CILK_DEBUG(ex) ex 83 | 84 | /** Standard text for failed assertion */ 85 | CHEETAH_INTERNAL extern const char __cilkrts_assertion_failed[]; 86 | 87 | #define CILK_ASSERT(ex) \ 88 | (__builtin_expect((ex) != 0, 1) \ 89 | ? (void)0 \ 90 | : cilkrts_bug(__cilkrts_assertion_failed, __FILE__, __LINE__, #ex)) 91 | 92 | #define CILK_ASSERT_NULL(P) \ 93 | ({ void *_t = (P); __builtin_expect(!_t, 1) \ 94 | ? (void)0 \ 95 | : cilkrts_bug("%s: %d: cilk_assertion failed: %s (%p) == NULL", \ 96 | __FILE__, __LINE__, #P, _t);}) 97 | 98 | #define CILK_ASSERT_POINTER_EQUAL(P1, P2) \ 99 | ({ void *_t1 = (P1), *_t2 = (P2); __builtin_expect(_t1 == _t2, 1) \ 100 | ? (void)0 \ 101 | : cilkrts_bug("%s: %d: cilk_assertion failed: %s (%p) == %s (%p)", \ 102 | __FILE__, __LINE__, #P1, _t1, #P2, _t2);}) 103 | 104 | #define CILK_ASSERT_INDEX_ZERO(LEFT, I, RIGHT, FMT) \ 105 | (__builtin_expect(!(LEFT[I] RIGHT), 1) \ 106 | ? (void)0 \ 107 | : cilkrts_bug("%s: %d: cilk_assertion failed: %s[%u]%s = " FMT \ 108 | " should be 0", \ 109 | __FILE__, __LINE__, #LEFT, I, #RIGHT, LEFT[I] RIGHT)) 110 | 111 | #define CILK_ASSERT_LE(A, B, FMT) \ 112 | (__builtin_expect(((A) <= (B)) != 0, 1) \ 113 | ? (void)0 \ 114 | : cilkrts_bug("%s: %d: cilk assertion failed: %s (" FMT \ 115 | ") <= %s " FMT ")", \ 116 | __FILE__, __LINE__, #A, A, #B, B)) 117 | 118 | #define CILK_ABORT(msg) \ 119 | cilkrts_bug(__cilkrts_assertion_failed, __FILE__, __LINE__, msg) 120 | 121 | #define CILK_ABORT_G(msg) \ 122 | cilkrts_bug(__cilkrts_assertion_failed_g, __FILE__, __LINE__, msg) 123 | 124 | #else 125 | #define CILK_ASSERT(ex) 126 | #define CILK_ASSERT_NULL(ex) 127 | #define CILK_ASSERT_POINTER_EQUAL(P1, P2) 128 | #define CILK_ASSERT_INDEX_ZERO(LEFT, I, RIGHT, FMT) 129 | #define CILK_ASSERT_LE(A, B, FMT) 130 | #define CILK_ABORT(msg) 131 | #define CILK_ABORT_G(msg) 132 | #define WHEN_CILK_DEBUG(ex) 133 | #endif // CILK_DEBUG 134 | 135 | // to silence compiler warning for vars only used during debugging 136 | #define USE_UNUSED(var) (void)(var) 137 | #endif 138 | -------------------------------------------------------------------------------- /unittests/test-hypertable-common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define TRACE 0 8 | 9 | // Dummy implementation of __cilkrts_get_worker_number. 10 | unsigned __cilkrts_get_worker_number(void) { return 0; } 11 | 12 | #define CHEETAH_INTERNAL 13 | #include "../runtime/local-hypertable.h" 14 | 15 | // Print alert message 16 | void ALERT(const char *fmt, ...) { 17 | va_list l; 18 | va_start(l, fmt); 19 | vfprintf(stderr, fmt, l); 20 | va_end(l); 21 | } 22 | 23 | // Print additional trace information if TRACE == 1. 24 | void PRINT_TRACE(const char *fmt, ...) { 25 | #if TRACE 26 | va_list l; 27 | va_start(l, fmt); 28 | vfprintf(stderr, fmt, l); 29 | va_end(l); 30 | #endif 31 | } 32 | 33 | // Structures for specifying simple table commands for tests. 34 | enum table_command_type { 35 | TABLE_INSERT, 36 | TABLE_LOOKUP, 37 | TABLE_DELETE 38 | }; 39 | typedef struct table_command { 40 | enum table_command_type type; 41 | uintptr_t key; 42 | } table_command; 43 | 44 | // Verify the entries of a hyper_table to verify that key appears exactly 45 | // expected_count times. Optionally print the entries of hyper_table. 46 | void verify_hypertable(hyper_table *table, uintptr_t key, int32_t expected_count) { 47 | int32_t key_count = 0; 48 | int32_t capacity = table->capacity; 49 | struct bucket *buckets = table->buckets; 50 | PRINT_TRACE("table(%p): cap %d, occ %d, ins_rm %d\n", buckets, capacity, 51 | table->occupancy, table->ins_rm_count); 52 | if (capacity < MIN_HT_CAPACITY) { 53 | int32_t occupancy = table->occupancy; 54 | for (int32_t i = 0; i < occupancy; ++i) { 55 | PRINT_TRACE("table(%p)[%d] = { 0x%lx, %p }\n", buckets, i, 56 | buckets[i].key, buckets[i].value.view); 57 | if (is_valid(key) && buckets[i].key == key) 58 | key_count++; 59 | } 60 | if (key_count != expected_count) 61 | PRINT_TRACE("ERROR: Unexpected count (%d != %d) for key 0x%lx!\n", 62 | key_count, expected_count, key); 63 | assert(key_count == expected_count); 64 | return; 65 | } 66 | 67 | for (int32_t i = 0; i < capacity; ++i) { 68 | PRINT_TRACE("table(%p)[%d] = { 0x%lx, %d, %p }\n", buckets, i, 69 | buckets[i].key, buckets[i].hash, 70 | is_valid(buckets[i].key) ? buckets[i].value.view : NULL); 71 | if (is_valid(key) && buckets[i].key == key) 72 | key_count++; 73 | } 74 | if (key_count != expected_count) 75 | PRINT_TRACE("ERROR: Unexpected count (%d != %d) for key 0x%lx!\n", 76 | key_count, expected_count, key); 77 | assert(key_count == expected_count); 78 | } 79 | 80 | // A weaker form of verify_hypertable, returns whether the specified key shows 81 | // up the expected number of times. 82 | bool check_hypertable(hyper_table *table, uintptr_t key, 83 | int32_t expected_count) { 84 | int32_t key_count = 0; 85 | int32_t capacity = table->capacity; 86 | struct bucket *buckets = table->buckets; 87 | if (capacity < MIN_HT_CAPACITY) { 88 | int32_t occupancy = table->occupancy; 89 | for (int32_t i = 0; i < occupancy; ++i) { 90 | if (is_valid(key) && buckets[i].key == key) 91 | key_count++; 92 | } 93 | return key_count == expected_count; 94 | } 95 | 96 | for (int32_t i = 0; i < capacity; ++i) { 97 | if (is_valid(key) && buckets[i].key == key) 98 | key_count++; 99 | } 100 | return key_count == expected_count; 101 | } 102 | 103 | // Parse and execute a table_command on a hyper_table. 104 | void do_table_command(hyper_table *table, table_command cmd) { 105 | switch (cmd.type) { 106 | case TABLE_INSERT: { 107 | PRINT_TRACE("INSERT 0x%lx\n", cmd.key); 108 | /* if (!check_hypertable(table, cmd.key, 0)) { */ 109 | /* ALERT("INSERT Unsupported! 0x%lx already in table\n", cmd.key); */ 110 | /* break; */ 111 | /* } */ 112 | bool success = insert_hyperobject( 113 | table, (struct bucket){ 114 | .key = cmd.key, 115 | .value = {.view = (void *)cmd.key, .reduce_fn = NULL}}); 116 | assert(success && "insert_hyperobject failed"); 117 | verify_hypertable(table, cmd.key, 1); 118 | break; 119 | } 120 | case TABLE_LOOKUP: { 121 | PRINT_TRACE("LOOKUP 0x%lx\n", cmd.key); 122 | struct bucket *b = find_hyperobject(table, cmd.key); 123 | verify_hypertable(table, cmd.key, NULL != b); 124 | break; 125 | } 126 | case TABLE_DELETE: { 127 | PRINT_TRACE("DELETE 0x%lx\n", cmd.key); 128 | /* if (!check_hypertable(table, cmd.key, 1)) { */ 129 | /* ALERT("DELETE Unsupported! 0x%lx not in table\n", cmd.key); */ 130 | /* break; */ 131 | /* } */ 132 | bool success = remove_hyperobject(table, cmd.key); 133 | assert(success && "remove_hyperobject failed"); 134 | verify_hypertable(table, cmd.key, 0); 135 | break; 136 | } 137 | } 138 | } 139 | 140 | // Simple test routine to insert and remove elements from a hyper_table, 141 | // according to the given list of table_commands. 142 | void test_insert_remove(const table_command *commands, int num_commands) { 143 | hyper_table *table = __cilkrts_local_hyper_table_alloc(); 144 | for (int i = 0; i < num_commands; ++i) { 145 | do_table_command(table, commands[i]); 146 | } 147 | local_hyper_table_free(table); 148 | } 149 | 150 | void test_set_insert_remove(const uintptr_t *keys, int num_keys, 151 | const table_command *commands, int num_commands) { 152 | assert((num_keys & -num_keys) == num_keys && 153 | "Must use a power-of-2 number of keys."); 154 | hyper_table *table = __cilkrts_local_hyper_table_alloc(); 155 | 156 | // Add enough temporary keys to make the table the correct size. 157 | for (int i = 0; i < num_keys / 2 + 1; ++i) { 158 | table_command tmpInsert = {TABLE_INSERT, i + 1}; 159 | do_table_command(table, tmpInsert); 160 | } 161 | 162 | // Set the keys to their intended values. 163 | int num_valid = 0; 164 | int num_tomb = 0; 165 | for (int i = 0; i < num_keys; ++i) { 166 | num_valid += is_valid(keys[i]); 167 | num_tomb += is_tombstone(keys[i]); 168 | table->buckets[i].key = keys[i]; 169 | table->buckets[i].hash = hash(keys[i]) % num_keys; 170 | } 171 | table->occupancy = num_valid; 172 | table->ins_rm_count = num_tomb; 173 | verify_hypertable(table, 1, 0); 174 | 175 | // Run test. 176 | for (int i = 0; i < num_commands; ++i) { 177 | do_table_command(table, commands[i]); 178 | } 179 | local_hyper_table_free(table); 180 | } 181 | -------------------------------------------------------------------------------- /runtime/cilk2c.cpp: -------------------------------------------------------------------------------- 1 | #include "debug.h" 2 | #include "cilk-internal.h" 3 | #include "cilk2c.h" 4 | #include "fiber.h" 5 | #include "global.h" 6 | #include "rts-config.h" 7 | #include "scheduler.h" 8 | #include 9 | 10 | extern __attribute__((noreturn)) 11 | void _Unwind_Resume(struct _Unwind_Exception *); 12 | extern __attribute__((noreturn)) 13 | _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *); 14 | 15 | CHEETAH_INTERNAL struct cilkrts_callbacks cilkrts_callbacks = { 16 | 0, 0, false, {nullptr}, {nullptr}}; 17 | 18 | // Test if the Cilk runtime has been initialized. This method is intended to 19 | // help initialization of libraries that depend on the OpenCilk runtime. 20 | __attribute__((nothrow)) 21 | int __cilkrts_is_initialized(void) { return nullptr != default_cilkrts; } 22 | 23 | __attribute__((nothrow)) 24 | int __cilkrts_running_on_workers(void) { 25 | return !__cilkrts_status.need_to_cilkify; 26 | } 27 | 28 | // These callback-registration methods can run before the runtime system has 29 | // started. 30 | // 31 | // Init callbacks are called in order of registration. Exit callbacks are 32 | // called in reverse order of registration. 33 | 34 | // Register a callback to run at Cilk-runtime initialization. Returns 0 on 35 | // successful registration, nonzero otherwise. 36 | __attribute__((nothrow)) 37 | int __cilkrts_atinit(void (*callback)(void)) { 38 | if (cilkrts_callbacks.last_init >= MAX_CALLBACKS || 39 | cilkrts_callbacks.after_init) 40 | return -1; 41 | 42 | cilkrts_callbacks.init[cilkrts_callbacks.last_init++] = callback; 43 | return 0; 44 | } 45 | 46 | // Register a callback to run at Cilk-runtime exit. Returns 0 on successful 47 | // registration, nonzero otherwise. 48 | __attribute__((nothrow)) 49 | int __cilkrts_atexit(void (*callback)(void)) { 50 | if (cilkrts_callbacks.last_exit >= MAX_CALLBACKS) 51 | return -1; 52 | 53 | cilkrts_callbacks.exit[cilkrts_callbacks.last_exit++] = callback; 54 | return 0; 55 | } 56 | 57 | // Called after a normal cilk_sync or a cilk_sync performed within the 58 | // personality function. Checks if there is an exception that needs to be 59 | // propagated. This is called from the frame that will handle whatever exception 60 | // was thrown. 61 | void __cilkrts_check_exception_raise(__cilkrts_stack_frame *sf) { 62 | __cilkrts_worker *w = get_worker_from_stack(sf); 63 | CILK_ASSERT_POINTER_EQUAL(w, __cilkrts_get_tls_worker()); 64 | 65 | struct closure_exception *exn_r = get_exception_reducer(w); 66 | char *exn = exn_r->exn; 67 | 68 | // zero exception storage, so we don't unintentionally try to 69 | // handle/propagate this exception again 70 | clear_exception_reducer(w, exn_r); 71 | sf->flags &= ~CILK_FRAME_EXCEPTION_PENDING; 72 | 73 | if (exn != nullptr) { 74 | _Unwind_RaiseException((struct _Unwind_Exception *)exn); // noreturn 75 | __builtin_unreachable(); 76 | } 77 | 78 | return; 79 | } 80 | 81 | // Checks if there is an exception that needs to be propagated, and if so, 82 | // resumes unwinding with that exception. 83 | void __cilkrts_check_exception_resume(__cilkrts_stack_frame *sf) { 84 | __cilkrts_worker *w = get_worker_from_stack(sf); 85 | CILK_ASSERT_POINTER_EQUAL(w, __cilkrts_get_tls_worker()); 86 | 87 | struct closure_exception *exn_r = get_exception_reducer(w); 88 | char *exn = exn_r->exn; 89 | 90 | // zero exception storage, so we don't unintentionally try to 91 | // handle/propagate this exception again 92 | clear_exception_reducer(w, exn_r); 93 | sf->flags &= ~CILK_FRAME_EXCEPTION_PENDING; 94 | 95 | if (exn != nullptr) { 96 | _Unwind_Resume((struct _Unwind_Exception *)exn); // noreturn 97 | __builtin_unreachable(); 98 | } 99 | 100 | return; 101 | } 102 | 103 | // Called by generated exception-handling code, specifically, at the beginning 104 | // of each landingpad in a spawning function. Ensures that the stack pointer 105 | // points at the fiber and call-stack frame containing sf before any catch 106 | // handlers in that frame execute. 107 | extern "C" 108 | void __cilkrts_cleanup_fiber(__cilkrts_stack_frame *sf, int32_t sel) noexcept { 109 | (void)sel; // currently unused 110 | 111 | __cilkrts_worker *w = get_worker_from_stack(sf); 112 | CILK_ASSERT_POINTER_EQUAL(w, __cilkrts_get_tls_worker()); 113 | 114 | CILK_ASSERT(__cilkrts_synced(sf)); 115 | 116 | struct closure_exception *exn_r = get_exception_reducer_or_null(w); 117 | struct cilk_fiber *throwing_fiber = nullptr; 118 | char *parent_rsp = nullptr; 119 | if (exn_r != nullptr) { 120 | throwing_fiber = exn_r->throwing_fiber; 121 | parent_rsp = exn_r->parent_rsp; 122 | 123 | exn_r->throwing_fiber = nullptr; 124 | clear_exception_reducer(w, exn_r); 125 | } 126 | 127 | // If parent_rsp is non-null, then the Cilk personality function executed 128 | // __cilkrts_sync(sf), which implies that sf is at the top of the deque. 129 | // Because we're executing a non-cleanup landingpad, execution is continuing 130 | // within this function frame, rather than unwinding further to a parent 131 | // frame, which would belong to a distinct closure. Hence, if we reach this 132 | // point, set the stack pointer in sf to parent_rsp if parent_rsp is 133 | // non-null. 134 | 135 | if (nullptr == parent_rsp) { 136 | // If parent_rsp is null, we might have unwound past the point where the 137 | // Cilk personality function performed a sync. Because we're executing 138 | // a non-cleanup landing pad, execution is continuing within this frame, 139 | // and we can safely free any saved throwing fiber. 140 | if (throwing_fiber) { 141 | cilk_fiber_deallocate_to_pool(w, throwing_fiber); 142 | } 143 | return; 144 | } 145 | 146 | SP(sf) = (void *)parent_rsp; 147 | 148 | // Since we're longjmping to another fiber, we don't need to save 149 | // throwing_fiber anymore. 150 | if (throwing_fiber) { 151 | cilk_fiber_deallocate_to_pool(w, throwing_fiber); 152 | } 153 | __builtin_longjmp(sf->ctx, 1); // Does not return 154 | return; 155 | } 156 | 157 | extern "C" 158 | __attribute__((noreturn)) 159 | void __cilkrts_sync(__cilkrts_stack_frame *sf) { 160 | __cilkrts_worker *w = get_worker_from_stack(sf); 161 | CILK_ASSERT_POINTER_EQUAL(w, __cilkrts_get_tls_worker()); 162 | 163 | CILK_ASSERT(CHECK_CILK_FRAME_MAGIC(w->g, sf)); 164 | 165 | if (Cilk_sync(w, sf) == SYNC_READY) { 166 | // The Cilk_sync restores the original rsp stored in sf->ctx 167 | // if this frame is ready to sync. 168 | sysdep_longjmp_to_sf(sf); 169 | } else { 170 | longjmp_to_runtime(w); 171 | } 172 | } 173 | 174 | /////////////////////////////////////////////////////////////////////////// 175 | /// Methods for handling extensions 176 | 177 | extern "C" 178 | void __cilkrts_register_extension(void *extension) { 179 | __cilkrts_status.use_extension = true; 180 | __cilkrts_worker *w = __cilkrts_get_tls_worker(); 181 | w->extension = extension; 182 | } 183 | 184 | extern "C" 185 | void *__cilkrts_get_extension(void) { 186 | __cilkrts_worker *w = __cilkrts_get_tls_worker(); 187 | return w->extension; 188 | } 189 | -------------------------------------------------------------------------------- /cmake/Modules/HandleCheetahFlags.cmake: -------------------------------------------------------------------------------- 1 | # HandleCheetahFlags - A set of macros used to setup the flags used to compile 2 | # and link cheetah. These macros add flags to the following CMake variables. 3 | # - CHEETAH_COMPILE_FLAGS: flags used to compile cheetah 4 | # - CHEETAH_LINK_FLAGS: flags used to link cheetah 5 | 6 | include(CheckCXXCompilerFlag) 7 | 8 | unset(add_flag_if_supported) 9 | 10 | # Mangle the name of a compiler flag into a valid CMake identifier. 11 | # Ex: --std=c++11 -> STD_EQ_CXX11 12 | macro(mangle_name str output) 13 | string(STRIP "${str}" strippedStr) 14 | string(REGEX REPLACE "^/" "" strippedStr "${strippedStr}") 15 | string(REGEX REPLACE "^-+" "" strippedStr "${strippedStr}") 16 | string(REGEX REPLACE "-+$" "" strippedStr "${strippedStr}") 17 | string(REPLACE "-" "_" strippedStr "${strippedStr}") 18 | string(REPLACE "=" "_EQ_" strippedStr "${strippedStr}") 19 | string(REPLACE "+" "X" strippedStr "${strippedStr}") 20 | string(TOUPPER "${strippedStr}" ${output}) 21 | endmacro() 22 | 23 | # Remove a list of flags from all CMake variables that affect compile flags. 24 | # This can be used to remove unwanted flags specified on the command line 25 | # or added in other parts of LLVM's cmake configuration. 26 | macro(remove_flags) 27 | foreach(var ${ARGN}) 28 | string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") 29 | string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") 30 | string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") 31 | string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") 32 | string(REPLACE "${var}" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 33 | string(REPLACE "${var}" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") 34 | string(REPLACE "${var}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") 35 | string(REPLACE "${var}" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") 36 | string(REPLACE "${var}" "" CMAKE_SHARED_MODULE_FLAGS "${CMAKE_SHARED_MODULE_FLAGS}") 37 | remove_definitions(${var}) 38 | endforeach() 39 | endmacro(remove_flags) 40 | 41 | macro(check_flag_supported flag) 42 | mangle_name("${flag}" flagname) 43 | check_cxx_compiler_flag("${flag}" "CHEETAH_SUPPORTS_${flagname}_FLAG") 44 | endmacro() 45 | 46 | # Add a macro definition if condition is true. 47 | macro(define_if condition def) 48 | if (${condition}) 49 | add_definitions(${def}) 50 | endif() 51 | endmacro() 52 | 53 | # Add a macro definition if condition is not true. 54 | macro(define_if_not condition def) 55 | if (NOT ${condition}) 56 | add_definitions(${def}) 57 | endif() 58 | endmacro() 59 | 60 | # Add a macro definition to the __config_site file if the specified condition 61 | # is 'true'. Note that '-D${def}' is not added. Instead it is expected that 62 | # the build include the '__config_site' header. 63 | macro(config_define_if condition def) 64 | if (${condition}) 65 | set(${def} ON) 66 | set(CHEETAH_NEEDS_SITE_CONFIG ON) 67 | endif() 68 | endmacro() 69 | 70 | macro(config_define_if_not condition def) 71 | if (NOT ${condition}) 72 | set(${def} ON) 73 | set(CHEETAH_NEEDS_SITE_CONFIG ON) 74 | endif() 75 | endmacro() 76 | 77 | macro(config_define value def) 78 | set(${def} ${value}) 79 | set(CHEETAH_NEEDS_SITE_CONFIG ON) 80 | endmacro() 81 | 82 | # Add a list of flags to all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 83 | # 'CHEETAH_COMPILE_FLAGS' and 'CHEETAH_LINK_FLAGS'. 84 | macro(add_target_flags) 85 | foreach(value ${ARGN}) 86 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${value}") 87 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${value}") 88 | list(APPEND CHEETAH_COMPILE_FLAGS ${value}) 89 | list(APPEND CHEETAH_LINK_FLAGS ${value}) 90 | endforeach() 91 | endmacro() 92 | 93 | # If the specified 'condition' is true then add a list of flags to 94 | # all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'CHEETAH_COMPILE_FLAGS' 95 | # and 'CHEETAH_LINK_FLAGS'. 96 | macro(add_target_flags_if condition) 97 | if (${condition}) 98 | add_target_flags(${ARGN}) 99 | endif() 100 | endmacro() 101 | 102 | # Add a specified list of flags to both 'CHEETAH_COMPILE_FLAGS' and 103 | # 'CHEETAH_LINK_FLAGS'. 104 | macro(add_flags) 105 | foreach(value ${ARGN}) 106 | list(APPEND CHEETAH_COMPILE_FLAGS ${value}) 107 | list(APPEND CHEETAH_LINK_FLAGS ${value}) 108 | endforeach() 109 | endmacro() 110 | 111 | # If the specified 'condition' is true then add a list of flags to both 112 | # 'CHEETAH_COMPILE_FLAGS' and 'CHEETAH_LINK_FLAGS'. 113 | macro(add_flags_if condition) 114 | if (${condition}) 115 | add_flags(${ARGN}) 116 | endif() 117 | endmacro() 118 | 119 | # Add each flag in the list to CHEETAH_COMPILE_FLAGS and CHEETAH_LINK_FLAGS 120 | # if that flag is supported by the current compiler. 121 | macro(add_flags_if_supported) 122 | foreach(flag ${ARGN}) 123 | mangle_name("${flag}" flagname) 124 | check_cxx_compiler_flag("${flag}" "CHEETAH_SUPPORTS_${flagname}_FLAG") 125 | add_flags_if(CHEETAH_SUPPORTS_${flagname}_FLAG ${flag}) 126 | endforeach() 127 | endmacro() 128 | 129 | # Add a list of flags to 'CHEETAH_COMPILE_FLAGS'. 130 | macro(add_compile_flags) 131 | foreach(f ${ARGN}) 132 | list(APPEND CHEETAH_COMPILE_FLAGS ${f}) 133 | endforeach() 134 | endmacro() 135 | 136 | # If 'condition' is true then add the specified list of flags to 137 | # 'CHEETAH_COMPILE_FLAGS' 138 | macro(add_compile_flags_if condition) 139 | if (${condition}) 140 | add_compile_flags(${ARGN}) 141 | endif() 142 | endmacro() 143 | 144 | # For each specified flag, add that flag to 'CHEETAH_COMPILE_FLAGS' if the 145 | # flag is supported by the C++ compiler. 146 | macro(add_compile_flags_if_supported) 147 | foreach(flag ${ARGN}) 148 | mangle_name("${flag}" flagname) 149 | check_cxx_compiler_flag("${flag}" "CHEETAH_SUPPORTS_${flagname}_FLAG") 150 | add_compile_flags_if(CHEETAH_SUPPORTS_${flagname}_FLAG ${flag}) 151 | endforeach() 152 | endmacro() 153 | 154 | # For each specified flag, add that flag to 'CHEETAH_COMPILE_FLAGS' if the 155 | # flag is supported by the C compiler. 156 | macro(add_c_compile_flags_if_supported) 157 | foreach(flag ${ARGN}) 158 | mangle_name("${flag}" flagname) 159 | check_c_compiler_flag("${flag}" "CHEETAH_SUPPORTS_${flagname}_FLAG") 160 | add_compile_flags_if(CHEETAH_SUPPORTS_${flagname}_FLAG ${flag}) 161 | endforeach() 162 | endmacro() 163 | 164 | # Add a list of flags to 'CHEETAH_LINK_FLAGS'. 165 | macro(add_link_flags) 166 | foreach(f ${ARGN}) 167 | list(APPEND CHEETAH_LINK_FLAGS ${f}) 168 | endforeach() 169 | endmacro() 170 | 171 | # If 'condition' is true then add the specified list of flags to 172 | # 'CHEETAH_LINK_FLAGS' 173 | macro(add_link_flags_if condition) 174 | if (${condition}) 175 | add_link_flags(${ARGN}) 176 | endif() 177 | endmacro() 178 | 179 | # For each specified flag, add that flag to 'CHEETAH_LINK_FLAGS' if the 180 | # flag is supported by the C++ compiler. 181 | macro(add_link_flags_if_supported) 182 | foreach(flag ${ARGN}) 183 | mangle_name("${flag}" flagname) 184 | check_cxx_compiler_flag("${flag}" "CHEETAH_SUPPORTS_${flagname}_FLAG") 185 | add_link_flags_if(CHEETAH_SUPPORTS_${flagname}_FLAG ${flag}) 186 | endforeach() 187 | endmacro() 188 | 189 | # Turn a comma separated CMake list into a space separated string. 190 | macro(split_list listname) 191 | string(REPLACE ";" " " ${listname} "${${listname}}") 192 | endmacro() 193 | -------------------------------------------------------------------------------- /runtime/readydeque.h: -------------------------------------------------------------------------------- 1 | #ifndef _READYDEQUE_H 2 | #define _READYDEQUE_H 3 | 4 | #include "closure.h" 5 | #include "rts-config.h" 6 | #include "worker_coord.h" 7 | #include 8 | 9 | // Forward declaration 10 | struct ReadyDeque; 11 | 12 | // Includes 13 | #include "cilk-internal.h" 14 | #include "mutex.h" 15 | #include "debug.h" 16 | #include "global.h" 17 | #include "local.h" 18 | 19 | // Actual declaration 20 | struct ReadyDeque { 21 | Closure *bottom; 22 | Closure *top __attribute__((aligned(CILK_CACHE_LINE))); 23 | std::atomic mutex_owner 24 | __attribute__((aligned(CILK_CACHE_LINE))); 25 | 26 | /********************************************************* 27 | * Management of ReadyDeques 28 | *********************************************************/ 29 | 30 | void assert_ownership(worker_id self) { 31 | CILK_ASSERT(mutex_owner.load(std::memory_order_relaxed) == self); 32 | (void)self; 33 | } 34 | 35 | static void assert_ownership(ReadyDeque *deques, worker_id self, 36 | worker_id pn) { 37 | deques[pn].assert_ownership(self); 38 | } 39 | 40 | void lock(worker_id id) { 41 | while (true) { 42 | worker_id current_owner = 43 | mutex_owner.load(std::memory_order_relaxed); 44 | if ((current_owner == NO_WORKER) && 45 | mutex_owner.compare_exchange_weak 46 | (current_owner, id, std::memory_order_acq_rel, 47 | std::memory_order_relaxed)) 48 | return; 49 | busy_loop_pause(); 50 | } 51 | } 52 | 53 | static void lock(ReadyDeque *deques, worker_id self, worker_id pn) { 54 | deques[pn].lock(self); 55 | } 56 | 57 | static void lock_self(ReadyDeque *deques, worker_id self) { 58 | deques[self].lock(self); 59 | } 60 | static void unlock_self(ReadyDeque *deques, worker_id self) { 61 | worker_id id = self; 62 | deques[id].mutex_owner.store(NO_WORKER, std::memory_order_release); 63 | } 64 | 65 | bool trylock(worker_id id) { 66 | worker_id current_owner = 67 | mutex_owner.load(std::memory_order_relaxed); 68 | if (current_owner == NO_WORKER) 69 | return mutex_owner.compare_exchange_weak 70 | (current_owner, id, std::memory_order_acq_rel, 71 | std::memory_order_relaxed); 72 | return false; 73 | } 74 | 75 | static bool trylock(ReadyDeque *deques, worker_id self, worker_id pn) { 76 | return deques[pn].trylock(self); 77 | } 78 | 79 | void unlock(worker_id self) { 80 | (void)self; // TODO: Remove unused parameter? 81 | mutex_owner.store(NO_WORKER, std::memory_order_release); 82 | } 83 | 84 | static void unlock(ReadyDeque *deques, worker_id self, worker_id pn) { 85 | deques[pn].unlock(self); 86 | } 87 | 88 | /* 89 | * functions that add/remove elements from the top/bottom 90 | * of deques 91 | * 92 | * ANGE: the precondition of these functions is that the worker w -> self 93 | * must have locked worker pn's deque before entering the function 94 | */ 95 | 96 | Closure *xtract_top(worker_id self) { 97 | /* ANGE: make sure w has the lock on worker pn's deque */ 98 | assert_ownership(self); 99 | 100 | if (Closure *cl = top) { 101 | top = cl->next_ready; 102 | /* ANGE: if there is only one entry in the deque ... */ 103 | if (cl == bottom) { 104 | CILK_ASSERT_NULL(cl->next_ready); 105 | bottom = nullptr; 106 | } else { 107 | CILK_ASSERT(cl->next_ready); 108 | (cl->next_ready)->prev_ready = nullptr; 109 | } 110 | cl->owner_ready_deque = NO_WORKER; 111 | return cl; 112 | } 113 | CILK_ASSERT_NULL(bottom); 114 | return nullptr; 115 | } 116 | 117 | static Closure *xtract_top(ReadyDeque *deques, worker_id self, 118 | worker_id pn) { 119 | return deques[pn].xtract_top(self); 120 | } 121 | 122 | static Closure *xtract_bottom(ReadyDeque *deques, worker_id self, 123 | worker_id pn) { 124 | return deques[pn].xtract_bottom(self); 125 | } 126 | 127 | Closure *xtract_bottom(worker_id self) { 128 | /* ANGE: make sure w has the lock on worker pn's deque */ 129 | assert_ownership(self); 130 | 131 | if (Closure *cl = bottom) { 132 | bottom = cl->prev_ready; 133 | if (cl == top) { 134 | CILK_ASSERT_NULL(cl->prev_ready); 135 | top = nullptr; 136 | } else { 137 | CILK_ASSERT(cl->prev_ready); 138 | (cl->prev_ready)->next_ready = nullptr; 139 | } 140 | cl->owner_ready_deque = NO_WORKER; 141 | return cl; 142 | } 143 | CILK_ASSERT_NULL(top); 144 | return nullptr; 145 | } 146 | 147 | Closure *peek_top(worker_id self) { 148 | /* ANGE: make sure w has the lock on worker pn's deque */ 149 | assert_ownership(self); 150 | 151 | /* ANGE: return the top but does not unlink it from the rest */ 152 | if (Closure *cl = top) { 153 | // If w is stealing, then it may peek the top of the deque 154 | // of the worker who is in the midst of exiting a 155 | // Cilkified region. In that case, cl will be the root 156 | // closure, and cl->owner_ready_deque is not necessarily 157 | // pn. The steal will subsequently fail do_dekker_on. 158 | //CILK_ASSERT(cl->owner_ready_deque == pn || 159 | // (self != pn && cl == w->g->root_closure)); 160 | return cl; 161 | } 162 | CILK_ASSERT_NULL(bottom); 163 | return nullptr; 164 | } 165 | 166 | static Closure *peek_top(ReadyDeque *deques, worker_id self, 167 | worker_id pn) { 168 | return deques[pn].peek_top(self); 169 | } 170 | 171 | Closure *peek_bottom(worker_id self) { 172 | /* ANGE: make sure w has the lock on worker pn's deque */ 173 | assert_ownership(self); 174 | 175 | if (Closure *cl = bottom) { 176 | return cl; 177 | } 178 | CILK_ASSERT_NULL(top); 179 | return nullptr; 180 | } 181 | 182 | static Closure * 183 | peek_bottom(ReadyDeque *deques, worker_id self, worker_id pn) { 184 | return deques[pn].peek_bottom(self); 185 | } 186 | 187 | /* 188 | * ANGE: this allow w -> self to append Closure cl onto worker pn's ready 189 | * deque (i.e. make cl the new bottom). 190 | */ 191 | void add_bottom(Closure *cl, worker_id self, worker_id pn) { 192 | assert_ownership(self); 193 | 194 | CILK_ASSERT(cl->owner_ready_deque == NO_WORKER); 195 | 196 | cl->prev_ready = bottom; 197 | cl->next_ready = nullptr; 198 | bottom = cl; 199 | cl->owner_ready_deque = pn; 200 | if (top) { 201 | CILK_ASSERT(cl->prev_ready); 202 | (cl->prev_ready)->next_ready = cl; 203 | } else { 204 | top = cl; 205 | } 206 | } 207 | 208 | static void add_bottom(ReadyDeque *deques, Closure *cl, 209 | worker_id self, worker_id pn) { 210 | return deques[pn].add_bottom(cl, self, pn); 211 | } 212 | 213 | } __attribute__((aligned(CILK_CACHE_LINE))); 214 | 215 | #endif 216 | -------------------------------------------------------------------------------- /handcomp_test/mm_dac.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../runtime/cilk2c.h" 5 | #include "../runtime/cilk2c_inlined.cpp" 6 | #include "ktiming.h" 7 | #include "getoptions.h" 8 | 9 | #ifndef TIMING_COUNT 10 | #define TIMING_COUNT 1 11 | #endif 12 | 13 | #define CHECK_RESULT 1 14 | #define THRESHOLD 16 15 | #define TRUE 1 16 | #define FALSE 0 17 | 18 | extern size_t ZERO; 19 | void __attribute__((weak)) dummy(void *p) { return; } 20 | 21 | unsigned int randomSeed = 1; 22 | 23 | static void mm_dac_serial(int *C, const int *A, const int *B, int n, int length) { 24 | 25 | if(length < THRESHOLD) { 26 | // Use a loop for small matrices 27 | for (int i = 0; i < length; i++) 28 | for (int j = 0; j < length; j++) 29 | for (int k = 0; k < length; k++) 30 | C[i*n+j] += A[i*n+k] * B[k*n+j]; 31 | return; 32 | } 33 | 34 | // Partition the matrices 35 | int mid = length >> 1; 36 | 37 | int *C00 = C; 38 | int *C01 = C + mid; 39 | int *C10 = C + n*mid; 40 | int *C11 = C + n*mid + mid; 41 | 42 | int const *A00 = A; 43 | int const *A01 = A + mid; 44 | int const *A10 = A + n*mid; 45 | int const *A11 = A + n*mid + mid; 46 | 47 | int const *B00 = B; 48 | int const *B01 = B + mid; 49 | int const *B10 = B + n*mid; 50 | int const *B11 = B + n*mid + mid; 51 | 52 | mm_dac_serial(C00, A00, B00, n, mid); 53 | mm_dac_serial(C01, A00, B01, n, mid); 54 | mm_dac_serial(C10, A10, B00, n, mid); 55 | mm_dac_serial(C11, A10, B01, n, mid); 56 | 57 | mm_dac_serial(C00, A01, B10, n, mid); 58 | mm_dac_serial(C01, A01, B11, n, mid); 59 | mm_dac_serial(C10, A11, B10, n, mid); 60 | mm_dac_serial(C11, A11, B11, n, mid); 61 | } 62 | 63 | __attribute__((noinline)) static void 64 | mm_dac_spawn_helper(int *C, const int *A, const int *B, int n, int length, 65 | __cilkrts_stack_frame *parent); 66 | 67 | /** 68 | * Recursive implementation of matrix multiply. 69 | * This code will not work on non-square matrices. 70 | * Effect: Compute C+=A*B, 71 | * where C, A, and B are the starting addresses of submatrices with dimension 72 | * length x length. Argument n is the original input matrix length. 73 | **/ 74 | static void mm_dac(int *C, const int *A, const int *B, int n, int length) { 75 | 76 | if(length < THRESHOLD) { 77 | // Use a loop for small matrices 78 | for (int i = 0; i < length; i++) 79 | for (int j = 0; j < length; j++) 80 | for (int k = 0; k < length; k++) 81 | C[i*n+j] += A[i*n+k] * B[k*n+j]; 82 | return; 83 | } 84 | 85 | dummy(alloca(ZERO)); 86 | __cilkrts_stack_frame sf; 87 | __cilkrts_enter_frame(&sf); 88 | 89 | // Partition the matrices 90 | int mid = length >> 1; 91 | 92 | int *C00 = C; 93 | int *C01 = C + mid; 94 | int *C10 = C + n*mid; 95 | int *C11 = C + n*mid + mid; 96 | 97 | int const *A00 = A; 98 | int const *A01 = A + mid; 99 | int const *A10 = A + n*mid; 100 | int const *A11 = A + n*mid + mid; 101 | 102 | int const *B00 = B; 103 | int const *B01 = B + mid; 104 | int const *B10 = B + n*mid; 105 | int const *B11 = B + n*mid + mid; 106 | 107 | /* cilk_spawn mm_dac(C00, A00, B00, n, mid); */ 108 | if (!__cilk_prepare_spawn(&sf)) { 109 | mm_dac_spawn_helper(C00, A00, B00, n, mid, &sf); 110 | } 111 | 112 | /* cilk_spawn mm_dac(C01, A00, B01, n, mid); */ 113 | if (!__cilk_prepare_spawn(&sf)) { 114 | mm_dac_spawn_helper(C01, A00, B01, n, mid, &sf); 115 | } 116 | 117 | /* cilk_spawn mm_dac(C10, A10, B00, n, mid); */ 118 | if (!__cilk_prepare_spawn(&sf)) { 119 | mm_dac_spawn_helper(C10, A10, B00, n, mid, &sf); 120 | } 121 | mm_dac(C11, A10, B01, n, mid); 122 | 123 | /* cilk_sync */ 124 | __cilk_sync_nothrow(&sf); 125 | 126 | /* cilk_spawn mm_dac(C00, A01, B10, n, mid); */ 127 | if (!__cilk_prepare_spawn(&sf)) { 128 | mm_dac_spawn_helper(C00, A01, B10, n, mid, &sf); 129 | } 130 | 131 | /* cilk_spawn mm_dac(C01, A01, B11, n, mid); */ 132 | if (!__cilk_prepare_spawn(&sf)) { 133 | mm_dac_spawn_helper(C01, A01, B11, n, mid, &sf); 134 | } 135 | 136 | /* cilk_spawn mm_dac(C10, A11, B10, n, mid); */ 137 | if (!__cilk_prepare_spawn(&sf)) { 138 | mm_dac_spawn_helper(C10, A11, B10, n, mid, &sf); 139 | } 140 | mm_dac(C11, A11, B11, n, mid); 141 | 142 | /* cilk_sync */ 143 | __cilk_sync_nothrow(&sf); 144 | 145 | __cilk_parent_epilogue(&sf); 146 | } 147 | 148 | __attribute__((noinline)) 149 | static void mm_dac_spawn_helper(int *C, const int *A, const int *B, int n, int length, 150 | __cilkrts_stack_frame *parent) { 151 | 152 | __cilkrts_stack_frame sf; 153 | __cilkrts_enter_frame_helper(&sf, parent, false); 154 | __cilkrts_detach(&sf, parent); 155 | mm_dac(C, A, B, n, length); 156 | __cilk_helper_epilogue(&sf, parent, false); 157 | } 158 | 159 | static void rand_matrix(int *dest, int n) { 160 | for(int i = 0; i < n*n; ++i) 161 | dest[i] = rand_r(&randomSeed) & 0xff; 162 | } 163 | 164 | static void zero_matrix(int *dest, int n) { 165 | for(int i = 0; i < n*n; ++i) 166 | dest[i] = 0; 167 | } 168 | 169 | #if CHECK_RESULT 170 | static int are_equal_matrices(const int *a, const int *b, int n) { 171 | for(int i = 0; i < n*n; ++i) 172 | if(a[i] != b[i]) 173 | return FALSE; 174 | return TRUE; 175 | } 176 | #endif 177 | 178 | static void test_mm(int n, int check) { 179 | clockmark_t begin, end; 180 | uint64_t running_time[TIMING_COUNT]; 181 | 182 | int *A = (int *) malloc(sizeof(int)*(n*n)); 183 | int *B = (int *) malloc(sizeof(int)*(n*n)); 184 | int *C = (int *) malloc(sizeof(int)*(n*n)); 185 | 186 | rand_matrix(A, n); 187 | rand_matrix(B, n); 188 | 189 | for(int i = 0; i < TIMING_COUNT; i++) { 190 | zero_matrix(C, n); 191 | begin = ktiming_getmark(); 192 | mm_dac(C, A, B, n, n); 193 | end = ktiming_getmark(); 194 | running_time[i] = ktiming_diff_nsec(&begin, &end); 195 | } 196 | print_runtime(running_time, TIMING_COUNT); 197 | 198 | if(check) { 199 | fprintf(stderr, "Checking result ...\n"); 200 | int * Cs = (int*) malloc(sizeof(int) * (n*n)); 201 | zero_matrix(Cs, n); 202 | mm_dac_serial(Cs, A, B, n, n); 203 | if(!are_equal_matrices(C, Cs, n)) { 204 | fprintf(stderr, "MM_dac test FAILED.\n"); 205 | } else { 206 | fprintf(stderr, "MM_dac test passed.\n"); 207 | } 208 | free(Cs); 209 | } 210 | 211 | free(C); 212 | free(B); 213 | free(A); 214 | } 215 | 216 | // return true iff n = 2^k (or 0). 217 | static int is_power_of_2(int n) { 218 | return (n & (n-1)) == 0; 219 | } 220 | 221 | 222 | const char *specifiers[] = {"-n", "-c", "-h", 0}; 223 | int opt_types[] = {LONGARG, BOOLARG, BOOLARG, 0}; 224 | 225 | int main(int argc, char *argv[]) { 226 | 227 | long size; 228 | int help, check; 229 | 230 | /* standard benchmark options */ 231 | size = 1024; 232 | check = 0; 233 | help = 0; 234 | 235 | get_options(argc, argv, specifiers, opt_types, &size, &check, &help); 236 | 237 | if(help) { 238 | fprintf(stderr, "Usage: mm_dac [cilk options] -n [-c|-h]\n"); 239 | fprintf(stderr, " when -c is set, check result against sequential MM (slow).\n"); 240 | fprintf(stderr, " when -h is set, print this message and quit.\n"); 241 | exit(0); 242 | } 243 | 244 | if(!is_power_of_2(size)) { 245 | fprintf(stderr, "Input size must be a power of 2 \n"); 246 | exit(1); 247 | } 248 | test_mm(size, check); 249 | 250 | return 0; 251 | } 252 | -------------------------------------------------------------------------------- /cmake/LLVMCommonModules/FindGRPC.cmake: -------------------------------------------------------------------------------- 1 | option(ENABLE_GRPC_REFLECTION "Link to gRPC Reflection library" OFF) 2 | 3 | # FIXME(kirillbobyrev): Check if gRPC and Protobuf headers can be included at 4 | # configure time. 5 | find_package(Threads REQUIRED) 6 | if (GRPC_INSTALL_PATH) 7 | # This setup requires gRPC to be built from sources using CMake and installed 8 | # to ${GRPC_INSTALL_PATH} via -DCMAKE_INSTALL_PREFIX=${GRPC_INSTALL_PATH}. 9 | # Libraries will be linked according to gRPC build policy which generates 10 | # static libraries when BUILD_SHARED_LIBS is Off and dynamic libraries when 11 | # it's On (NOTE: This is a variable passed to gRPC CMake build invocation, 12 | # LLVM's BUILD_SHARED_LIBS has no effect). 13 | set(protobuf_MODULE_COMPATIBLE TRUE) 14 | find_package(Protobuf CONFIG REQUIRED HINTS ${GRPC_INSTALL_PATH}) 15 | message(STATUS "Using protobuf ${Protobuf_VERSION}") 16 | find_package(gRPC CONFIG REQUIRED HINTS ${GRPC_INSTALL_PATH}) 17 | message(STATUS "Using gRPC ${gRPC_VERSION}") 18 | 19 | include_directories(${Protobuf_INCLUDE_DIRS}) 20 | 21 | # gRPC CMake CONFIG gives the libraries slightly odd names, make them match 22 | # the conventional system-installed names. 23 | set_target_properties(protobuf::libprotobuf PROPERTIES IMPORTED_GLOBAL TRUE) 24 | add_library(protobuf ALIAS protobuf::libprotobuf) 25 | set_target_properties(gRPC::grpc++ PROPERTIES IMPORTED_GLOBAL TRUE) 26 | add_library(grpc++ ALIAS gRPC::grpc++) 27 | if (ENABLE_GRPC_REFLECTION) 28 | set_target_properties(gRPC::grpc++_reflection PROPERTIES IMPORTED_GLOBAL TRUE) 29 | add_library(grpc++_reflection ALIAS gRPC::grpc++_reflection) 30 | endif() 31 | 32 | set(GRPC_CPP_PLUGIN $) 33 | set(PROTOC ${Protobuf_PROTOC_EXECUTABLE}) 34 | else() 35 | # This setup requires system-installed gRPC and Protobuf. 36 | # We always link dynamically in this mode. While the static libraries are 37 | # usually installed, the CMake files telling us *which* static libraries to 38 | # link are not. 39 | if (NOT BUILD_SHARED_LIBS) 40 | message(NOTICE "gRPC and Protobuf will be linked dynamically. If you want static linking, build gRPC from sources with -DBUILD_SHARED_LIBS=Off.") 41 | endif() 42 | find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin) 43 | find_program(PROTOC protoc) 44 | if (NOT GRPC_CPP_PLUGIN OR NOT PROTOC) 45 | message(FATAL_ERROR "gRPC C++ Plugin and Protoc must be on $PATH for gRPC-enabled build.") 46 | endif() 47 | # On macOS the libraries are typically installed via Homebrew and are not on 48 | # the system path. 49 | set(GRPC_OPTS "") 50 | set(PROTOBUF_OPTS "") 51 | set(GRPC_INCLUDE_PATHS "") 52 | if (${APPLE}) 53 | find_program(HOMEBREW brew) 54 | # If Homebrew is not found, the user might have installed libraries 55 | # manually. Fall back to the system path. 56 | if (HOMEBREW) 57 | execute_process(COMMAND ${HOMEBREW} --prefix grpc 58 | OUTPUT_VARIABLE GRPC_HOMEBREW_PATH 59 | RESULT_VARIABLE GRPC_HOMEBREW_RETURN_CODE 60 | OUTPUT_STRIP_TRAILING_WHITESPACE) 61 | execute_process(COMMAND ${HOMEBREW} --prefix protobuf 62 | OUTPUT_VARIABLE PROTOBUF_HOMEBREW_PATH 63 | RESULT_VARIABLE PROTOBUF_HOMEBREW_RETURN_CODE 64 | OUTPUT_STRIP_TRAILING_WHITESPACE) 65 | execute_process(COMMAND ${HOMEBREW} --prefix abseil 66 | OUTPUT_VARIABLE ABSL_HOMEBREW_PATH 67 | RESULT_VARIABLE ABSL_HOMEBREW_RETURN_CODE 68 | OUTPUT_STRIP_TRAILING_WHITESPACE) 69 | # If either library is not installed via Homebrew, fall back to the 70 | # system path. 71 | if (GRPC_HOMEBREW_RETURN_CODE EQUAL "0") 72 | list(APPEND GRPC_INCLUDE_PATHS ${GRPC_HOMEBREW_PATH}/include) 73 | list(APPEND GRPC_OPTS PATHS ${GRPC_HOMEBREW_PATH}/lib NO_DEFAULT_PATH) 74 | endif() 75 | if (PROTOBUF_HOMEBREW_RETURN_CODE EQUAL "0") 76 | list(APPEND GRPC_INCLUDE_PATHS ${PROTOBUF_HOMEBREW_PATH}/include) 77 | list(APPEND PROTOBUF_OPTS PATHS ${PROTOBUF_HOMEBREW_PATH}/lib NO_DEFAULT_PATH) 78 | endif() 79 | if (ABSL_HOMEBREW_RETURN_CODE EQUAL "0") 80 | list(APPEND GRPC_INCLUDE_PATHS ${ABSL_HOMEBREW_PATH}/include) 81 | endif() 82 | endif() 83 | endif() 84 | if(NOT TARGET grpc++) 85 | find_library(GRPC_LIBRARY grpc++ ${GRPC_OPTS} REQUIRED) 86 | add_library(grpc++ UNKNOWN IMPORTED GLOBAL) 87 | message(STATUS "Using grpc++: " ${GRPC_LIBRARY}) 88 | set_target_properties(grpc++ PROPERTIES IMPORTED_LOCATION ${GRPC_LIBRARY}) 89 | target_include_directories(grpc++ INTERFACE ${GRPC_INCLUDE_PATHS}) 90 | if (ENABLE_GRPC_REFLECTION) 91 | find_library(GRPC_REFLECTION_LIBRARY grpc++_reflection ${GRPC_OPTS} REQUIRED) 92 | add_library(grpc++_reflection UNKNOWN IMPORTED GLOBAL) 93 | set_target_properties(grpc++_reflection PROPERTIES IMPORTED_LOCATION ${GRPC_REFLECTION_LIBRARY}) 94 | endif() 95 | find_library(PROTOBUF_LIBRARY protobuf ${PROTOBUF_OPTS} REQUIRED) 96 | message(STATUS "Using protobuf: " ${PROTOBUF_LIBRARY}) 97 | add_library(protobuf UNKNOWN IMPORTED GLOBAL) 98 | set_target_properties(protobuf PROPERTIES IMPORTED_LOCATION ${PROTOBUF_LIBRARY}) 99 | endif() 100 | endif() 101 | 102 | if (ENABLE_GRPC_REFLECTION) 103 | set(REFLECTION_LIBRARY grpc++_reflection) 104 | endif() 105 | 106 | # Proto headers are generated in ${CMAKE_CURRENT_BINARY_DIR}. 107 | # Libraries that use these headers should adjust the include path. 108 | # If the "GRPC" argument is given, services are also generated. 109 | # The DEPENDS list should name *.proto source files that are imported. 110 | # They may be relative to the source dir or absolute (for generated protos). 111 | function(generate_proto_sources GeneratedSource ProtoFile) 112 | cmake_parse_arguments(PARSE_ARGV 2 PROTO "GRPC" "" "DEPENDS") 113 | get_filename_component(ProtoSourceAbsolutePath "${CMAKE_CURRENT_SOURCE_DIR}/${ProtoFile}" ABSOLUTE) 114 | get_filename_component(ProtoSourcePath ${ProtoSourceAbsolutePath} PATH) 115 | get_filename_component(Basename ${ProtoSourceAbsolutePath} NAME_WLE) 116 | 117 | set(GeneratedProtoSource "${CMAKE_CURRENT_BINARY_DIR}/${Basename}.pb.cc") 118 | set(GeneratedProtoHeader "${CMAKE_CURRENT_BINARY_DIR}/${Basename}.pb.h") 119 | set(Flags 120 | --cpp_out="${CMAKE_CURRENT_BINARY_DIR}" 121 | --proto_path="${ProtoSourcePath}") 122 | if (PROTO_GRPC) 123 | list(APPEND Flags 124 | --grpc_out="${CMAKE_CURRENT_BINARY_DIR}" 125 | --plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN}") 126 | list(APPEND GeneratedProtoSource "${CMAKE_CURRENT_BINARY_DIR}/${Basename}.grpc.pb.cc") 127 | list(APPEND GeneratedProtoHeader "${CMAKE_CURRENT_BINARY_DIR}/${Basename}.grpc.pb.h") 128 | endif() 129 | add_custom_command( 130 | OUTPUT ${GeneratedProtoSource} ${GeneratedProtoHeader} 131 | COMMAND ${PROTOC} 132 | ARGS ${Flags} "${ProtoSourceAbsolutePath}" 133 | DEPENDS "${ProtoSourceAbsolutePath}") 134 | 135 | set(${GeneratedSource} ${GeneratedProtoSource} PARENT_SCOPE) 136 | 137 | # Ensure dependency headers are generated before dependent protos are built. 138 | # DEPENDS arg is a list of "Foo.proto". While they're logically relative to 139 | # the source dir, the generated headers we need are in the binary dir. 140 | foreach(ImportedProto IN LISTS PROTO_DEPENDS) 141 | # Foo.proto -> Foo.pb.h 142 | STRING(REGEX REPLACE "\\.proto$" ".pb.h" ImportedHeader "${ImportedProto}") 143 | # Foo.pb.h -> ${CMAKE_CURRENT_BINARY_DIR}/Foo.pb.h 144 | get_filename_component(ImportedHeader "${ImportedHeader}" 145 | ABSOLUTE 146 | BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") 147 | # Compilation of each generated source depends on ${BINARY}/Foo.pb.h. 148 | foreach(Generated IN LISTS GeneratedProtoSource) 149 | # FIXME: CMake docs suggest OBJECT_DEPENDS isn't needed, but I can't get 150 | # the recommended add_dependencies() approach to work. 151 | set_source_files_properties("${Generated}" 152 | PROPERTIES OBJECT_DEPENDS "${ImportedHeader}") 153 | endforeach(Generated) 154 | endforeach(ImportedProto) 155 | endfunction() 156 | -------------------------------------------------------------------------------- /unittests/test-hypertable.c: -------------------------------------------------------------------------------- 1 | #include "test-hypertable-common.h" 2 | 3 | void test0(void) { 4 | // Basic test case 5 | table_command test[] = { 6 | {TABLE_INSERT, 0x1}, 7 | {TABLE_INSERT, 0x2}, 8 | {TABLE_INSERT, 0x3}, 9 | {TABLE_INSERT, 0x4}, 10 | {TABLE_INSERT, 0x5}, 11 | {TABLE_INSERT, 0x6}, 12 | {TABLE_INSERT, 0x7}, 13 | {TABLE_INSERT, 0x8}, 14 | {TABLE_INSERT, 0x9}, 15 | {TABLE_INSERT, 0xa}, 16 | {TABLE_INSERT, 0xb}, 17 | {TABLE_INSERT, 0xc}, 18 | {TABLE_INSERT, 0xd}, 19 | {TABLE_INSERT, 0xe}, 20 | {TABLE_INSERT, 0xf}, 21 | 22 | {TABLE_DELETE, 0x1}, 23 | {TABLE_INSERT, 0x1}, 24 | 25 | {TABLE_DELETE, 0x1}, 26 | {TABLE_DELETE, 0x2}, 27 | {TABLE_DELETE, 0x3}, 28 | {TABLE_DELETE, 0x4}, 29 | {TABLE_DELETE, 0x5}, 30 | {TABLE_DELETE, 0x6}, 31 | {TABLE_DELETE, 0x7}, 32 | {TABLE_DELETE, 0x8}, 33 | {TABLE_DELETE, 0x9}, 34 | {TABLE_DELETE, 0xa}, 35 | {TABLE_DELETE, 0xb}, 36 | {TABLE_DELETE, 0xc}, 37 | {TABLE_DELETE, 0xd}, 38 | {TABLE_DELETE, 0xe}, 39 | {TABLE_DELETE, 0xf}, 40 | }; 41 | test_insert_remove(test, sizeof(test)/sizeof(table_command)); 42 | } 43 | 44 | void test1(void) { 45 | // Test WP+NR and WP+WR inserts 46 | table_command test[] = { 47 | {TABLE_INSERT, 0x4}, 48 | {TABLE_INSERT, 0x1}, 49 | {TABLE_INSERT, 0x2}, 50 | {TABLE_INSERT, 0x3}, 51 | {TABLE_INSERT, 0x5}, 52 | 53 | {TABLE_INSERT, 0x6}, 54 | {TABLE_DELETE, 0x2}, 55 | {TABLE_INSERT, 0x7}, 56 | {TABLE_DELETE, 0x3}, 57 | {TABLE_INSERT, 0x8}, 58 | {TABLE_DELETE, 0x1}, 59 | {TABLE_DELETE, 0x8}, 60 | 61 | {TABLE_INSERT, 0x15}, // NP+NR insert, move 0x7 to wrap 62 | {TABLE_INSERT, 0x25}, // NP+NR insert, move 0x6 to wrap 63 | 64 | {TABLE_INSERT, 0x2}, // Direct insert into empty slot 65 | {TABLE_DELETE, 0x2}, // Tombstone left behind 66 | {TABLE_INSERT, 0x3}, // Direct insert into empty slot 67 | {TABLE_DELETE, 0x3}, // Tombstone left behind 68 | 69 | {TABLE_DELETE, 0x7}, // Tombstone left behind 70 | {TABLE_INSERT, 0x7}, // Insert wraps, stops in WP+NR case 71 | 72 | {TABLE_DELETE, 0x6}, // Create tombstone after wrap 73 | {TABLE_INSERT, 0x8}, // WP+WR insert, must be inserted after 0x7 74 | 75 | {TABLE_LOOKUP, 0x7}, 76 | {TABLE_LOOKUP, 0x8}, 77 | }; 78 | test_insert_remove(test, sizeof(test)/sizeof(table_command)); 79 | } 80 | 81 | void test2(void) { 82 | // Test NS+WR and WP+WR inserts 83 | table_command test[] = { 84 | {TABLE_INSERT, 0x4}, 85 | {TABLE_INSERT, 0x1}, 86 | {TABLE_INSERT, 0x2}, 87 | {TABLE_INSERT, 0x3}, 88 | {TABLE_INSERT, 0x5}, 89 | 90 | {TABLE_INSERT, 0x6}, 91 | {TABLE_DELETE, 0x2}, 92 | {TABLE_INSERT, 0x7}, 93 | {TABLE_DELETE, 0x3}, 94 | {TABLE_INSERT, 0x8}, 95 | {TABLE_DELETE, 0x1}, 96 | {TABLE_DELETE, 0x8}, 97 | 98 | {TABLE_INSERT, 0x15}, // NP+NR insert, move 0x7 to wrap 99 | {TABLE_INSERT, 0x25}, // NP+NR insert, move 0x6 to wrap 100 | {TABLE_DELETE, 0x15}, 101 | {TABLE_DELETE, 0x25}, 102 | 103 | {TABLE_INSERT, 0x1}, // NP+WR insert, must be inserted after 0x7 104 | {TABLE_LOOKUP, 0x1}, 105 | 106 | {TABLE_DELETE, 0x7}, 107 | {TABLE_INSERT, 0x3}, 108 | {TABLE_DELETE, 0x6}, 109 | {TABLE_INSERT, 0x7}, // NP+NR insert, searching wrapped tombstones 110 | 111 | {TABLE_LOOKUP, 0x7}, 112 | }; 113 | test_insert_remove(test, sizeof(test)/sizeof(table_command)); 114 | } 115 | 116 | void test3(void) { 117 | // WP+WR search, wrapping around whole table 118 | table_command test[] = { 119 | {TABLE_INSERT, 0x5}, 120 | {TABLE_INSERT, 0x15}, 121 | {TABLE_INSERT, 0x25}, 122 | {TABLE_INSERT, 0x35}, 123 | {TABLE_INSERT, 0x45}, 124 | 125 | {TABLE_INSERT, 0x6}, 126 | {TABLE_INSERT, 0x16}, 127 | {TABLE_INSERT, 0x26}, 128 | 129 | {TABLE_DELETE, 0x15}, 130 | {TABLE_LOOKUP, 0x26}, 131 | 132 | {TABLE_INSERT, 0x37}, // Scans ~whole table to insert 133 | 134 | {TABLE_LOOKUP, 0x5}, 135 | {TABLE_LOOKUP, 0x25}, 136 | {TABLE_LOOKUP, 0x35}, 137 | {TABLE_LOOKUP, 0x45}, 138 | {TABLE_LOOKUP, 0x6}, 139 | {TABLE_LOOKUP, 0x16}, 140 | {TABLE_LOOKUP, 0x26}, 141 | {TABLE_LOOKUP, 0x37}, 142 | }; 143 | test_insert_remove(test, sizeof(test)/sizeof(table_command)); 144 | } 145 | 146 | void test4(void) { 147 | // WP+WR search, wrapping around whole table 148 | table_command test[] = { 149 | {TABLE_INSERT, 0x5}, 150 | {TABLE_INSERT, 0x15}, 151 | {TABLE_INSERT, 0x25}, 152 | {TABLE_INSERT, 0x35}, 153 | {TABLE_INSERT, 0x45}, 154 | {TABLE_INSERT, 0x55}, 155 | {TABLE_INSERT, 0x65}, 156 | {TABLE_INSERT, 0x75}, 157 | 158 | {TABLE_DELETE, 0x15}, 159 | 160 | {TABLE_INSERT, 0x7}, // Scans whole table to insert at index 5 161 | {TABLE_LOOKUP, 0x35}, 162 | {TABLE_LOOKUP, 0x7}, 163 | 164 | {TABLE_DELETE, 0x7}, 165 | {TABLE_LOOKUP, 0x35}, 166 | {TABLE_DELETE, 0x5}, 167 | 168 | {TABLE_INSERT, 0x7}, // Scans ~whole table to insert 169 | {TABLE_INSERT, 0x17}, // Trigger table rebuild 170 | 171 | {TABLE_DELETE, 0x7}, 172 | {TABLE_DELETE, 0x17}, 173 | 174 | {TABLE_INSERT, 0x5}, 175 | {TABLE_LOOKUP, 0x5}, 176 | {TABLE_DELETE, 0x65}, 177 | {TABLE_DELETE, 0x75}, 178 | {TABLE_DELETE, 0x35}, 179 | 180 | {TABLE_INSERT, 0x7}, // Scans whole table to insert after hash = 5 run 181 | 182 | {TABLE_LOOKUP, 0x7}, 183 | {TABLE_LOOKUP, 0x5}, 184 | {TABLE_LOOKUP, 0x25}, 185 | {TABLE_LOOKUP, 0x45}, 186 | {TABLE_LOOKUP, 0x55}, 187 | }; 188 | test_insert_remove(test, sizeof(test)/sizeof(table_command)); 189 | } 190 | 191 | void test5(void) { 192 | // WP+WR and NP+NR tests, wrapping around whole table with min elements. 193 | // Test inserting into into the middle of a run of tombstones, where insert 194 | // scan would wrap around the whole table. 195 | table_command test[] = { 196 | {TABLE_INSERT, 0x8}, 197 | {TABLE_INSERT, 0x18}, 198 | {TABLE_INSERT, 0x28}, 199 | {TABLE_INSERT, 0x38}, 200 | {TABLE_INSERT, 0x7}, 201 | {TABLE_INSERT, 0x17}, 202 | {TABLE_INSERT, 0x27}, 203 | {TABLE_INSERT, 0x37}, 204 | 205 | {TABLE_DELETE, 0x37}, 206 | {TABLE_DELETE, 0x27}, 207 | {TABLE_DELETE, 0x17}, 208 | {TABLE_DELETE, 0x7}, 209 | 210 | // NP+NR insert in middle of tombstones, where all other elements have 211 | // smaller hashes. Must insert after hash = 8 run. 212 | {TABLE_INSERT, 0x1}, 213 | 214 | {TABLE_LOOKUP, 0x1}, 215 | {TABLE_LOOKUP, 0x8}, 216 | {TABLE_LOOKUP, 0x18}, 217 | {TABLE_LOOKUP, 0x28}, 218 | {TABLE_LOOKUP, 0x38}, 219 | }; 220 | test_insert_remove(test, sizeof(test)/sizeof(table_command)); 221 | } 222 | 223 | int main(int argc, char *argv[]) { 224 | int to_run = -1; 225 | if (argc > 1) 226 | to_run = atoi(argv[1]); 227 | 228 | if (to_run < 0 || to_run == 0) { 229 | test0(); 230 | printf("test0 PASSED\n"); 231 | } 232 | if (to_run < 0 || to_run == 1) { 233 | test1(); 234 | printf("test1 PASSED\n"); 235 | } 236 | if (to_run < 0 || to_run == 2) { 237 | test2(); 238 | printf("test2 PASSED\n"); 239 | } 240 | if (to_run < 0 || to_run == 3) { 241 | test3(); 242 | printf("test3 PASSED\n"); 243 | } 244 | if (to_run < 0 || to_run == 4) { 245 | test4(); 246 | printf("test4 PASSED\n"); 247 | } 248 | if (to_run < 0 || to_run == 5) { 249 | test5(); 250 | printf("test5 PASSED\n"); 251 | } 252 | return 0; 253 | } 254 | --------------------------------------------------------------------------------