Skip to content

Commit

Permalink
[#56] Fix update current thread priority for linux and make an enum
Browse files Browse the repository at this point in the history
  • Loading branch information
CMurtagh-LGTM committed Dec 15, 2024
1 parent 2b46a4d commit 971f512
Show file tree
Hide file tree
Showing 17 changed files with 88 additions and 89 deletions.
4 changes: 3 additions & 1 deletion src/Reactor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ namespace dsl {

struct Once;

template <util::Priority>
struct Priority;

template <typename>
Expand Down Expand Up @@ -192,7 +193,8 @@ class Reactor {
using Trigger = dsl::word::Trigger<T>;

/// @copydoc dsl::word::Priority
using Priority = dsl::word::Priority;
template <util::Priority value>
using Priority = dsl::word::Priority<value>;

/// @copydoc dsl::word::Always
using Always = dsl::word::Always;
Expand Down
2 changes: 1 addition & 1 deletion src/dsl/Parse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ namespace dsl {
Parse<Sentence...>>(task);
}

static int priority(threading::ReactionTask& task) {
static util::Priority priority(threading::ReactionTask& task) {
return std::conditional_t<fusion::has_priority<DSL>::value, DSL, fusion::NoOp>::template priority<
Parse<Sentence...>>(task);
}
Expand Down
4 changes: 2 additions & 2 deletions src/dsl/fusion/NoOp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ namespace dsl {
}

template <typename DSL>
static int priority(const threading::ReactionTask& /*task*/) {
return word::Priority::NORMAL::value;
static util::Priority priority(const threading::ReactionTask& /*task*/) {
return util::Priority::NORMAL;
}

template <typename DSL>
Expand Down
4 changes: 2 additions & 2 deletions src/dsl/fusion/PriorityFusion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ namespace dsl {
struct PriorityFuser<std::tuple<Word>> {

template <typename DSL>
static int priority(threading::ReactionTask& task) {
static util::Priority priority(threading::ReactionTask& task) {

// Return our priority
return Word::template priority<DSL>(task);
Expand All @@ -56,7 +56,7 @@ namespace dsl {
struct PriorityFuser<std::tuple<Word1, Word2, WordN...>> {

template <typename DSL>
static int priority(threading::ReactionTask& task) {
static util::Priority priority(threading::ReactionTask& task) {

// Choose our maximum priority
return std::max(Word1::template priority<DSL>(task),
Expand Down
2 changes: 1 addition & 1 deletion src/dsl/word/Always.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ namespace dsl {
auto idle_task = std::make_unique<threading::ReactionTask>(
reaction,
false,
[](threading::ReactionTask& task) { return DSL::priority(task) - 1; },
[](threading::ReactionTask& task) { return prev(DSL::priority(task)); },
DSL::run_inline,
DSL::pool,
DSL::group);
Expand Down
57 changes: 6 additions & 51 deletions src/dsl/word/Priority.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
#define NUCLEAR_DSL_WORD_PRIORITY_HPP

#include "../../threading/Reaction.hpp"
#include "../../util/Priority.hpp"

namespace NUClear {
namespace dsl {
namespace word {

/**
* Task priority can be controlled using an assigned setting.
*
Expand Down Expand Up @@ -67,57 +67,12 @@ namespace dsl {
* @par Implements
* Fusion
*/
template <util::Priority value>
struct Priority {

struct REALTIME {
/// Realtime priority runs with 1000 value
static constexpr int value = 1000;

template <typename DSL>
static int priority(const threading::ReactionTask& /*task*/) {
return value;
}
};

struct HIGH {
/// High priority runs with 750 value
static constexpr int value = 750;

template <typename DSL>
static int priority(const threading::ReactionTask& /*task*/) {
return value;
}
};

struct NORMAL {
/// Normal priority runs with 500 value
static constexpr int value = 500;

template <typename DSL>
static int priority(const threading::ReactionTask& /*task*/) {
return value;
}
};

struct LOW {
/// Low priority runs with 250 value
static constexpr int value = 250;

template <typename DSL>
static int priority(const threading::ReactionTask& /*task*/) {
return value;
}
};

struct IDLE {
/// Idle tasks run with 0 priority, they run when there is free time
static constexpr int value = 0;

template <typename DSL>
static int priority(const threading::ReactionTask& /*task*/) {
return value;
}
};
template <typename DSL>
static util::Priority priority(const threading::ReactionTask& /*task*/) {
return value;
}
};

} // namespace word
Expand Down
3 changes: 2 additions & 1 deletion src/dsl/word/Shutdown.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#define NUCLEAR_DSL_WORD_SHUTDOWN_HPP

#include "../operation/TypeBind.hpp"
#include "../../util/Priority.hpp"

namespace NUClear {
namespace dsl {
Expand Down Expand Up @@ -54,7 +55,7 @@ namespace dsl {
*/
struct Shutdown
: operation::TypeBind<Shutdown>
, Priority::IDLE {};
, Priority<util::Priority::LOWEST> {};

} // namespace word
} // namespace dsl
Expand Down
2 changes: 1 addition & 1 deletion src/extension/ChronoController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ namespace extension {
wait.notify_all();
});

on<Always, Priority::REALTIME>().then("Chrono Controller", [this] {
on<Always, Priority<util::Priority::HIGHEST>>().then("Chrono Controller", [this] {
// Run until we are told to stop
while (running.load(std::memory_order_acquire)) {

Expand Down
3 changes: 2 additions & 1 deletion src/threading/ReactionTask.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "../util/GroupDescriptor.hpp"
#include "../util/Inline.hpp"
#include "../util/ThreadPoolDescriptor.hpp"
#include "../util/Priority.hpp"
#include "../util/platform.hpp"
#include "Reaction.hpp"

Expand Down Expand Up @@ -136,7 +137,7 @@ namespace threading {
bool run_inline{false};

/// The priority to run this task at
int priority;
util::Priority priority;
/// If the task should be executed inline (in the current thread) or not
util::Inline should_inline{util::Inline::NEUTRAL};
/// Details about the thread pool that this task will run from, this will also influence what task queue
Expand Down
4 changes: 2 additions & 2 deletions src/threading/scheduler/Group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace NUClear {
namespace threading {
namespace scheduler {

Group::LockHandle::LockHandle(const NUClear::id_t& task_id, const int& priority, std::function<void()> notify)
Group::LockHandle::LockHandle(const NUClear::id_t& task_id, const util::Priority& priority, std::function<void()> notify)
: task_id(task_id), priority(priority), notify(std::move(notify)) {}

Group::GroupLock::GroupLock(Group& group, std::shared_ptr<LockHandle> handle)
Expand Down Expand Up @@ -109,7 +109,7 @@ namespace threading {
Group::Group(std::shared_ptr<const util::GroupDescriptor> descriptor) : descriptor(std::move(descriptor)) {}

std::unique_ptr<Lock> Group::lock(const NUClear::id_t& task_id,
const int& priority,
const util::Priority& priority,
const std::function<void()>& notify) {

auto handle = std::make_shared<LockHandle>(task_id, priority, notify);
Expand Down
7 changes: 4 additions & 3 deletions src/threading/scheduler/Group.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <vector>

#include "../../util/GroupDescriptor.hpp"
#include "../../util/Priority.hpp"
#include "Lock.hpp"

namespace NUClear {
Expand All @@ -50,7 +51,7 @@ namespace threading {
* It holds if the lock should currently be locked, as well as ordering which locks should be locked first.
*/
struct LockHandle {
LockHandle(const NUClear::id_t& task_id, const int& priority, std::function<void()> notify);
LockHandle(const NUClear::id_t& task_id, const util::Priority& priority, std::function<void()> notify);

/**
* Compare two lock handles by comparing their priority and task id
Expand Down Expand Up @@ -78,7 +79,7 @@ namespace threading {
/// The task id of the reaction that is waiting, lower task ids run first
NUClear::id_t task_id;
/// The priority of the reaction that is waiting, higher priorities run first
int priority;
util::Priority priority;
/// If this lock has been successfully locked
bool locked{false};
/// If this lock has been notified that it can lock
Expand Down Expand Up @@ -156,7 +157,7 @@ namespace threading {
* @return a lock which can be locked once a token is available
*/
std::unique_ptr<Lock> lock(const NUClear::id_t& task_id,
const int& priority,
const util::Priority& priority,
const std::function<void()>& notify);

/// The descriptor for this group
Expand Down
2 changes: 1 addition & 1 deletion src/threading/scheduler/Pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ namespace threading {
auto task = std::make_unique<ReactionTask>(
nullptr,
true,
[](const ReactionTask&) { return 0; },
[](const ReactionTask&) { return util::Priority::LOWEST; },
[](const ReactionTask&) { return util::Inline::ALWAYS; },
[](const ReactionTask&) { return dsl::word::Pool<>::descriptor(); },
[](const ReactionTask&) { return std::set<std::shared_ptr<const util::GroupDescriptor>>{}; });
Expand Down
2 changes: 1 addition & 1 deletion src/threading/scheduler/Scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ namespace threading {

std::unique_ptr<Lock> Scheduler::get_groups_lock(
const NUClear::id_t& task_id,
const int& priority,
const util::Priority& priority,
const std::shared_ptr<Pool>& pool,
const std::set<std::shared_ptr<const util::GroupDescriptor>>& descs) {

Expand Down
2 changes: 1 addition & 1 deletion src/threading/scheduler/Scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ namespace threading {
* @return a combined lock representing the state of all the groups
*/
std::unique_ptr<Lock> get_groups_lock(const NUClear::id_t& task_id,
const int& priority,
const util::Priority& priority,
const std::shared_ptr<Pool>& pool,
const std::set<std::shared_ptr<const util::GroupDescriptor>>& descs);

Expand Down
1 change: 1 addition & 0 deletions src/util/CallbackGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "../message/ReactionStatistics.hpp"
#include "../util/MergeTransient.hpp"
#include "../util/TransientDataElements.hpp"
#include "../util/Priority.hpp"
#include "../util/apply.hpp"
#include "../util/unpack.hpp"
#include "../util/update_current_thread_priority.hpp"
Expand Down
44 changes: 44 additions & 0 deletions src/util/Priority.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* MIT License
*
* Copyright (c) 2024 NUClear Contributors
*
* This file is part of the NUClear codebase.
* See https://github.com/Fastcode/NUClear for further info.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef NUCLEAR_UTIL_PRIORITY_HPP
#define NUCLEAR_UTIL_PRIORITY_HPP

#include <algorithm>
#include <cstdint>
#include <type_traits>

namespace NUClear {
namespace util {

enum class Priority : uint8_t { LOWEST = 0, LOW = 1, NORMAL = 2, HIGH = 3, HIGHEST = 4 };
inline Priority prev(Priority value) {
value = static_cast<Priority>(static_cast<std::underlying_type_t<Priority>>(value) - 1);
value = std::min(value, Priority::LOWEST);
return value;
}
constexpr Priority MAX_PRIORITY = Priority::HIGHEST;

} // namespace util
} // namespace NUClear

#endif // NUCLEAR_UTIL_PRIORITY_HPP
34 changes: 14 additions & 20 deletions src/util/update_current_thread_priority.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@
#ifndef NUCLEAR_UTIL_UPDATE_CURRENT_THREAD_PRIORITY_HPP
#define NUCLEAR_UTIL_UPDATE_CURRENT_THREAD_PRIORITY_HPP

#include "../util/Priority.hpp"

#ifndef _WIN32

#include <pthread.h>

inline void update_current_thread_priority(int priority) {

// TODO(Trent) SCHED_NORMAL for normal threads
// TODO(Trent) SCHED_FIFO for realtime threads
// TODO(Trent) SCHED_RR for high priority threads
inline void update_current_thread_priority(NUClear::util::Priority priority) {
auto priority_int = static_cast<std::underlying_type_t<NUClear::util::Priority>>(priority);

auto sched_priority = sched_get_priority_min(SCHED_RR)
+ (priority / (sched_get_priority_max(SCHED_RR) - sched_get_priority_min(SCHED_RR)));
auto step = (sched_get_priority_max(SCHED_RR) - sched_get_priority_min(SCHED_RR))
/ static_cast<std::underlying_type_t<NUClear::util::Priority>>(NUClear::util::MAX_PRIORITY);
auto sched_priority = priority_int * step;

sched_param p{};
p.sched_priority = sched_priority;
Expand All @@ -46,30 +46,24 @@ inline void update_current_thread_priority(int priority) {

#include "platform.hpp"

inline void update_current_thread_priority(int priority) {
inline void update_current_thread_priority(NUClear::util::Priority priority) {

switch ((priority * 7) / 1000) {
case 0: {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
} break;
case 1: {
switch (priority) {
case LOWEST: {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
} break;
case 2: {
case LOW: {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
} break;
case 3: {
case NORMAL: {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
} break;
case 4: {
case HIGH: {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
} break;
case 5: {
case HIGHEST: {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
} break;
case 6: {
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
} break;
}
}

Expand Down

0 comments on commit 971f512

Please sign in to comment.