diff --git a/MatrixCPP/CMakeLists.txt b/MatrixCPP/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a80dc10e74bdc98f22ace799979f8a7fde5ce1c --- /dev/null +++ b/MatrixCPP/CMakeLists.txt @@ -0,0 +1,104 @@ +cmake_minimum_required(VERSION 3.12) +project(MatrixCPP VERSION 1.0.0 LANGUAGES CXX) +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) + +# Override default install directories to use build directory +set(MATRIXCPP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(MATRIXCPP_BINARY_DIR ${MATRIXCPP_SOURCE_DIR}/build) +set(CMAKE_SKIP_RPATH TRUE) +add_compile_options(-fstack-protector-strong) +add_compile_options(-D_FORTIFY_SOURCE=2 -O2) +add_compile_options(-ftrapv) +add_link_options(-s) + +# Basic configuration +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fno-omit-frame-pointer -fPIC -D_GLIBCXX_USE_CXX11_ABI=0") + +# Check for required environment variables +if(NOT DEFINED RAY_CPP_PATH) + message(FATAL_ERROR "RAY_CPP_PATH not set. Please input by -DRAY_CPP_PATH=/path/to/ray") +endif() +get_filename_component(RAY_API_LIB_PATH "${RAY_CPP_PATH}/lib/libray_api.so" ABSOLUTE) +get_filename_component(RAY_INCLUDE_PATH "${RAY_CPP_PATH}/include" ABSOLUTE) + +# Import pre-built ray_api library +add_library(ray_api SHARED IMPORTED GLOBAL) +set_target_properties(ray_api PROPERTIES + IMPORTED_LOCATION "${RAY_API_LIB_PATH}" + INTERFACE_INCLUDE_DIRECTORIES "${RAY_INCLUDE_PATH}" + IMPORTED_NO_SONAME TRUE +) + +# Main MatrixCPP library configuration +file(GLOB MatrixCPP_SRC "runtime/*.cpp") + +add_library(MatrixCPP SHARED ${MatrixCPP_SRC}) +target_include_directories(MatrixCPP PUBLIC + $ + $ + $ + ${RAY_INCLUDE_PATH} +) +target_link_libraries(MatrixCPP PUBLIC + ray_api + pthread +) +target_link_options(MatrixCPP PRIVATE + "-Wl,-z,relro,-z,now" + "-Wl,--disable-new-dtags" +) + +export(TARGETS MatrixCPP + NAMESPACE MatrixCPP:: + FILE "${MATRIXCPP_BINARY_DIR}/MatrixCPPTargets.cmake" +) + +# Create config file template +set(CONFIG_TEMPLATE "${MATRIXCPP_BINARY_DIR}/MatrixCPPConfig.cmake.in") +file(WRITE "${CONFIG_TEMPLATE}" [=[ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +# Find dependencies +find_dependency(Threads REQUIRED) + +# Re-import ray_api (if not already defined by user) +if(NOT TARGET ray_api) + set(RAY_API_LIB_PATH "@RAY_API_LIB_PATH@") + set(RAY_INCLUDE_PATH "@RAY_INCLUDE_PATH@") + + add_library(ray_api SHARED IMPORTED) + set_target_properties(ray_api PROPERTIES + IMPORTED_LOCATION "${RAY_API_LIB_PATH}" + INTERFACE_INCLUDE_DIRECTORIES "${RAY_INCLUDE_PATH}" + IMPORTED_NO_SONAME TRUE + ) +endif() + +# Include the targets file +include("${CMAKE_CURRENT_LIST_DIR}/MatrixCPPTargets.cmake") + +# Set variables for users +set(MatrixCPP_INCLUDE_DIRS "@MATRIXCPP_SOURCE_DIR@/include" "@RAY_INCLUDE_PATH@") +set(MatrixCPP_LIBRARIES MatrixCPP::MatrixCPP) + +check_required_components(MatrixCPP) +]=]) + +# Generate and install package config files +configure_package_config_file( + "${CONFIG_TEMPLATE}" + "${MATRIXCPP_BINARY_DIR}/MatrixCPPConfig.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MatrixCPP + PATH_VARS RAY_API_LIB_PATH RAY_INCLUDE_PATH MATRIXCPP_SOURCE_DIR +) + +write_basic_package_version_file( + "${MATRIXCPP_BINARY_DIR}/MatrixCPPConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion +) diff --git a/MatrixCPP/CODE_OWNERS.TXT b/MatrixCPP/CODE_OWNERS.TXT new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MatrixCPP/LICENSE.TXT b/MatrixCPP/LICENSE.TXT new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MatrixCPP/README.md b/MatrixCPP/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b94452009b32f1ab0b3ad249ce11529cd8ba0bb2 --- /dev/null +++ b/MatrixCPP/README.md @@ -0,0 +1,27 @@ +# MatrixCPP + +1. Matrix C++ offers native support for distributed concurrent programming: + The native supernode programming model builds upon ISO C++'s inherent +concurrency capabilities, enhancing supernode-level concurrency and +heterogeneous computing. It delivers a seamless development experience where +code written for a single machine can run directly on supernodes, eliminating +the need for third-party libraries or frameworks to achieve distributed +concurrency. This approach significantly improves programming efficiency and +cross-platform portability. + +2. Required before building: Install Ray using the recommended command: + pip install -U ray[cpp]== 2.34.0 + +3. Building method: + Add the -M option when building the LLVM command. + +4. To build the MatrixCPP library from source: + mkdir build && cd build + cmake -DRAY_CPP_PATH=path/to/ray .. + make -j + +5. For projects that depend on MatrixCPP, refer to the test directory for +compilation examples: + cd test + cmake -DMATRIXCPP_SOURCE_PATH=/path/to/MatrixCPP .. + make -j$(nproc) \ No newline at end of file diff --git a/MatrixCPP/cmake/.gitkeep b/MatrixCPP/cmake/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MatrixCPP/docs/.gitkeep b/MatrixCPP/docs/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MatrixCPP/examples/.gitkeep b/MatrixCPP/examples/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MatrixCPP/include/MatrixCPP.h b/MatrixCPP/include/MatrixCPP.h new file mode 100644 index 0000000000000000000000000000000000000000..f74cf4e8a87ea1f6ba619da7e653e5b826faa8d0 --- /dev/null +++ b/MatrixCPP/include/MatrixCPP.h @@ -0,0 +1,28 @@ +//===--- MatrixCPP.h - MatrixCPP Framework Main Header ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file MatrixCPP.h + * @brief Unified header for MatrixCPP parallel computing framework + */ + +#ifndef MATRIXCPP_H +#define MATRIXCPP_H + +#include "async.h" +#include "future.h" +#include "new.h" +#include "startup_shutdown.h" +#include "wait_all.h" +#include "wait_any.h" +#include "wait_some.h" + +#endif // MATRIXCPP_H \ No newline at end of file diff --git a/MatrixCPP/include/async.h b/MatrixCPP/include/async.h new file mode 100644 index 0000000000000000000000000000000000000000..ee5d008007288bf2cfdb299b3734d598cd9909cf --- /dev/null +++ b/MatrixCPP/include/async.h @@ -0,0 +1,119 @@ +//===---------- async.h - Provides a async interface. -*- C++ -*-----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file async.h + * @brief async implementation for distributed computing + * + * Provides async functions + * - The async function can be used to schedule a task to a specific node by + * specifying the name and value of the target node + * - The async function can also automatically schedule a function to a node + */ + +#ifndef BISHENG_ASYNC_H +#define BISHENG_ASYNC_H + +#include "future.h" +#include "remote_launch.h" +#include "type_traits.h" + +#define BISHENG_REMOTE BISHENG_REMOTE_LAUNCH +namespace bisheng { + +// assign a task to a specific node using its name and value +template < + typename F, typename... Args, + typename Enable = std::enable_if_t>> +auto async(F f, std::string name, double value, Args... args) { + return bisheng::future( + std::move(bisheng::remoteLaunchAsync(f, name, value, args...))); +} + +template < + typename F, typename... Args, + typename Enable = std::enable_if_t>> +auto async(F f, const char *name, double value, Args... args) { + return bisheng::future(std::move( + bisheng::remoteLaunchAsync(f, std::string(name), value, args...))); +} + +template >> +auto async(std::string name, double value, Args... args) { + return bisheng::future( + std::move(bisheng::remoteLaunchAsync(name, value, args...))); +} + +template >> +auto async(const char *name, double value, Args... args) { + return bisheng::future(std::move( + bisheng::remoteLaunchAsync(std::string(name), value, args...))); +} + +template && + std::is_invocable_v &, Args...>>> +auto async(F func, std::string name, double value, id_type &id, + Args &&...args) { + return bisheng::future( + bisheng::remoteLaunchAsync(func, name, value, id, args...)); +} + +template && + std::is_invocable_v< + decltype(F), class_of_mfunction_t &, Args...>>> +auto async(std::string name, double value, id_type &id, Args &&...args) { + return bisheng::future( + bisheng::remoteLaunchAsync(name, value, id, args...)); +} + +// automatically assign a task to a node +template < + typename F, typename... Args, + typename Enable = std::enable_if_t>> +auto async(F f, Args... args) { + return bisheng::future(std::move(bisheng::remoteLaunchAsync(f, args...))); +} + +template >> +auto async(Args... args) { + return bisheng::future(std::move(bisheng::remoteLaunchAsync(args...))); +} + +template && + std::is_invocable_v &, Args...>>> +auto async(F func, id_type &id, Args &&...args) { + return bisheng::future(bisheng::remoteLaunchAsync(func, id, args...)); +} + +template && + std::is_invocable_v< + decltype(F), class_of_mfunction_t &, Args...>>> +auto async(id_type &id, Args &&...args) { + return bisheng::future(bisheng::remoteLaunchAsync(id, args...)); +} + +} // namespace bisheng + +#endif // BISHENG_ASYNC_H \ No newline at end of file diff --git a/MatrixCPP/include/future.h b/MatrixCPP/include/future.h new file mode 100644 index 0000000000000000000000000000000000000000..128093859aa957807597739d2be2b904125c3694 --- /dev/null +++ b/MatrixCPP/include/future.h @@ -0,0 +1,87 @@ +//===-------- future.h - Provides a future interface. -*- C++ -*-----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file future.h + * @brief Thread-safe future implementation for distributed computing + * + * Provides a templated future implementation for distributed computing + * - Type-safe asynchronous value retrieval + * - Dual-mode error handling (exceptions/error codes) + * - Full STL compatibility + * - Move-only semantics for thread safety + * + * @note This is a move-only type that guarantees thread safety in distributed + * environments + * @warning External code should use the public future interface instead + */ + +#ifndef BISHENG_FUTURE_H +#define BISHENG_FUTURE_H + +#include "internal_future.h" +#include +#include +#include + +namespace bisheng { + +template class future { +public: + using result_type = T; + + future() = default; + explicit future(bisheng::InternalFuture impl) noexcept + : impl_(std::move(impl)) {} + + // Move semantics + future(future &&) noexcept = default; + future &operator=(future &&) noexcept = default; + + // Deleted copy operations + future(const future &) = delete; + future &operator=(const future &) = delete; + + // Primary interface + result_type get() const { return impl_.get(); } + result_type get(std::error_code &ec) const noexcept { return impl_.get(ec); } + + // Compatibility interface (returns shared_ptr) + std::shared_ptr getPtr() const { + if (!impl_) { + throw std::runtime_error("Accessing invalid future"); + } + return impl_.getPtr(); + } + + void wait() const { impl_.wait(); } + + template + future_status wait_until( + const std::chrono::time_point &timeout_time) const { + return impl_.wait_until(timeout_time); + } + + template + future_status + wait_for(const std::chrono::duration &timeout_duration) const { + return impl_.wait_for(timeout_duration); + } + + // Validity check + explicit operator bool() const noexcept { return static_cast(impl_); } + +private: + InternalFuture impl_; +}; +} // namespace bisheng + +#endif // BISHENG_FUTURE_H \ No newline at end of file diff --git a/MatrixCPP/include/new.h b/MatrixCPP/include/new.h new file mode 100644 index 0000000000000000000000000000000000000000..40fb43202a3e8a99a9b5528e88269a7d4be584f1 --- /dev/null +++ b/MatrixCPP/include/new.h @@ -0,0 +1,40 @@ +//===- new.h - Provides a component new interface. --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file new.h + * @brief Create new instances of the given Component type on the current or + * specified locality + * @note These functions requires to specify an explicit function on how to + * create the component + */ + +#ifndef BISHENG_NEW_H +#define BISHENG_NEW_H + +#include "internal_future.h" +#include "create.h" +#include + +namespace bisheng { + +template +id_type createNew(F func, Args &&...args) { + return createComponent(func, args...); +} + +template +id_type createNew(std::string node, double value, F func, Args &&...args) { + return createComponent(node, value, func, args...); +} +} // namespace bisheng + +#endif // BISHENG_NEW_H \ No newline at end of file diff --git a/MatrixCPP/include/startup_shutdown.h b/MatrixCPP/include/startup_shutdown.h new file mode 100644 index 0000000000000000000000000000000000000000..a94a1e39f6c7abb3154017592048a2a99cd23a5d --- /dev/null +++ b/MatrixCPP/include/startup_shutdown.h @@ -0,0 +1,50 @@ +//===- startup_shutdown.h - Provides a init/shutdown interface.-*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file startup_shutdown.h + * @brief User-facing interface for runtime lifecycle management + * + * Provides simplified access to initialization/shutdown operations + */ + +#ifndef BISHENG_STARTUP_SHUTDOWN_H +#define BISHENG_STARTUP_SHUTDOWN_H + +#include "init_shutdown.h" +#include +#include + +namespace bisheng { + +class StartupShutdown { +public: + // init + static void Init() { InitShutdown::Init(); } + + // shutdown + static void Shutdown() noexcept { InitShutdown::Shutdown(); } + + class ScopedInstance { + public: + ScopedInstance() { Init(); } + ~ScopedInstance() { Shutdown(); } + + ScopedInstance(const ScopedInstance &) = delete; + ScopedInstance &operator=(const ScopedInstance &) = delete; + }; + +private: + StartupShutdown() = delete; +}; +} // namespace bisheng + +#endif // BISHENG_STARTUP_SHUTDOWN_H \ No newline at end of file diff --git a/MatrixCPP/include/wait_all.h b/MatrixCPP/include/wait_all.h new file mode 100644 index 0000000000000000000000000000000000000000..a96d7397383b7ee3d50ad713805ebec39884eb90 --- /dev/null +++ b/MatrixCPP/include/wait_all.h @@ -0,0 +1,66 @@ +//===- wait_all.h - Provides a wait_all interface. --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file wait_all.h + * @brief Bulk asynchronous synchronization primitive + * Provides concurrent waiting for multiple future objects + * @note Input futures are consumed and become invalid after call + * All futures must be move-constructible and share executor context + */ + +#ifndef BISHENG_WAIT_ALL_H +#define BISHENG_WAIT_ALL_H + +#include "future.h" +#include "type_traits.h" + +#include +#include + +namespace bisheng { + + template + void wait_all(std::vector> const &values) { + for (auto &f :values) { + f.wait(); + } + } + + template + inline void wait_all(std::vector> &values) { + wait_all(const_cast> const &>(values)); + } + + template + inline void wait_all(std::vector> &&values) { + wait_all(const_cast> const &>(values)); + } + + template >> + void wait_all(Iter begin, Iter end) { + for (Iter p = begin; p != end; p++) { + p->wait(); + } + } + + inline constexpr void wait_all() { return; } + + template + void wait_all(future &f, Ts &&...ts) { + f.wait(); + wait_all(ts...); + } + +} // namespace bisheng + +#endif // BISHENG_WAIT_ALL_H \ No newline at end of file diff --git a/MatrixCPP/include/wait_any.h b/MatrixCPP/include/wait_any.h new file mode 100644 index 0000000000000000000000000000000000000000..bcbf6fba2efaef30f689f91704f479f4504fcf17 --- /dev/null +++ b/MatrixCPP/include/wait_any.h @@ -0,0 +1,61 @@ +//===- wait_any.h - Provides a wait_any interface. --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file wait_any.h + * @brief First-result asynchronous selector + * Provides non-blocking race detection for multiple features with immediate + * return on first available result + * @note Returns immediately if any input is already satisfied + * Uncompleted futures remain valid and must be handled separately + */ + +#ifndef BISHENG_WAIT_ANY_H +#define BISHENG_WAIT_ANY_H + +#include "wait_some.h" + +#include +#include + +namespace bisheng { + + template + void wait_any(std::vector> const &values) { + wait_some(1, values); + } + + template + inline void wait_any(std::vector> &values) { + wait_any(const_cast> const &>(values)); + } + + template + inline void wait_any(std::vector> &&values) { + wait_any(const_cast> const &>(values)); + } + + template >> + void wait_any(Iter begin, Iter end) { + wait_some(1, begin, end); + } + + inline void wait_any() { wait_some(0); } + + template + inline void wait_any(Ts &&...ts) { + wait_some(1, std::forward(ts)...); + } + +} // namespace bisheng + +#endif // BISHENG_WAIT_ANY_H \ No newline at end of file diff --git a/MatrixCPP/include/wait_some.h b/MatrixCPP/include/wait_some.h new file mode 100644 index 0000000000000000000000000000000000000000..df16eb5442279fc668506a12b364a87547a0cabe --- /dev/null +++ b/MatrixCPP/include/wait_some.h @@ -0,0 +1,103 @@ +//===- wait_some.h - Provides a wait_some interface. ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file wait_some.h + * @brief Partial completion synchronization + * Provides waiting for a specified subset of futures to complete + * @note Returns when at least the requested number of futures are ready + */ + +#ifndef BISHENG_WAIT_SOME_H +#define BISHENG_WAIT_SOME_H + +#include "future.h" +#include "type_traits.h" + +#include +#include + +namespace bisheng { + + template + void wait_some(std::size_t n, std::vector> const &values) { + std::size_t size = values.size(); + std::size_t wait_num = std::min(n, size); + + std::vector removed_futures(size); + std::size_t count = 0; + do { + for (std::size_t i = 0; i < size; i++) { + auto &f = values[i]; + if (!removed_futures[i] && + f.wait_for(std::chrono::seconds(0)) == future_status::ready) { + count++; + removed_futures[i] = true; + } + } + } while (count < wait_num); + } + + template + inline void wait_some(std::size_t n, std::vector> &values) { + wait_some(n, const_cast> const &>(values)); + } + + template + inline void wait_some(std::size_t n, std::vector> &&values) { + return wait_some(n, const_cast> const &>(values)); + } + + template >> + void wait_some(std::size_t n, Iter begin, Iter end) { + if (begin == end) { + return; + } + + std::size_t count; + do { + count = 0; + for (Iter p = begin; p != end; p++) { + if (p->wait_for(std::chrono::seconds(0)) == future_status::ready) { + count++; + } + } + } while (count < n); + } + + void wait_some(std::size_t n) { return; } + + template + void wait_some(std::size_t n, future &f, Ts &&...ts) { + if (n == 0) { + return; + } + + std::size_t count; + + auto wait = [&](future &f) { + if (f.wait_for(std::chrono::seconds(0)) == future_status::ready) { + count++; + } + }; + + do { + count = 0; + wait(f); + + (wait(ts), ...); + } while (count < n); + } + +} // namespace bisheng + +#endif // BISHENG_WAIT_SOME_H \ No newline at end of file diff --git a/MatrixCPP/lib/.gitkeep b/MatrixCPP/lib/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MatrixCPP/runtime/create.h b/MatrixCPP/runtime/create.h new file mode 100644 index 0000000000000000000000000000000000000000..20bdffd6846b567387558ff38d13b8a22b94cc70 --- /dev/null +++ b/MatrixCPP/runtime/create.h @@ -0,0 +1,53 @@ +//===- create.h - Provides a component create interface. --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file create.h + * @brief Create new instances of the given Component type on the current or + * specified locality + * @note These functions require specifying an explicit funtion on how to create + * the component + */ + +#ifndef BISHENG_CREATE_H +#define BISHENG_CREATE_H + +#include "internal_future.h" +#include +#include + +namespace bisheng { + +template +id_type createComponent(F func, Args &&...args) { + static_assert(std::is_same_v>, + "Component type should be same with Function return type!"); + + ray::ActorHandle actor = + ray::Actor(func).Remote(std::forward(args)...); + return actor.ID(); +} + +template +id_type createComponent(std::string node, double value, F func, + Args &&...args) { + static_assert(std::is_same_v>, + "Component type should be same with Function return type!"); + + ray::ActorHandle actor = ray::Actor(func) + .SetResource(node, value) + .Remote(std::forward(args)...); + return actor.ID(); +} + +} // namespace bisheng + +#endif // BISHENG_CREATE_H \ No newline at end of file diff --git a/MatrixCPP/runtime/init_shutdown.cpp b/MatrixCPP/runtime/init_shutdown.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0287ccd473ba5869833d528138ebfb4d88d65309 --- /dev/null +++ b/MatrixCPP/runtime/init_shutdown.cpp @@ -0,0 +1,31 @@ +//===---init_shutdown.cpp - Provides a init/shutdown interface.-*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#include "init_shutdown.h" + +namespace bisheng { + +void InitShutdown::Init() { + static std::once_flag init_flag; + std::call_once(init_flag, [] { + ray::Init(); + if (!ray::IsInitialized()) { + throw std::runtime_error("Init failed"); + } + }); +} + +void InitShutdown::Shutdown() noexcept { + static std::once_flag shutdown_flag; + std::call_once(shutdown_flag, [] { ray::Shutdown(); }); +} + +} // namespace bisheng \ No newline at end of file diff --git a/MatrixCPP/runtime/init_shutdown.h b/MatrixCPP/runtime/init_shutdown.h new file mode 100644 index 0000000000000000000000000000000000000000..c3c5acda12ae2bae6cbec3075076a23f733ff896 --- /dev/null +++ b/MatrixCPP/runtime/init_shutdown.h @@ -0,0 +1,45 @@ +//===--- init_shutdown.h - Provides a init/shutdown interface -*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file init_shutdown.h + * @brief Thread-safe wrapper for runtime initialization and shutdown + * + * Provides one-time initialization and cleanup of the runtime environment. + * Ensures proper resource management in distributed computing scenarios. + */ + +#ifndef BISHENG_INIT_SHUTDOWN_H +#define BISHENG_INIT_SHUTDOWN_H + +#include +#include +#include + +namespace bisheng { + +class InitShutdown { +public: + // init + static void Init(); + + // shutdown + static void Shutdown() noexcept; + + // Prohibit instantiation + InitShutdown() = delete; + InitShutdown(const InitShutdown &) = delete; + InitShutdown &operator=(const InitShutdown &) = delete; +}; + +} // namespace bisheng + +#endif // BISHENG_INIT_SHUTDOWN_H \ No newline at end of file diff --git a/MatrixCPP/runtime/internal_future.h b/MatrixCPP/runtime/internal_future.h new file mode 100644 index 0000000000000000000000000000000000000000..05438c1e30d0e0c5365a9630c9cf500258eebc24 --- /dev/null +++ b/MatrixCPP/runtime/internal_future.h @@ -0,0 +1,160 @@ +//===--- InternalFuture.h - Low-level future abstraction. -*- C++ -*------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file InternalFuture.h + * @brief Core abstraction layer for future implementation + * + * Implements fundamental operations with: + * - Mutex-protected value access + * - Dual-mode error reporting + * - Strict ownership transfer semantics + * + * @warning Internal implementation component - External dependencies are + * strictly prohibited + */ + +#ifndef BISHENG_INTERNAL_FUTURE_H +#define BISHENG_INTERNAL_FUTURE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace bisheng { + +enum class future_status { + ready, + timeout, + deferred, +}; + +template class InternalFuture { +public: + InternalFuture() = default; + + explicit InternalFuture(ray::ObjectRef ref) : ref_(std::move(ref)) {} + + // Move semantics (defaulted for optimal performance) + InternalFuture(InternalFuture &&other) noexcept = default; + InternalFuture &operator=(InternalFuture &&other) noexcept = default; + + // Deleted copy operations (non-copyable by design) + InternalFuture(const InternalFuture &) = delete; + InternalFuture &operator=(const InternalFuture &) = delete; + + // Primary value accessor (throws on error) + T get() const { + if (!IsValid()) { + throw std::runtime_error("Accessing invalid Future"); + } + + try { + auto ptr = ray::Get(ref_); + if (!ptr) { + throw std::runtime_error("Failed to get value from ObjectRef"); + } + return *ptr; + } catch (const ray::internal::RayTaskException &e) { + throw std::runtime_error(e.what()); + } + } + + // Error-code version of value accessor (noexcept) + T get(std::error_code &ec) const noexcept { + ec.clear(); + if (!IsValid()) { + ec = std::make_error_code(std::errc::invalid_argument); + return T{}; + } + + try { + auto ptr = ray::Get(ref_); + if (!ptr) { + ec = std::make_error_code(std::errc::operation_not_permitted); + return T{}; + } + return *ptr; + } catch (...) { + ec = std::make_error_code(std::errc::operation_not_permitted); + return T{}; + } + } + + // Error-code version of pointer accessor (noexcept) + std::shared_ptr getPtr() const { + if (!IsValid()) { + throw std::runtime_error("Invalid internal Future"); + } + + try { + auto ptr = ray::Get(ref_); + if (!ptr) { + throw std::runtime_error("Failed to get value from ObjectRef"); + } + return ptr; + } catch (const ray::internal::RayTaskException &e) { + throw std::runtime_error(e.what()); + } + } + + void wait() const { + std::vector> objects = {ref_}; + ray::Wait(objects, 1, -1); + } + + template + future_status wait_until( + const std::chrono::time_point &timeout_time) const { + std::vector> objects = {ref_}; + auto result = + ray::Wait(objects, 1, + std::chrono::duration_cast( + timeout_time - std::chrono::system_clock::now()) + .count()); + if (result.ready.size() == 1) { + return future_status::ready; + } else { + return future_status::timeout; + } + + assert(0 && "bisheng::wait_until should not reach here!"); + } + + template + future_status + wait_for(const std::chrono::duration &timeout_duration) const { + return wait_until(std::chrono::system_clock::now() + timeout_duration); + } + + explicit operator bool() const noexcept { return IsValid(); } + + // Access underlying ObjectRef + const ray::ObjectRef &GetObjectRef() const noexcept { return ref_; } + +private: + // Internal validity check + bool IsValid() const noexcept { return !ref_.ID().empty(); } + + // Underlying Ray object reference + ray::ObjectRef ref_; +}; + +using id_type = std::string; + +} // namespace bisheng + +#endif // BISHENG_INTERNAL_FUTURE_H diff --git a/MatrixCPP/runtime/remote_launch.h b/MatrixCPP/runtime/remote_launch.h new file mode 100644 index 0000000000000000000000000000000000000000..f673e9d721322316bdcd76a02d8b4e41b2615ce4 --- /dev/null +++ b/MatrixCPP/runtime/remote_launch.h @@ -0,0 +1,100 @@ +//===--- remote_launch.h - Provides a remote launch interface. -*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file remote_launch.h + * @brief Core abstraction layer for asynchronous execution + * + * Provides remote_launch functions + * - The remote_launch function can be used to schedule a task to a specific + * node by specifying the name and value of the target node + * - The remote_launch function can also automatically schedule a function to + * a node when the node is not specified + */ + +#ifndef BISHENG_REMOTE_LAUNCH_H +#define BISHENG_REMOTE_LAUNCH_H + +#include "internal_future.h" +#include "type_traits.h" +#include +#include + +#define BISHENG_REMOTE_LAUNCH RAY_REMOTE + +namespace bisheng { + +// assign a task to a specific node using its name and value +template +auto remoteLaunchAsync(F f, std::string name, double value, Args... args) { + return bisheng::InternalFuture( + std::move(ray::Task(f).SetResource(name, value).Remote(args...))); +} + +template +auto remoteLaunchAsync(std::string name, double value, Args... args) { + return bisheng::InternalFuture( + std::move(ray::Task(F).SetResource(name, value).Remote(args...))); +} + +// automatically assign a task to a node +template +auto remoteLaunchAsync(F f, Args... args) { + return bisheng::InternalFuture(std::move(ray::Task(f).Remote(args...))); +} + +template auto remoteLaunchAsync(Args... args) { + return bisheng::InternalFuture(std::move(ray::Task(F).Remote(args...))); +} + +template +auto remoteLaunchAsync(F func, id_type& id, Args &&...args) { + using ClassType = class_of_mfunction_t; + + ray::ActorHandle actor(id); + return bisheng::InternalFuture( + actor.Task(func).Remote(std::forward(args)...)); +} + +template +auto remoteLaunchAsync(id_type &id, Args &&...args) { + using ClassType = class_of_mfunction_t; + + ray::ActorHandle actor(id); + return bisheng::InternalFuture( + actor.Task(F).Remote(std::forward(args)...)); +} + +template +auto remoteLaunchAsync(F func, std::string name, double value, id_type &id, + Args &&...args) { + using ClassType = class_of_mfunction_t; + + ray::ActorHandle actor(id); + return bisheng::InternalFuture(actor.Task(func) + .SetResource(name, value) + .Remote(std::forward(args)...)); +} + +template +auto remoteLaunchAsync(std::string name, double value, id_type &id, + Args &&...args) { + using ClassType = class_of_mfunction_t; + + ray::ActorHandle actor(id); + return bisheng::InternalFuture(actor.Task(F) + .SetResource(name, value) + .Remote(std::forward(args)...)); +} + +} // namespace bisheng + +#endif // BISHENG_REMOTE_LAUNCH_H diff --git a/MatrixCPP/runtime/type_traits.h b/MatrixCPP/runtime/type_traits.h new file mode 100644 index 0000000000000000000000000000000000000000..510aaccce65418915bd3b72ce6709a95036ab13d --- /dev/null +++ b/MatrixCPP/runtime/type_traits.h @@ -0,0 +1,72 @@ +//===- type_traits.h - Provides a traits interface. -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file type_traits.h + * @brief Compile-time type introspection utilities + * + * Provides template-based type metaprogramming facilities with: + * - Type categorization (integral, floating-point, pointer, etc.) + * - Type transformation traits (add/remove const, pointer, reference) + * - Type relationship checks (is_same, is_base_of, is_convertible) + * - Compile-time constant extraction (true_type/false_type) + * - Full C++ standard library compatibility + * @note All operations are evaluated at compile-time with zero runtime overhead + */ + +#ifndef BISHENG_TYPE_TRAITS_H +#define BISHENG_TYPE_TRAITS_H + +#include +#include +#include + +namespace bisheng { + +template +struct is_iterator : std::false_type {}; + +template +struct is_iterator< + T, std::void_t::iterator_category>> + : std::true_type {}; + +template +inline constexpr bool is_iterator_v = is_iterator::value; + +template struct class_of_mfunction {}; + +template +struct class_of_mfunction { + using type = Class; +}; + +template +struct class_of_mfunction { + using type = Class; +}; + +template +struct class_of_mfunction { + using type = Class; +}; + +template +struct class_of_mfunction { + using type = Class; +}; + +template +using class_of_mfunction_t = typename class_of_mfunction::type; + +} // namespace bisheng + +#endif // BISHENG_TYPE_TRAITS_H \ No newline at end of file diff --git a/MatrixCPP/test/CMakeLists.txt b/MatrixCPP/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8db81d3e9c9e921f5c9a4c498c2e295ae375e856 --- /dev/null +++ b/MatrixCPP/test/CMakeLists.txt @@ -0,0 +1,63 @@ +# Minimum CMake version requirement +cmake_minimum_required(VERSION 3.12) + +# Project definition +project(example) + +# Basic compiler settings +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fno-omit-frame-pointer -fPIC -D_GLIBCXX_USE_CXX11_ABI=0") + +# Find MatrixCPP package +if(NOT DEFINED MATRIXCPP_SOURCE_PATH) + message(FATAL_ERROR "MATRIXCPP_SOURCE_PATH not set. Please input by -DMATRIXCPP_SOURCE_PATH=/path/to/MatrixCPP") +endif() +set(MatrixCPP_DIR "${MATRIXCPP_SOURCE_PATH}/build") +find_package(MatrixCPP 1.0 REQUIRED) + +file(GLOB SOURCE_FILES "*.cpp") + +# Create executables and shared libraries for each source file +foreach(SRC_FILE ${SOURCE_FILES}) + # Get base name without extension + get_filename_component(TARGET_BASE ${SRC_FILE} NAME_WE) + + # set target dir + set(TEST_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_BASE}") + + # Define executable target + add_executable(${TARGET_BASE} ${SRC_FILE}) + target_include_directories(${TARGET_BASE} PRIVATE ${MatrixCPP_INCLUDE_DIRS}) + target_link_libraries(${TARGET_BASE} PRIVATE + MatrixCPP::MatrixCPP + ) + target_link_options(${TARGET_BASE} PRIVATE + "-Wl,--no-as-needed" + ) + + set_target_properties(${TARGET_BASE} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${TEST_OUTPUT_DIR} + ) + + # Define shared library target + add_library(${TARGET_BASE}_shared SHARED ${SRC_FILE}) + target_include_directories(${TARGET_BASE}_shared PRIVATE ${MatrixCPP_INCLUDE_DIRS}) + target_link_libraries(${TARGET_BASE}_shared PRIVATE + MatrixCPP::MatrixCPP + ) + set_target_properties(${TARGET_BASE}_shared PROPERTIES + OUTPUT_NAME "${TARGET_BASE}" + POSITION_INDEPENDENT_CODE ON + ) + target_link_options(${TARGET_BASE}_shared PRIVATE + "-Wl,-rpath,\$ORIGIN" + ) + + set_target_properties(${TARGET_BASE}_shared PROPERTIES + OUTPUT_NAME "${TARGET_BASE}" + LIBRARY_OUTPUT_DIRECTORY ${TEST_OUTPUT_DIR} + ARCHIVE_OUTPUT_DIRECTORY ${TEST_OUTPUT_DIR} + POSITION_INDEPENDENT_CODE ON + ) +endforeach() \ No newline at end of file diff --git a/MatrixCPP/test/test_all.sh b/MatrixCPP/test/test_all.sh new file mode 100644 index 0000000000000000000000000000000000000000..d45fadda6feec52b6bd332ee33cfd08314cdff0f --- /dev/null +++ b/MatrixCPP/test/test_all.sh @@ -0,0 +1,106 @@ +set -e +set -o pipefail + +LOG_FILE="./bisheng_test.log" +ADDR_FILE="./ray_addr.txt" + +echo ">>> Stopping any running Ray cluster..." +ray stop --force > "$LOG_FILE" 2>&1 || true + +echo ">>> Starting Ray head node..." +ray start --head --resources='{"node0": 1}' >> "$LOG_FILE" 2>&1 + +#(qeual --address='IP:PORT') +RAY_ADDR=$(grep -oP "(?<=--address=')\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+" "$LOG_FILE" | tail -n 1 || true) + +if [ -z "$RAY_ADDR" ]; then + echo "Failed to extract RAY address from log:" + cat "$LOG_FILE" + exit 1 +fi + +# export environment +export RAY_ADDRESS=$RAY_ADDR +echo ">>> Using RAY_ADDRESS=$RAY_ADDRESS" + + +# test component +echo ">>> Running test component..." +set +e +OUTPUT=$(./build/test_component/test_component 2>&1) +STATUS=$? +set -e + +echo "$OUTPUT" >> "$LOG_FILE" + +if [ $STATUS -ne 0 ]; then + echo "Test program exited with code $STATUS" + echo "---- Output ----" + echo "$OUTPUT" + echo "----------------" + ray stop --force >> "$LOG_FILE" 2>&1 || true + exit 1 +fi + +if echo "$OUTPUT" | grep -q "test_result_4 = 12"; then + echo "test_component test pass" +else + echo "---- test_component output ----" + echo "$OUTPUT" + echo "--------------------------------" + echo "test_component test failed" +fi + +# test future +echo ">>> Running test_future..." +set +e +OUTPUT2=$(./build/test_future/test_future 2>&1) +STATUS2=$? +set -e +echo "$OUTPUT2" >> "$LOG_FILE" + +if [ $STATUS2 -eq 0 ] && echo "$OUTPUT2" | grep -q "Completed 100/100 tasks"; then + echo "test_future passed" +else + echo "---- test_future output ----" + echo "$OUTPUT2" + echo "--------------------------------" + echo "test_future failed" +fi + +# test async +echo ">>> Running test_async..." +set +e +OUTPUT3=$(./build/test_async/test_async 2>&1) +STATUS3=$? +set -e +echo "$OUTPUT3" >> "$LOG_FILE" + +if [ $STATUS3 -eq 0 ] && echo "$OUTPUT3" | grep -q "196"; then + echo "test_async passed" +else + echo "---- test_async output ----" + echo "$OUTPUT3" + echo "--------------------------------" + echo "test_async failed" +fi + +# test wait +echo ">>> Running test_wait..." +set +e +OUTPUT4=$(./build/test_wait/test_wait 2>&1) +STATUS4=$? +set -e +echo "$OUTPUT4" >> "$LOG_FILE" + +if [ $STATUS4 -eq 0 ] && echo "$OUTPUT4" | grep -q "wait some elapsed"; then + echo "test_wait passed" +else + echo "---- test_wait output ----" + echo "$OUTPUT4" + echo "--------------------------------" + echo "test_wait failed" +fi + +echo ">>> All Test Done, Stopping Ray..." +ray stop --force >> "$LOG_FILE" 2>&1 \ No newline at end of file diff --git a/MatrixCPP/test/test_async.cpp b/MatrixCPP/test/test_async.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3d5e302cb2e48adc0418d33c697e1b0acd707ae --- /dev/null +++ b/MatrixCPP/test/test_async.cpp @@ -0,0 +1,63 @@ +//===- test_async.cpp - Comprehensive tests for the async implementation. -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file test_async.cpp + * @brief Comprehensive test suite for bisheng::async and bisheng::async_auto + * implementation + * + * This test file verifies all core functionality of the asynchronous functions: + * - Manual scheduling using async function with name and value of a node + * - Automatic scheduling using async_auto + */ + +#include +#include +#include +#include + +int Myfunc(int x) { return x * x; } + +BISHENG_REMOTE(Myfunc); + +int main() { + bisheng::StartupShutdown::Init(); + + std::vector> futures; + int num_tasks = 5; + // assign tasks automatically with the runtime scheduling policy + for (int i = 1; i < num_tasks; i++) { + futures.push_back(bisheng::async(Myfunc, i)); + futures.push_back(bisheng::async(i)); + } + + for (auto &future : futures) { + std::cout << future.get() << std::endl; + } + + // schedule tasks to a node with name "node0" and value 1.0 + std::string node = "node0"; + double value = 1.0; + bisheng::future res0 = bisheng::async(node, value, 13); + std::cout << (res0.get()) << std::endl; + + bisheng::future res1 = bisheng::async(Myfunc, node, value, 14); + std::cout << (res1.get()) << std::endl; + + bisheng::future res2 = bisheng::async("node0", 1.0, 13); + std::cout << (res2.get()) << std::endl; + + bisheng::future res3 = bisheng::async(Myfunc, "node0", 1.0, 14); + std::cout << (res3.get()) << std::endl; + + bisheng::StartupShutdown::Shutdown(); + return 0; +} diff --git a/MatrixCPP/test/test_component.cpp b/MatrixCPP/test/test_component.cpp new file mode 100644 index 0000000000000000000000000000000000000000..933ebc0c6ce5e392c56d8f189cc4c6ba925420d2 --- /dev/null +++ b/MatrixCPP/test/test_component.cpp @@ -0,0 +1,68 @@ +//===-- test_component.cpp - Tests for the component implementation. ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file test_component.cpp + * @brief Comprehensive test suite for component api. + */ + +#include +#include +#include +#include + +/// class +class TestComponent { +public: + int count; + + explicit TestComponent(int init) : count(init) {} + /// static factory method + static TestComponent *FactoryCreate(int init) { + return new TestComponent(init); + } + + /// non static function + int Add(int x) { + count += x; + return count; + } +}; + +/// Declare remote function +BISHENG_REMOTE(TestComponent::FactoryCreate, &TestComponent::Add); + +int main(int argc, char **argv) { + /// initialization + bisheng::StartupShutdown::Init(); + + bisheng::id_type id = + bisheng::createNew(TestComponent::FactoryCreate, 0); + + bisheng::future f1 = bisheng::async(&TestComponent::Add, id, 3); + bisheng::future f2 = bisheng::async<&TestComponent::Add>(id, 3); + bisheng::future f3 = + bisheng::async(&TestComponent::Add, "node0", 1, id, 3); + bisheng::future f4 = + bisheng::async<&TestComponent::Add>("node0", 1, id, 3); + int res = f1.get(); + std::cout << "test_result_1 = " << res << std::endl; + res = f2.get(); + std::cout << "test_result_2 = " << res << std::endl; + res = f3.get(); + std::cout << "test_result_3 = " << res << std::endl; + res = f4.get(); + std::cout << "test_result_4 = " << res << std::endl; + + /// shutdown + bisheng::StartupShutdown::Shutdown(); + return 0; +} diff --git a/MatrixCPP/test/test_future.cpp b/MatrixCPP/test/test_future.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aab12c6cd7703b9c4cadb804f0eb7c60ef0ae164 --- /dev/null +++ b/MatrixCPP/test/test_future.cpp @@ -0,0 +1,204 @@ +//==- test_future.cpp - Comprehensive tests for the future implementation. -==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file test_future.cpp + * @brief Comprehensive test suite for bisheng::future + * + * This test file verifies all core functionality of the distributed future + * pattern: + * - Basic value retrieval + * - Exception handling + * - Performance characteristics + * @note Requires Ray cluster initialization + */ + +#include +#include +#include +#include + + +// 1. Define simple remote functions +int SimpleCompute(int x) { return x + x; } + +int ComputeWithException() { + throw std::runtime_error("Intentional exception for testing"); + return 0; +} + +// 2. Register remote functions +BISHENG_REMOTE(SimpleCompute); +BISHENG_REMOTE(ComputeWithException); + +void TestBasicFunctionality() { + std::cout << "=== Testing Basic Functionality ===" << std::endl; + + // Test construction and validity + bisheng::future empty_fut; + std::cout << "Empty future is " << (empty_fut ? "valid ✘" : "invalid ✔") + << std::endl; + int test_ans = 20; + + // Submit remote task + bisheng::future fut = bisheng::async(SimpleCompute, 10); + + // Test validity + std::cout << "Initialized future is " << (fut ? "valid ✔" : "invalid ✘") + << std::endl; + + // Retrieve result with both methods + try { + // Standard get + int result = fut.get(); + std::cout << "Got result (get): " << result + << (result == test_ans ? " ✔" : " ✘") << std::endl; + + // Error-code version + std::error_code ec; + int result_ec = fut.get(ec); + if (!ec) { + std::cout << "Got result (get with ec): " << result_ec + << (result_ec == test_ans ? " ✔" : " ✘") << std::endl; + } + + // Shared pointer version + auto ptr = fut.getPtr(); + std::cout << "Got result (ptr): " << *ptr + << (*ptr == test_ans ? " ✔" : " ✘") << std::endl; + } catch (const std::exception &e) { + std::cerr << "Unexpected error : " << e.what() << std::endl; + } +} + +void TestExceptionHandling() { + std::cout << "\n=== Testing Exception Handling ===" << std::endl; + + // Test standard get() with exception + { + bisheng::future fut = bisheng::async(ComputeWithException); + + try { + int result = fut.get(); + std::cerr << "get() Unexpected success, got: " << result << " ✘" + << std::endl; + } catch (const std::runtime_error &e) { + std::cout << "get() Caught expected exception: " << e.what() << " ✔" + << std::endl; + } catch (...) { + std::cerr << "get() Caught unexpected exception type ✘" << std::endl; + } + } + + // Test error_code version + { + bisheng::future fut = bisheng::async(ComputeWithException); + + std::error_code ec; + int val = fut.get(ec); + if (ec) { + std::cout << "get(ec) Caught error via error_code: " + << (ec == std::errc::operation_not_permitted ? "Expected ✔" + : "Unexpected ✘") + << " | " << ec.message() << std::endl; + } else { + std::cerr << "get(ec) Failed to catch exception via error_code ✘" + << std::endl; + } + } + + // Test pointer version + { + bisheng::future fut = bisheng::async(ComputeWithException); + + try { + auto ptr = fut.getPtr(); + std::cerr << "getPtr() Unexpected success, returned: " + << (ptr ? std::to_string(*ptr) : "nullptr") << " ✘" + << std::endl; + } catch (const std::runtime_error &e) { + std::cout << "getPtr() Caught expected exception: " << e.what() << " ✔" + << std::endl; + } catch (...) { + std::cerr << "getPtr() Caught unexpected exception type ✘" << std::endl; + } + } +} + +void TestPerformance(int num_tasks = 100) { + std::cout << "\n=== Testing Performance (" << num_tasks + << " tasks ) === " << std::endl; + + std::vector> futures; + futures.reserve(num_tasks); + + auto start = std::chrono::steady_clock::now(); + + // Submit batch + for (int i = 0; i < num_tasks; ++i) { + futures.emplace_back(bisheng::async(SimpleCompute, i)); + } + + // Validate + int success_count = 0; + for (auto &fut : futures) { + std::error_code ec; + int val = fut.get(ec); + if (!ec && val == (success_count + success_count)) { + ++success_count; + } + } + + auto end = std::chrono::steady_clock::now(); + auto duration = + std::chrono::duration_cast(end - start); + + std::cout << "Completed " << success_count << "/" << num_tasks << " tasks in " + << duration.count() << "ms" << std::endl; +} + +int main() { + bisheng::StartupShutdown::Init(); + + TestBasicFunctionality(); + TestExceptionHandling(); + TestPerformance(); + + bisheng::StartupShutdown::Shutdown(); + return 0; +} + +/* +Expected output of test cases + +=== Testing Basic Functionality === +Empty future is invalid ✔ +Initialized future is valid ✔ +Got result (get): 20 ✔ +Got result (get with ec): 20 ✔ +Got result (ptr): 20 ✔ + +=== Testing Exception Handling === +get() Caught expected exception: Invalid: An exception was thrown while +executing function(ComputeWithException): + std::runtime_error: Intentional exception for testing ✔ + +get(ec) Caught error via error_code: + Expected ✔ | Operation not permitted + +getPtr() Caught expected exception: Invalid: An exception was thrown while +executing function(ComputeWithException): + std::runtime_error: Intentional exception for testing ✔ + +=== Testing Performence (100 tasks) === +Completed 100/100 tasks in 167ms + +*/ diff --git a/MatrixCPP/test/test_wait.cpp b/MatrixCPP/test/test_wait.cpp new file mode 100644 index 0000000000000000000000000000000000000000..447fb4a8f8ab8638bbbd90eeaf4aa97f8d624b0a --- /dev/null +++ b/MatrixCPP/test/test_wait.cpp @@ -0,0 +1,170 @@ +//===-- test_wait.cpp - Comprehensive tests for the wait implementation. --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/** + * @file test_wait.cpp + * @brief Comprehensive test suite for bisheng::wait wait_all and wait_some/any + * implementation This test file verifies all core functionality of the + * distributed future pattern: + * - Basic value retrieval + * @note Requires Ray cluster initialization + */ + +#include + +#include +#include +#include +#include + +constexpr int milliseconds1000 = 1000; +constexpr int seconds1 = 1; +constexpr int seconds2 = 2; +constexpr int seconds3 = 3; + +int ready_future_after(int n) { + std::this_thread::sleep_for(std::chrono::seconds(n)); + return n; +} + +BISHENG_REMOTE(ready_future_after); + +void TestWait() { + auto start = std::chrono::high_resolution_clock::now(); + + bisheng::future f_wait = bisheng::async(ready_future_after, seconds2); + f_wait.wait(); + + auto end = std::chrono::high_resolution_clock::now(); + + std::chrono::duration elapsed = end - start; + std::cout << "ready future after " << f_wait.get() << std::endl; + std::cout << "wait elapsed time " << (elapsed.count() / milliseconds1000) + << " s" << std::endl; +} + +void TestWaitUntil() { + bisheng::future f_wait_until = + bisheng::async(ready_future_after, seconds2); + auto after_1_second = + std::chrono::system_clock::now() + std::chrono::seconds(seconds1); + auto after_3_second = + std::chrono::system_clock::now() + std::chrono::seconds(seconds3); + auto status_until_1 = f_wait_until.wait_until(after_1_second); + auto status_until_3 = f_wait_until.wait_until(after_3_second); + + std::cout << "wait until after 1 status " << int(status_until_1) + << " after 3 status " << int(status_until_3) << std::endl; +} + +void TestWaitFor() { + bisheng::future f_wait_for = + bisheng::async(ready_future_after, seconds2); + auto status_for_1 = f_wait_for.wait_for(std::chrono::seconds(seconds1)); + auto status_for_3 = f_wait_for.wait_for(std::chrono::seconds(seconds3)); + std::cout << "wait for after 1 status " << int(status_for_1) + << " after 3 status " << int(status_for_3) << std::endl; +} + +void TestWaitAll(int n) { + std::vector> fs; + auto start = std::chrono::high_resolution_clock::now(); + + for (int i = 1; i <= n; i++) { + fs.push_back(bisheng::async(ready_future_after, i)); + } + wait_all(fs); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + std::cout << "wait all elapsed time " << (elapsed.count() / milliseconds1000) + << " s" << std::endl; +} + +void TestWaitAllIter(int n) { + std::vector> fs; + auto start = std::chrono::high_resolution_clock::now(); + + for (int i = 1; i <= n; i++) { + fs.push_back(bisheng::async(ready_future_after, i)); + } + wait_all(fs.begin(), fs.end()); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + std::cout << "wait all elapsed time " << (elapsed.count() / milliseconds1000) + << " s" << std::endl; +} + +void TestWaitAllVA(int n) { + std::vector> fs; + auto start = std::chrono::high_resolution_clock::now(); + + for (int i = 1; i <= n; i++) { + fs.push_back(bisheng::async(ready_future_after, i)); + } + wait_all(fs[0], fs[n - 1]); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + std::cout << "wait all elapsed time " << (elapsed.count() / milliseconds1000) + << " s" << std::endl; +} + +void TestWaitAny(int n) { + std::vector> fs; + auto start = std::chrono::high_resolution_clock::now(); + + for (int i = 1; i <= n; i++) { + fs.push_back(bisheng::async(ready_future_after, i)); + } + wait_any(fs); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + std::cout << "wait any elapsed time " << (elapsed.count() / milliseconds1000) + << " s" << std::endl; +} + +void TestWaitSome(int n) { + std::vector> fs; + auto start = std::chrono::high_resolution_clock::now(); + + for (int i = 1; i <= n; i++) { + fs.push_back(bisheng::async(ready_future_after, i)); + } + wait_some(1, fs); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + std::cout << "wait some elapsed time " << (elapsed.count() / milliseconds1000) + << " s" << std::endl; +} + +int main(int argc, char **argv) { + /// initialization + bisheng::StartupShutdown::Init(); + + TestWait(); + TestWaitUntil(); + TestWaitFor(); + + int n_futures = 10; + TestWaitAll(n_futures); + TestWaitAllIter(n_futures); + TestWaitAllVA(n_futures); + TestWaitAny(n_futures); + TestWaitSome(n_futures); + + /// shutdown + bisheng::StartupShutdown::Shutdown(); + return 0; +} diff --git a/MatrixCPP/tools/.gitkeep b/MatrixCPP/tools/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MatrixCPP/unittests/.gitkeep b/MatrixCPP/unittests/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/MatrixCPP/utils/.gitkeep b/MatrixCPP/utils/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/build.sh b/build.sh index 88b5fbfca365505d814f33e5277cc1aba0455681..c9c98866d9aa13ed87f813a390bc3361ce41d16f 100755 --- a/build.sh +++ b/build.sh @@ -16,6 +16,7 @@ embedded_toolchain="0" split_dwarf=on use_ccache="0" enable_classic_flang="0" +enable_matrix_cpp="0" do_install="0" clean=0 containerize=0 @@ -68,6 +69,7 @@ Options: -I name Specify install directory name (default: "$install_dir_name"). -d dir Specify the build directory (default: "$build_dir_name"). -j N Allow N jobs at once (default: $threads). + -M Enable MatrixCPP -o Enable LLVM_INSTALL_TOOLCHAIN_ONLY=ON. -O Do not build BOLT(binary optimization tool). -r Delete $install_prefix and perform a clean build (default: incremental). @@ -82,7 +84,7 @@ EOF # Process command-line options. Remember the options for passing to the # containerized build script. containerized_opts=() -while getopts :aAb:cCd:D:eEhiI:j:oOrstvfX: optchr; do +while getopts :aAb:cCd:D:eEhiI:j:MoOrstvfX: optchr; do case "$optchr" in a) enable_autotuner="0" @@ -170,6 +172,9 @@ while getopts :aAb:cCd:D:eEhiI:j:oOrstvfX: optchr; do threads="$OPTARG" containerized_opts+=(-$optchr "$OPTARG") ;; + M) + enable_matrix_cpp="1" + ;; o) install_toolchain_only=1 containerized_opts+=(-$optchr) @@ -368,6 +373,26 @@ if [ $embedded_toolchain == "1" ]; then -DLLVM_BUILD_FOR_EMBEDDED=ON" fi +# MatrixCPP +if [ $enable_matrix_cpp == "1" ]; then + if [ -z "$RAY_DIR" ]; then + echo "$0: RAY_DIR not set, please export RAY_DIR=path/to/ray" + echo "$RAY_DIR" + exit 1 + fi + if [ -d "$RAY_DIR/thirdparty" ]; then + echo "enable MatrixCPP build (thirdparty)" + RAY_CPP_PATH="$RAY_DIR/thirdparty" + elif [ -d "$RAY_DIR/cpp" ]; then + echo "enable MatrixCPP build (cpp)" + RAY_CPP_PATH="$RAY_DIR/cpp" + else + echo "$0: wrong ray path!No cpp/thirdparty in your RAY_DIR, please check your RAY_DIR:$RAY_DIR" + exit 1 + fi + CMAKE_OPTIONS="$CMAKE_OPTIONS -DLLVM_ENABLE_MATRIXCPP=ON -DRAY_CPP_PATH="$RAY_CPP_PATH"" +fi + # When set LLVM_INSTALL_TOOLCHAIN_ONLY to On it removes many of the LLVM development # and testing tools as well as component libraries from the default install target. if [ $install_toolchain_only == "1" ]; then @@ -397,10 +422,10 @@ if [ $enable_bolt == "1" ]; then #There is internal error when linking with gold while compiling BOLT. unset llvm_use_linker enabled_projects+=";bolt" - EXE_LINKER_FLAGS="-Wl,--compress-debug-sections=zlib" + EXE_LINKER_FLAGS="-Wl,--compress-debug-sections=zlib" else llvm_use_linker="-DLLVM_USE_LINKER=gold" - EXE_LINKER_FLAGS="-Wl,--gdb-index -Wl,--compress-debug-sections=zlib" + EXE_LINKER_FLAGS="-Wl,--gdb-index -Wl,--compress-debug-sections=zlib" fi # Build and install diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index 687a9a6892118e6e7bba0b501a7c18b48fcbacb6..bd785e1e44f5da189b4116e68ebbde5696efbc4e 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -1339,3 +1339,8 @@ endif() if (LLVM_INCLUDE_UTILS AND LLVM_INCLUDE_TOOLS) add_subdirectory(utils/llvm-locstats) endif() + +# MatrixCPP +if(LLVM_ENABLE_MATRIXCPP) + add_subdirectory(../MatrixCPP ../MatrixCPP/build/) +endif()