Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions bindings/c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,24 @@ target_include_directories(${TARGET_NAME}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src
)

find_package(OpenMP REQUIRED)
# PRIVATE: OpenMP is an implementation detail linked into the shared library.
# Exporting it would force consumers of the C ABI to resolve a C++ OpenMP
# target they never asked for.
target_link_libraries(${TARGET_NAME} PRIVATE OpenMP::OpenMP_CXX)
# Set default visibility to hidden for all symbols in the shared library.
target_compile_options(${TARGET_NAME} PRIVATE -fvisibility=hidden)
Comment thread
rfsaliev marked this conversation as resolved.

target_compile_options(${TARGET_NAME} PRIVATE
-DSVS_ENABLE_OMP=1
-fvisibility=hidden
)
if(NOT DEFINED SVS_ENABLE_OMP)
option(SVS_ENABLE_OMP
"Enable OpenMP threadpool support for parallelism." ON)
endif()

if(SVS_ENABLE_OMP)
find_package(OpenMP REQUIRED)
if (OpenMP_CXX_FOUND)
# PRIVATE: OpenMP is an implementation detail linked into the shared library.
# Exporting it would force consumers of the C ABI to resolve a C++ OpenMP
# target they never asked for.
target_link_libraries(${TARGET_NAME} PRIVATE OpenMP::OpenMP_CXX)
target_compile_definitions(${TARGET_NAME} PRIVATE SVS_ENABLE_OMP=1)
endif() # OpenMP_CXX_FOUND
endif() # SVS_ENABLE_OMP

if(UNIX AND NOT APPLE)
# Don't export 3rd-party symbols from the lib
Expand Down
2 changes: 1 addition & 1 deletion bindings/c/docs/C_API_Design.md
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ Controls parallelization strategy for index operations.
| Type | Configuration | Use Case |
|------|---------------|----------|
| **Native** | Thread count | Default SVS thread pool (recommended) |
| **OpenMP** | Uses OMP_NUM_THREADS | Integration with OpenMP applications |
| **OpenMP** | Thread count | Integration with OpenMP applications; requires a build with OpenMP support, otherwise `SVS_ERROR_NOT_IMPLEMENTED` |
| **Single Thread** | No parallelization | Debugging or minimal overhead |
| **Custom** | User-defined interface | Custom scheduling/work-stealing |

Expand Down
14 changes: 11 additions & 3 deletions bindings/c/include/svs/c/svs_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ enum svs_storage_kind {
};

/// @brief Thread pool implementation used for parallel operations.
/// @remarks SVS_THREADPOOL_KIND_OMP is available only if the library was built with
/// OpenMP support; otherwise selecting it fails with SVS_ERROR_NOT_IMPLEMENTED.
enum svs_threadpool_kind {
SVS_THREADPOOL_KIND_NATIVE = 0,
SVS_THREADPOOL_KIND_OMP = 1,
Expand Down Expand Up @@ -1068,6 +1070,11 @@ SVS_API bool svs_index_builder_set_storage(
/// @param num_threads The number of threads to use (if applicable)
/// @param out_err An optional error handle to capture errors
/// @return true on success, false on failure
/// @error On failure, if out_err is provided, it will contain:
/// - SVS_ERROR_INVALID_ARGUMENT if builder is NULL, num_threads is zero, or @p kind is
/// SVS_THREADPOOL_KIND_CUSTOM (use svs_index_builder_set_threadpool_custom() instead)
/// - SVS_ERROR_NOT_IMPLEMENTED if @p kind is SVS_THREADPOOL_KIND_OMP and the library was
/// built without OpenMP support
SVS_API bool svs_index_builder_set_threadpool(
svs_index_builder_h builder,
svs_threadpool_kind_t kind,
Expand Down Expand Up @@ -1658,9 +1665,10 @@ SVS_API bool svs_index_get_num_threads(
/// @param out_err An optional error handle to capture errors
/// @return true on success, false on failure
/// @remarks This function is only supported for indices built with threadpool kinds
/// SVS_THREADPOOL_KIND_NATIVE or SVS_THREADPOOL_KIND_OMP. Attempting to call this
/// function on indices built with SVS_THREADPOOL_KIND_CUSTOM or
/// SVS_THREADPOOL_KIND_SINGLE_THREAD will fail and return false.
/// SVS_THREADPOOL_KIND_NATIVE or SVS_THREADPOOL_KIND_OMP (when built with OpenMP
/// support). Attempting to call this function on indices built with
/// SVS_THREADPOOL_KIND_CUSTOM or SVS_THREADPOOL_KIND_SINGLE_THREAD will fail and return
/// false.
/// @error On failure, if out_err is provided, it will contain:
/// - SVS_ERROR_INVALID_OPERATION if the index's threadpool kind is unresizable
/// - SVS_ERROR_INVALID_ARGUMENT if num_threads is invalid or zero
Expand Down
8 changes: 3 additions & 5 deletions bindings/c/src/svs_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -629,15 +629,13 @@ extern "C" bool svs_index_builder_set_threadpool(
size_t num_threads,
svs_error_h out_err
) {
if (builder == nullptr) {
SET_ERROR(out_err, SVS_ERROR_INVALID_ARGUMENT, "Invalid argument");
return false;
}
using namespace svs::c_runtime;
return wrap_exceptions(
[&]() {
EXPECT_ARG_NOT_NULL(builder);
EXPECT_ARG_GT_THAN(num_threads, 0);
if (kind != SVS_THREADPOOL_KIND_SINGLE_THREAD) {
EXPECT_ARG_GT_THAN(num_threads, 0);
}
builder->impl->set_threadpool_builder({kind, num_threads});
return true;
},
Expand Down
12 changes: 12 additions & 0 deletions bindings/c/src/threadpool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ class ThreadPoolBuilder {
"SVS_THREADPOOL_KIND_CUSTOM cannot be built automatically."
);
}

// Validate that SVS_OMP macro is properly defined.
SVS_VALIDATE_BOOL_ENV(SVS_OMP);

if (!SVS_OMP && kind == SVS_THREADPOOL_KIND_OMP) {
throw svs::c_runtime::not_implemented("OpenMP support is not enabled.");
}
Comment thread
rfsaliev marked this conversation as resolved.
Comment thread
rfsaliev marked this conversation as resolved.
}

ThreadPoolBuilder(svs_threadpool_i pool)
Expand Down Expand Up @@ -158,7 +165,12 @@ class ThreadPoolBuilder {
case SVS_THREADPOOL_KIND_NATIVE:
return ThreadPoolHandle(NativeThreadPool(num_threads));
case SVS_THREADPOOL_KIND_OMP:
#if SVS_OMP
// OMPThreadPool is only available if OpenMP support is enabled.
return ThreadPoolHandle(OMPThreadPool(num_threads));
#else
assert(false && "OpenMP support is not enabled.");
#endif
Comment thread
rfsaliev marked this conversation as resolved.
Comment thread
rfsaliev marked this conversation as resolved.
case SVS_THREADPOOL_KIND_SINGLE_THREAD:
return ThreadPoolHandle(SequentialThreadPool());
case SVS_THREADPOOL_KIND_CUSTOM:
Expand Down
4 changes: 4 additions & 0 deletions bindings/c/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ if(SVS_RUNTIME_ENABLE_LVQ_LEANVEC)
target_compile_definitions(${TARGET_NAME} PRIVATE SVS_TEST_EXPECT_LVQ_LEANVEC)
endif()

if(SVS_ENABLE_OMP)
target_compile_definitions(${TARGET_NAME} PRIVATE SVS_TEST_EXPECT_OPENMP)
endif()

# Set C++ standard
target_compile_features(${TARGET_NAME} PRIVATE cxx_std_20)
set_target_properties(${TARGET_NAME} PROPERTIES
Expand Down
43 changes: 23 additions & 20 deletions bindings/c/tests/c_api_index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,31 +692,34 @@ CATCH_TEST_CASE("C API Threadpool Management", "[c_api][index][threadpool]") {
// Set OMP threadpool
bool success =
svs_index_builder_set_threadpool(builder, SVS_THREADPOOL_KIND_OMP, 3, error);
CATCH_REQUIRE(success);
CATCH_REQUIRE(svs_error_ok(error));
CATCH_REQUIRE(check_openmp_support(success, error));

svs_index_h index = svs_index_build(builder, data.data(), NUM_VECTORS, error);
CATCH_REQUIRE(index != nullptr);
CATCH_REQUIRE(svs_error_ok(error));
// if OMP is not supported the test will skip the following block.
if (success) {
svs_index_h index = svs_index_build(builder, data.data(), NUM_VECTORS, error);
CATCH_REQUIRE(index != nullptr);
CATCH_REQUIRE(svs_error_ok(error));

// Get current number of threads
size_t num_threads = 0;
success = svs_index_get_num_threads(index, &num_threads, error);
CATCH_REQUIRE(success);
CATCH_REQUIRE(svs_error_ok(error));
CATCH_REQUIRE(num_threads == 3);
// Get current number of threads
size_t num_threads = 0;
success = svs_index_get_num_threads(index, &num_threads, error);
CATCH_REQUIRE(success);
CATCH_REQUIRE(svs_error_ok(error));
CATCH_REQUIRE(num_threads == 3);

// Set to different number of threads
success = svs_index_set_num_threads(index, 5, error);
CATCH_REQUIRE(success);
CATCH_REQUIRE(svs_error_ok(error));
// Set to different number of threads
success = svs_index_set_num_threads(index, 5, error);
CATCH_REQUIRE(success);
CATCH_REQUIRE(svs_error_ok(error));

// Verify the change
success = svs_index_get_num_threads(index, &num_threads, error);
CATCH_REQUIRE(success);
CATCH_REQUIRE(num_threads == 5);
// Verify the change
success = svs_index_get_num_threads(index, &num_threads, error);
CATCH_REQUIRE(success);
CATCH_REQUIRE(num_threads == 5);

svs_index_free(index);
}

svs_index_free(index);
svs_index_builder_free(builder);
svs_algorithm_free(algorithm);
svs_error_free(error);
Expand Down
3 changes: 1 addition & 2 deletions bindings/c/tests/c_api_index_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,7 @@ CATCH_TEST_CASE("C API Index Builder", "[c_api][index_builder]") {

bool success =
svs_index_builder_set_threadpool(builder, SVS_THREADPOOL_KIND_OMP, 2, error);
CATCH_REQUIRE(success == true);
CATCH_REQUIRE(svs_error_ok(error) == true);
CATCH_REQUIRE(check_openmp_support(success, error));

svs_index_builder_free(builder);
svs_algorithm_free(algorithm);
Expand Down
11 changes: 11 additions & 0 deletions bindings/c/tests/c_api_test_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,14 @@ inline void* failing_allocator_allocate(
inline void failing_allocator_deallocate(
void* /*self*/, void* /*ptr*/, size_t /*size*/, size_t /*alignment*/
) {}

// If OMP is not implemented, success will be false and the error code will be
// SVS_ERROR_NOT_IMPLEMENTED. Otherwise, success should be true and the error should
// be OK.
Comment thread
rfsaliev marked this conversation as resolved.
inline bool check_openmp_support(bool success, svs_error_h error) {
#ifdef SVS_TEST_EXPECT_OPENMP
return success && svs_error_ok(error);
#else
return !success && svs_error_get_code(error) == SVS_ERROR_NOT_IMPLEMENTED;
#endif
}
5 changes: 5 additions & 0 deletions cmake/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ option(SVS_INITIALIZE_LOGGER
ON # enabled by default
)

option(SVS_ENABLE_OMP
"Enable OpenMP threadpool support for parallelism."
ON # enabled by default
)

#####
##### Experimental
#####
Expand Down
Loading