Skip to content

Commit d85b3ca

Browse files
authored
Allow multiple calls to cudf::initialize and cudf::deinitialize (#20111)
Closes #20022 Allow `cudf::initialize` to incrementally perform initialization steps if called multiple times. Also allow multiple calls to `cudf::deinitialize`. In both cases, redundant calls have no effect. Also adds tests for this utility, since the logic is now non-trivial. Authors: - Vukasin Milovanovic (https://github.com/vuule) Approvers: - Kyle Edwards (https://github.com/KyleFromNVIDIA) - Nghia Truong (https://github.com/ttnghia) - Muhammad Haseeb (https://github.com/mhaseeb123) - Shruti Shivakumar (https://github.com/shrshi) URL: #20111
1 parent 8690c9f commit d85b3ca

File tree

5 files changed

+115
-18
lines changed

5 files changed

+115
-18
lines changed

cpp/include/cudf/context.hpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ namespace CUDF_EXPORT cudf {
2525

2626
/// @brief Flags for controlling initialization steps
2727
enum class init_flags : std::uint32_t {
28+
/// @brief No initialization steps
29+
NONE = 0,
2830
/// @brief Load the nvCOMP library during initialization
2931
LOAD_NVCOMP = 1 << 0,
3032
/// @brief Initialize the JIT program cache during initialization
@@ -43,6 +45,27 @@ constexpr init_flags operator|(init_flags lhs, init_flags rhs) noexcept
4345
return static_cast<init_flags>(static_cast<underlying_t>(lhs) | static_cast<underlying_t>(rhs));
4446
}
4547

48+
/// @brief Bitwise AND operator for init_flags
49+
/// @param lhs The left-hand side of the operator
50+
/// @param rhs The right-hand side of the operator
51+
/// @return The result of the bitwise AND operation
52+
constexpr init_flags operator&(init_flags lhs, init_flags rhs) noexcept
53+
{
54+
using underlying_t = std::underlying_type_t<init_flags>;
55+
return static_cast<init_flags>(static_cast<underlying_t>(lhs) & static_cast<underlying_t>(rhs));
56+
}
57+
58+
/// @brief Bitwise NOT operator for init_flags
59+
/// @param flags The flags to negate
60+
/// @return The result of the bitwise NOT operation, only flipping bits that are part of
61+
/// init_flags::ALL
62+
constexpr init_flags operator~(init_flags flags) noexcept
63+
{
64+
using underlying_t = std::underlying_type_t<init_flags>;
65+
return static_cast<init_flags>(static_cast<underlying_t>(init_flags::ALL) &
66+
~static_cast<underlying_t>(flags));
67+
}
68+
4669
/// @brief Check if a flag is set
4770
/// @param flags The flags to check against
4871
/// @param flag The specific flag to check for
@@ -54,7 +77,8 @@ constexpr bool has_flag(init_flags flags, init_flags flag) noexcept
5477

5578
/// @brief Initialize the cudf global context
5679
/// @param flags Optional flags to control which initialization steps to perform.
57-
/// @throws std::runtime_error if the context is already initialized
80+
/// Can be called multiple times to initialize additional components. If all selected
81+
/// steps are already performed, the call has no effect.
5882
void initialize(init_flags flags = init_flags::INIT_JIT_CACHE);
5983

6084
/// @brief de-initialize the cudf global context

cpp/src/runtime/context.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,13 @@ namespace cudf {
2929

3030
context::context(init_flags flags) : _program_cache{nullptr}
3131
{
32-
if (has_flag(flags, init_flags::INIT_JIT_CACHE)) {
33-
_program_cache = std::make_unique<jit::program_cache>();
34-
}
35-
36-
if (has_flag(flags, init_flags::LOAD_NVCOMP)) { io::detail::nvcomp::load_nvcomp_library(); }
37-
3832
auto dump_codegen_flag = getenv_or("LIBCUDF_JIT_DUMP_CODEGEN", std::string{"OFF"});
3933
_dump_codegen = (dump_codegen_flag == "ON" || dump_codegen_flag == "1");
4034

4135
auto use_jit_flag = getenv_or("LIBCUDF_JIT_ENABLED", std::string{"OFF"});
4236
_use_jit = (use_jit_flag == "ON" || use_jit_flag == "1");
37+
38+
initialize_components(flags);
4339
}
4440

4541
jit::program_cache& context::program_cache()
@@ -50,6 +46,20 @@ jit::program_cache& context::program_cache()
5046

5147
bool context::dump_codegen() const { return _dump_codegen; }
5248

49+
void context::initialize_components(init_flags flags)
50+
{
51+
// Only initialize components that haven't been initialized yet
52+
auto const new_flags = flags & ~_initialized_flags;
53+
54+
if (has_flag(new_flags, init_flags::INIT_JIT_CACHE)) {
55+
_program_cache = std::make_unique<jit::program_cache>();
56+
}
57+
58+
if (has_flag(new_flags, init_flags::LOAD_NVCOMP)) { io::detail::nvcomp::load_nvcomp_library(); }
59+
60+
_initialized_flags = _initialized_flags | new_flags;
61+
}
62+
5363
bool context::use_jit() const { return _use_jit; }
5464

5565
std::unique_ptr<context>& get_context_ptr_ref()
@@ -71,15 +81,15 @@ namespace CUDF_EXPORT cudf {
7181

7282
void initialize(init_flags flags)
7383
{
74-
CUDF_EXPECTS(
75-
get_context_ptr_ref() == nullptr, "context is already initialized", std::runtime_error);
76-
get_context_ptr_ref() = std::make_unique<context>(flags);
84+
auto& ctx = get_context_ptr_ref();
85+
if (ctx == nullptr) {
86+
// First initialization - create the context
87+
ctx = std::make_unique<context>(flags);
88+
} else {
89+
// Context already exists - initialize additional components
90+
ctx->initialize_components(flags);
91+
}
7792
}
7893

79-
void deinitialize()
80-
{
81-
CUDF_EXPECTS(
82-
get_context_ptr_ref() != nullptr, "context has already been deinitialized", std::runtime_error);
83-
get_context_ptr_ref().reset();
84-
}
94+
void deinitialize() { get_context_ptr_ref().reset(); }
8595
} // namespace CUDF_EXPORT cudf

cpp/src/runtime/context.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ class program_cache;
3333
class context {
3434
private:
3535
std::unique_ptr<jit::program_cache> _program_cache;
36-
bool _dump_codegen = false;
37-
bool _use_jit = false;
36+
init_flags _initialized_flags = init_flags::NONE;
37+
bool _dump_codegen = false;
38+
bool _use_jit = false;
3839

3940
public:
4041
context(init_flags flags = init_flags::INIT_JIT_CACHE);
@@ -48,6 +49,10 @@ class context {
4849

4950
[[nodiscard]] bool dump_codegen() const;
5051

52+
/// @brief Initialize additional components based on the provided flags
53+
/// @param flags The initialization flags to process
54+
void initialize_components(init_flags flags);
55+
5156
[[nodiscard]] bool use_jit() const;
5257
};
5358

cpp/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ ConfigureTest(
427427
utilities_tests/column_debug_tests.cpp
428428
utilities_tests/column_utilities_tests.cpp
429429
utilities_tests/column_wrapper_tests.cpp
430+
utilities_tests/context_tests.cpp
430431
utilities_tests/default_stream_tests.cpp
431432
utilities_tests/io_utilities_tests.cpp
432433
utilities_tests/lists_column_wrapper_tests.cpp
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2025, NVIDIA CORPORATION.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <cudf_test/base_fixture.hpp>
18+
19+
#include <cudf/context.hpp>
20+
21+
#include <gtest/gtest.h>
22+
23+
struct ContextTest : public cudf::test::BaseFixture {
24+
~ContextTest() override
25+
{
26+
try {
27+
cudf::deinitialize();
28+
} catch (...) {
29+
}
30+
}
31+
};
32+
33+
TEST_F(ContextTest, MultipleInitializeCalls)
34+
{
35+
cudf::initialize(cudf::init_flags::INIT_JIT_CACHE);
36+
37+
EXPECT_NO_THROW(cudf::initialize(cudf::init_flags::LOAD_NVCOMP));
38+
EXPECT_NO_THROW(cudf::initialize(cudf::init_flags::ALL));
39+
}
40+
41+
TEST_F(ContextTest, InitializeAfterDeinitialize)
42+
{
43+
cudf::initialize(cudf::init_flags::ALL);
44+
cudf::deinitialize();
45+
46+
EXPECT_NO_THROW(cudf::initialize(cudf::init_flags::INIT_JIT_CACHE));
47+
}
48+
49+
TEST_F(ContextTest, DeinitializeWithoutInitialize) { EXPECT_NO_THROW(cudf::deinitialize()); }
50+
51+
TEST_F(ContextTest, MultipleDeinitializeCalls)
52+
{
53+
cudf::initialize(cudf::init_flags::ALL);
54+
cudf::deinitialize();
55+
56+
EXPECT_NO_THROW(cudf::deinitialize());
57+
}

0 commit comments

Comments
 (0)