Skip to content

Commit

Permalink
avoid using boost::rational in busy loop
Browse files Browse the repository at this point in the history
  • Loading branch information
kuron99 committed Dec 28, 2023
1 parent e61ec8d commit e65dc01
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 12 deletions.
5 changes: 3 additions & 2 deletions include/tateyama/task_scheduler/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include <glog/logging.h>
#include <tateyama/utils/cache_align.h>
#include <tateyama/task_scheduler/impl/periodic_notifier.h>

namespace tateyama::task_scheduler::impl {
class thread_control;
Expand Down Expand Up @@ -81,7 +82,7 @@ class cache_align context {
* @brief accessor to the count_check_local_first parameter
* @return counter used to accumulate ratio_check_local_first
*/
[[nodiscard]] rational& count_check_local_first() noexcept {
[[nodiscard]] impl::periodic_notifier& count_check_local_first() noexcept {
return count_check_local_first_;
}

Expand Down Expand Up @@ -136,7 +137,7 @@ class cache_align context {
private:
std::size_t index_{};
std::size_t last_steal_from_{};
rational count_check_local_first_{};
impl::periodic_notifier count_check_local_first_{};
bool task_is_stolen_{};
impl::thread_control* thread_{};
bool busy_working_{};
Expand Down
76 changes: 76 additions & 0 deletions include/tateyama/task_scheduler/impl/periodic_notifier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2018-2023 Project Tsurugi.
*
* 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 <atomic>

#include <takatori/util/assertion.h>

#include <tateyama/utils/cache_align.h>

namespace tateyama::task_scheduler::impl {

/**
* @brief util class to get the notification periodically while clients count up
*/
class cache_align periodic_notifier {
public:

/**
* @brief construct default instance
*/
periodic_notifier() = default;

/**
* @brief construct instance
* @param notifications the numerator of notification ratio
* @param period the denominator of the notification ratio
* @details client gets the notifications in accordance with the given notification ratio.
* The number of notifications that equals to `notifications` will be made by the time `period` count of
* `count_up` calls finish.
*/
periodic_notifier(
std::size_t notifications,
std::size_t period
) noexcept :
notifications_(notifications),
period_(period)
{
BOOST_ASSERT(notifications != 0); //NOLINT
BOOST_ASSERT(period != 0); //NOLINT
BOOST_ASSERT(notifications <= period); //NOLINT
}

bool count_up() {
current_ += notifications_;
if(current_ >= period_) {
current_ -= period_;
return true;
}
return false;
}

void reset() {
current_ = 0;
}

private:
std::size_t notifications_{1};
std::size_t period_{1};
std::size_t current_{};
};

}
4 changes: 1 addition & 3 deletions include/tateyama/task_scheduler/impl/worker.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,15 +282,13 @@ class cache_align worker {
) {
// using counter, check sticky sometimes for fairness
auto& cnt = ctx.count_check_local_first();
cnt += cfg_->ratio_check_local_first();
if(cnt < 1) {
if(! cnt.count_up()) {
if(try_process(ctx, sq)) {
++stat_->sticky_;
return true;
}
if(try_process(ctx, q)) return true;
} else {
--cnt;
if(try_process(ctx, q)) return true;
if(try_process(ctx, sq)) {
++stat_->sticky_;
Expand Down
11 changes: 11 additions & 0 deletions include/tateyama/task_scheduler/scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,13 @@ class cache_align scheduler {
return worker_stats_;
}

/**
* @brief accessor to the contexts for testing purpose
*/
[[nodiscard]] std::vector<context>& contexts() noexcept {
return contexts_;
}

/**
* @brief accessor to the local queue for testing purpose
*/
Expand Down Expand Up @@ -404,6 +411,10 @@ class cache_align scheduler {
threads_.reserve(sz);
for(std::size_t i = 0; i < sz; ++i) {
auto& ctx = contexts_.emplace_back(i);
ctx.count_check_local_first() = impl::periodic_notifier{
static_cast<std::size_t>(cfg_.ratio_check_local_first().numerator()),
static_cast<std::size_t>(cfg_.ratio_check_local_first().denominator())
};
auto& worker = workers_.emplace_back(
queues_, sticky_task_queues_, initial_tasks_, worker_stats_[i], cfg_, [this](std::size_t index) {
this->initialize_preferred_worker_for_current_thread(index);
Expand Down
70 changes: 70 additions & 0 deletions test/tateyama/task_scheduler/periodic_notifier_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2018-2023 Project Tsurugi.
*
* 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.
*/
#include <tateyama/task_scheduler/impl/periodic_notifier.h>

#include <gtest/gtest.h>

namespace tateyama::task_scheduler::impl {

using namespace std::literals::string_literals;
using namespace std::chrono_literals;

class periodic_notifier_test : public ::testing::Test {

};

using namespace std::string_view_literals;

TEST_F(periodic_notifier_test, default_instance) {
periodic_notifier n{};
EXPECT_TRUE(n.count_up());
EXPECT_TRUE(n.count_up());
EXPECT_TRUE(n.count_up());
EXPECT_TRUE(n.count_up());
EXPECT_TRUE(n.count_up());
}

TEST_F(periodic_notifier_test, simple) {
periodic_notifier n{1, 2};
EXPECT_FALSE(n.count_up());
EXPECT_TRUE(n.count_up());
EXPECT_FALSE(n.count_up());
EXPECT_TRUE(n.count_up());
EXPECT_FALSE(n.count_up());
EXPECT_TRUE(n.count_up());
}

TEST_F(periodic_notifier_test, ratio_2_3) {
periodic_notifier n{2, 3};
EXPECT_FALSE(n.count_up());
EXPECT_TRUE(n.count_up());
EXPECT_TRUE(n.count_up());
EXPECT_FALSE(n.count_up());
EXPECT_TRUE(n.count_up());
EXPECT_TRUE(n.count_up());
}

TEST_F(periodic_notifier_test, ratio_1_3) {
periodic_notifier n{1, 3};
EXPECT_FALSE(n.count_up());
EXPECT_FALSE(n.count_up());
EXPECT_TRUE(n.count_up());
EXPECT_FALSE(n.count_up());
EXPECT_FALSE(n.count_up());
EXPECT_TRUE(n.count_up());
}

}
14 changes: 7 additions & 7 deletions test/tateyama/task_scheduler/scheduler_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,10 @@ TEST_F(scheduler_test, sticky_task_simple) {
sched.schedule_at(task{test_task_sticky{[&](context& t) {
executed02 = true;
}}}, 0);
context ctx{};
auto& ctx = sched.contexts()[0];
w0.init(thread_initialization_info{0}, ctx);

context ctx0{0};
auto& ctx0 = sched.contexts()[0];
w0.process_next(ctx0, lq0, sq0);
EXPECT_TRUE(executed00);
w0.process_next(ctx0, lq0, sq0);
Expand Down Expand Up @@ -185,12 +185,12 @@ TEST_F(scheduler_test, sticky_task_stealing) {
sched.schedule_at(task{test_task_sticky{[&](context& t) {
executed10 = true;
}}}, 1);
context ctx{};
auto& ctx = sched.contexts()[0];
w0.init(thread_initialization_info{0}, ctx);
w0.init(thread_initialization_info{1}, ctx);

context ctx0{0};
context ctx1{1};
auto& ctx0 = sched.contexts()[0];
auto& ctx1 = sched.contexts()[0];
w0.process_next(ctx0, lq0, sq0);
EXPECT_TRUE(executed00);
w1.process_next(ctx1, lq1, sq1);
Expand Down Expand Up @@ -235,10 +235,10 @@ TEST_F(scheduler_test, sticky_tasks) {
sched.schedule_at(task{test_task_sticky{[&](context& t) {
executed04 = true;
}}}, 0);
context ctx{};
auto& ctx = sched.contexts()[0];
w0.init(thread_initialization_info{0}, ctx);

context ctx0{0};
auto& ctx0 = sched.contexts()[0];
w0.process_next(ctx0, lq0, sq0);
EXPECT_TRUE(executed00);
w0.process_next(ctx0, lq0, sq0);
Expand Down

0 comments on commit e65dc01

Please sign in to comment.