Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#56] Fix update current thread priority for linux and make an enum #160

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
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
77 changes: 10 additions & 67 deletions src/dsl/word/Priority.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,100 +24,43 @@
#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.
*
* @code on<Trigger<T, ...>, Priority::HIGH>() @endcode
* @code on<Trigger<T, ...>, Priority<util::Priority::HIGH>>() @endcode
* The PowerPlant uses this setting to determine the scheduling order in the threadpool, as well as assign a
* priority to the thread on the OS.
*
* The available priority settings are:
*
* <b>REALTIME:</b> Tasks assigned with this will be queued with all other REALTIME tasks.
*
* <b>HIGHEST:</b>
* <b>HIGH:</b>
* Tasks assigned with this will be queued with all other HIGH tasks.
* They will be scheduled for execution when there are no REALTIME tasks in the queue.
*
* <b>NORMAL:</b>
* Tasks assigned with this will be queued with all other NORMAL tasks.
* They will be scheduled for execution when there are no REALTIME and HIGH tasks in the queue.
*
* <b>LOW:</b>
* Tasks assigned with this will be queued with all other LOW tasks.
* They will be scheduled for execution when there are no REALTIME, HIGH and NORMAL tasks in the queue.
*
* <b>IDLE:</b>
* Tasks assigned with this priority will be queued with all other IDLE tasks.
* They will be scheduled for execution when there are no other tasks running in the system.
* <b>LOWEST:</b>
*
* @par Default Behaviour
* @code on<Trigger<T>>() @endcode
* When the priority is not specified, tasks will be assigned a default setting; NORMAL.
*
* @attention
* If the OS allows the user to set thread priority, this word can also be used to assign the priority of the
* If the OS allows the user to set thread priority, this word will also be used to assign the priority of the
* thread in its runtime environment.
*
* @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/dsl/word/emit/Initialise.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ namespace dsl {
auto emitter = std::make_unique<threading::ReactionTask>(
nullptr,
false,
[](threading::ReactionTask& /*task*/) { return 1000; },
[](threading::ReactionTask& /*task*/) { return NUClear::util::Priority::HIGHEST; },
[](threading::ReactionTask& /*task*/) { return util::Inline::NEVER; },
[](threading::ReactionTask& /*task*/) { return Pool<>::descriptor(); },
[](threading::ReactionTask& /*task*/) {
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
49 changes: 49 additions & 0 deletions src/util/Priority.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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 {

/**
* The priority value for Priority dsl word
*/
enum class Priority : uint8_t { LOWEST = 0, LOW = 1, NORMAL = 2, HIGH = 3, HIGHEST = 4 };
/**
* Gets one lower priority unless already lowest
*/
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;
}

} // namespace util
} // namespace NUClear

#endif // NUCLEAR_UTIL_PRIORITY_HPP
Loading
Loading