Skip to content

sys/sched_rr: Add a simple round robin scheduler module#14810

Closed
kfessel wants to merge 10 commits intoRIOT-OS:masterfrom
kfessel:sched_rr
Closed

sys/sched_rr: Add a simple round robin scheduler module#14810
kfessel wants to merge 10 commits intoRIOT-OS:masterfrom
kfessel:sched_rr

Conversation

@kfessel
Copy link
Copy Markdown
Contributor

@kfessel kfessel commented Aug 20, 2020

I would like to use RIOT with multiple threads at the same priority,
that might not cooperate but should share CPU time.

Contribution description

This contains a simple round robin scheduler module using xtimer to rearrange the current run queue

Testing procedure

create multiple threads of same priority that should work in parallel
without this module only one of them will run.

with this module and calling start_schedule_rr() form #include "sched_rr.h"
they run parallel , sharing cpu time.

see https://github.com/kfessel/riot-thread-duel for a demonstration.

Issues/PRs references

non yet

@benpicco
Copy link
Copy Markdown
Contributor

Would probably be a good idea to include the test application with this PR.

@benpicco benpicco requested a review from kaspar030 August 20, 2020 16:14
@benpicco benpicco added Area: core Area: RIOT kernel. Handle PRs marked with this with care! Type: new feature The issue requests / The PR implemements a new feature for RIOT labels Aug 20, 2020
//this will try to reorder the current priority
//(put the current thread at the end of the list)
thread_t * active_thread = thread_get_active();
if(active_thread != NULL){
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes me wonder: Can't we simply turn off the sched tick when we enter the idle state?
And turn it back on when we leave idle?

Copy link
Copy Markdown
Contributor Author

@kfessel kfessel Aug 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be possible to do that (turn off on idle) or to check when switching priority if there is more than one thread in that priority run queue. That would need a little more integration with the existing scheduler.
active_thread == NULL is not a case for idle but for a thread ended and no new one is scheduled yet

@kfessel
Copy link
Copy Markdown
Contributor Author

kfessel commented Aug 21, 2020

@maribu may also like to look at this

@kfessel
Copy link
Copy Markdown
Contributor Author

kfessel commented Aug 21, 2020

I will add a small example of the thread_duel to the PR

Copy link
Copy Markdown
Member

@maribu maribu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some inline comments mostly regarding coding style.

In addition, I think that this should be in core, as it needs to access scheduler internal data structures. IMO there should be no accesses to internals of core outside of core, only APIs should be used from outside. (An alternative to moving this to core would be to provide APIs as needed. But new core APIs need extra care for maintaining, so IMO it is better to move this to core.)


/**
* @defgroup Sched_RR
* @ingroup sys
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO scheduler and everything strongly coupled to it should be in core.

Comment on lines +26 to +31
/**
* time between rond robin calls default 1ms
*/
#ifndef SCHED_RR_TIMER
#define SCHED_RR_TIMER 1000
#endif
Copy link
Copy Markdown
Member

@maribu maribu Aug 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/**
* time between rond robin calls default 1ms
*/
#ifndef SCHED_RR_TIMER
#define SCHED_RR_TIMER 1000
#endif
#if !defined(SCHED_RR_TIMER) || defined(DOXYGEN)
/**
* @brief Time between round robin calls in µs
*
* @details Defaults to 1ms
*/
#define SCHED_RR_TIMER 1000
#endif
  1. You should always use the @brief command.
  2. The doxygen comment should be right before the macro it applies to
  3. In order to appear in the Doxygen documentation regardless of whether SCHED_RR_TIMER is previously defined, it is best to add an || defined(DOXYGEN).

Also: Please align the text that comes after @brief, @details etc.

Comment on lines +33 to +38
/**
* masks off priorities that should not be scheduled default 0
*/
#ifndef SCHED_RR_MASK
#define SCHED_RR_MASK 1<<0
#endif
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/**
* masks off priorities that should not be scheduled default 0
*/
#ifndef SCHED_RR_MASK
#define SCHED_RR_MASK 1<<0
#endif
#if !defined(SCHED_RR_MASK) || defined(DOXYGEN)
/**
* @brief masks off priorities that should not be scheduled default 0
*/
#define SCHED_RR_MASK BIT0
#endif

The macro BIT0 is provided in bitarithm.h

Copy link
Copy Markdown
Contributor Author

@kfessel kfessel Aug 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i do no bitarithmetics so i rather not like to include bitarithm.h in the header (especially since its prone to conflict with other similar definitions)
i would go for #define SCHED_RR_MASK 1<<PRIO_HIGHEST if there is such a thing

thread_t * active_thread = thread_get_active();
if(active_thread != NULL){
if(! (SCHED_RR_MASK & 1 << active_thread->priority)){
clist_lpoprpush(&sched_runqueues[active_thread->priority]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is accesses scheduler internal data structures, this should be IMO

a) Either moved to core
b) core_sched should be extended to provide a public API that this could use

I'm personally for a)

Copy link
Copy Markdown
Contributor Author

@kfessel kfessel Aug 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure: wouldn't moving this to core make this not a module?
This uses xtimer which is not part of core maybe this would be a blocker for it being in core.
Aside from that i am all for it:
If we move this to core we could also go for a little bit more integration
(e.g.: switching RR on and off depending on if the current queue needs it or at least stop it on idle as @benpicco said)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

core is indeed a single module, which contains submodules. E.g. core_thread_flags enables an optional feature, which is part of core. If this would be part of core, it could be named e.g. core_sched_round_robin. (I think the extra verbosity in the module name doesn't hurt.)

This using a high level timer is to my understanding not a blocker for this being part of core. E.g. stdio is used in core for debugging and for panic(), but is not part of core.

Comment on lines +29 to +30
// this lets the current thread give way
// simple RoundRobin
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use C style comments (e.g. /* ... */), instead of C++ style. (I'm aware that recent versions of C also support C++ style comments, but the coding conventions wants C style comments.)

The comment seems content-wise a bit confusing to me. Maybe you could rephrase it.

@kfessel
Copy link
Copy Markdown
Contributor Author

kfessel commented Aug 21, 2020

Fixed comments and coding style

@benpicco
Copy link
Copy Markdown
Contributor

Probably worth adding a note that this scheduler does not attempt to be fair.

e.g. you could have

A |........Y |........Y.|
B |         .|         .|

Here A would yield before it's time slice expires, B gets scheduled only to be scheduled away by the next timer tick.

@kfessel
Copy link
Copy Markdown
Contributor Author

kfessel commented Aug 21, 2020

you are right i went for a as simple as possible approach to get this started

@kfessel kfessel requested a review from jia200x as a code owner August 21, 2020 13:07
@kfessel
Copy link
Copy Markdown
Contributor Author

kfessel commented Aug 21, 2020

what does linux do:
preempt_rt adds 4 RT classes which are in order of priority SCHED_DEADLINE, SCHED_FIFO, SCHED_RR, SCHED_OTHER (contains everything else (fair scheduled))

@kfessel
Copy link
Copy Markdown
Contributor Author

kfessel commented Aug 21, 2020

I did some more fair RR attempt which can be seen in https://github.com/kfessel/riot-thread-duel, it uses the shed_cb to monitor the used cpu time and prefers to run the thread with the least used time.

Copy link
Copy Markdown
Member

@maribu maribu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some inline comments. You might want to consider giving uncrustify a try ;-) There is a configuration for uncrustify in the root of the RIOT repo that automatically formats your code as required by the coding convention (with some minor issues).

{
int size = THREAD_STACKSIZE_DEFAULT ;
char * wech = malloc(size + 4);
* (uint32_t *) wech = 3; /* 0-10 workness*/
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* (uint32_t *) wech = 3; /* 0-10 workness*/
*(uint32_t *)wech = 3; /* 0-10 workness*/

Also: It would improve readability if you don't abuse the stack for this, but just use distinct variables for this.

thread_t * active_thread = thread_get_active();
if(active_thread != NULL){
if(! (SCHED_RR_MASK & 1 << active_thread->priority)){
clist_lpoprpush(&sched_runqueues[active_thread->priority]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

core is indeed a single module, which contains submodules. E.g. core_thread_flags enables an optional feature, which is part of core. If this would be part of core, it could be named e.g. core_sched_round_robin. (I think the extra verbosity in the module name doesn't hurt.)

This using a high level timer is to my understanding not a blocker for this being part of core. E.g. stdio is used in core for debugging and for panic(), but is not part of core.

Thread_Duel
============

this is a thread duell application to test RIOTS mutithreading abblities
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test applications should be placed in tests/

Copy link
Copy Markdown
Contributor Author

@kfessel kfessel Aug 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its not a test in a unit-test sense but i replaced the word

@kfessel
Copy link
Copy Markdown
Contributor Author

kfessel commented Aug 24, 2020

should

+ifneq (,$(filter sched_rr, $(USEMODULE)))
+    USEMODULE += xtimer
+endif

got to /Makefile.dep
or to /sys//Makefile.dep << i think this but i see much of the other

@maribu
Copy link
Copy Markdown
Member

maribu commented Aug 24, 2020

should

+ifneq (,$(filter sched_rr, $(USEMODULE)))
+    USEMODULE += xtimer
+endif

got to /Makefile.dep
or to /sys//Makefile.dep << i think this but i see much of the other

It should be in sys/Makefile.dep. For historic reasons the root-level Makefile.dep was previously used a lot.

@kfessel
Copy link
Copy Markdown
Contributor Author

kfessel commented Aug 26, 2020

moved the the dependancy
btw. working on core/sched_rr for deeper integration (atm that is a little delayed)

@kfessel
Copy link
Copy Markdown
Contributor Author

kfessel commented Mar 17, 2021

Closing this in favor of #16126 please continue the review there

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: core Area: RIOT kernel. Handle PRs marked with this with care! Type: new feature The issue requests / The PR implemements a new feature for RIOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants