diff --git a/cpp/src/mip/diversity/diversity_manager.cu b/cpp/src/mip/diversity/diversity_manager.cu index a858c10958..3584151828 100644 --- a/cpp/src/mip/diversity/diversity_manager.cu +++ b/cpp/src/mip/diversity/diversity_manager.cu @@ -22,6 +22,8 @@ #include #include +#include + #include "cuda_profiler_api.h" namespace cuopt::linear_programming::detail { @@ -308,6 +310,10 @@ solution_t diversity_manager_t::run_solver() constexpr f_t max_time_on_lp = 30; const f_t lp_time_limit = min(max_time_on_lp, time_limit * time_ratio_on_init_lp); + // to automatically compute the solving time on scope exit + auto timer_raii_guard = + cuopt::scope_guard([&]() { stats.total_solve_time = timer.elapsed_time(); }); + // after every change to the problem, we should resize all the relevant vars // we need to encapsulate that to prevent repetitions lp_optimal_solution.resize(problem_ptr->n_variables, problem_ptr->handle_ptr->get_stream()); @@ -371,12 +377,8 @@ solution_t diversity_manager_t::run_solver() if (check_b_b_preemption()) { return population.best_feasible(); } // generate a population with 5 solutions(FP+FJ) generate_initial_solutions(); - if (timer.check_time_limit()) { - stats.total_solve_time = timer.elapsed_time(); - return population.best_feasible(); - } + if (timer.check_time_limit()) { return population.best_feasible(); } main_loop(); - stats.total_solve_time = timer.elapsed_time(); return population.best_feasible(); }; diff --git a/cpp/src/utilities/scope_guard.hpp b/cpp/src/utilities/scope_guard.hpp new file mode 100644 index 0000000000..e1791854f3 --- /dev/null +++ b/cpp/src/utilities/scope_guard.hpp @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights + * reserved. SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace cuopt { + +template +class scope_guard { + public: + explicit scope_guard(Func cleanup) : cleanup_(std::move(cleanup)) {} + + ~scope_guard() { cleanup_(); } + + scope_guard(const scope_guard&) = delete; + scope_guard& operator=(const scope_guard&) = delete; + scope_guard(scope_guard&&) = delete; + scope_guard& operator=(scope_guard&&) = delete; + + private: + Func cleanup_; +}; + +} // namespace cuopt diff --git a/cpp/tests/linear_programming/c_api_tests/c_api_tests.cpp b/cpp/tests/linear_programming/c_api_tests/c_api_tests.cpp index 2e414b5bbe..e675a3d5d3 100644 --- a/cpp/tests/linear_programming/c_api_tests/c_api_tests.cpp +++ b/cpp/tests/linear_programming/c_api_tests/c_api_tests.cpp @@ -79,6 +79,19 @@ TEST(c_api, iteration_limit) EXPECT_EQ(termination_status, CUOPT_TERIMINATION_STATUS_ITERATION_LIMIT); } +TEST(c_api, solve_time_bb_preemption) +{ + const std::string& rapidsDatasetRootDir = cuopt::test::get_rapids_dataset_root_dir(); + std::string filename = rapidsDatasetRootDir + "/mip/" + "bb_optimality.mps"; + int termination_status; + double solve_time = std::numeric_limits::quiet_NaN(); + EXPECT_EQ(solve_mps_file(filename.c_str(), 5, CUOPT_INFINITY, &termination_status, &solve_time), + CUOPT_SUCCESS); + EXPECT_EQ(termination_status, CUOPT_TERIMINATION_STATUS_OPTIMAL); + EXPECT_GT(solve_time, 0); // solve time should not be equal to 0, even on very simple instances + // solved by B&B before the diversity solver has time to run +} + TEST(c_api, bad_parameter_name) { EXPECT_EQ(test_bad_parameter_name(), CUOPT_INVALID_ARGUMENT); } TEST(c_api, burglar) { EXPECT_EQ(burglar_problem(), CUOPT_SUCCESS); }