Skip to content

Commit ceee53c

Browse files
committed
Replace weighted-priority with simple RR traversal
The weighted priority scheduler was over-engineered for common cases. In the systems with small task counts, simple fairness and reliability are more valuable than sophisticated priority weighting that introduces complexity without proportional benefits. The round-robin approach achieves the 80/20 rule: 80% of the benefits (fair scheduling, good performance) with 20% of the complexity, making it ideal for small systems where maintainability and reliability are paramount.
1 parent 9679c50 commit ceee53c

File tree

3 files changed

+236
-123
lines changed

3 files changed

+236
-123
lines changed

app/rtsched.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ typedef struct {
6262
* When "remaining" reaches zero it is reloaded from "credits" on the task’s
6363
* next turn.
6464
* – The function returns the ID of the selected RT task, or –1 when no RT task
65-
* is ready so the kernel should fall back to its normal weighted round-robin
66-
* scheduler.
65+
* is ready so the kernel should fall back to its round-robin scheduler.
6766
*/
6867
static int32_t custom_sched(void)
6968
{

include/sys/task.h

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@
33
/* Task Management and Scheduling
44
*
55
* Provides a lightweight task model with shared address space and
6-
* priority-based round-robin scheduling. Supports both preemptive and
7-
* cooperative scheduling modes with real-time scheduler hooks.
6+
* efficient round-robin scheduling. The scheduler uses the master task
7+
* list with optimized algorithms for better performance than naive O(n)
8+
* implementations, while maintaining simplicity and compatibility.
9+
*
10+
* The scheduler provides O(n) complexity but with small constant factors
11+
* and excellent practical performance for typical embedded workloads.
12+
* Priority-aware time slice allocation ensures good responsiveness.
813
*/
914

1015
#include <hal.h>
@@ -13,55 +18,67 @@
1318

1419
/* Task Priority
1520
*
16-
* Task priorities are encoded in a 16-bit value using weighted round-robin:
17-
* - Bits 15-8: Base Priority (Static) - determines task's "weight"
18-
* - Bits 7-0: Dynamic Priority (Counter) - decremented by scheduler
19-
*
20-
* Lower base priority values mean higher priority. When a task runs, its
21-
* counter is reloaded from its base priority. This ensures high-priority
22-
* tasks (low base values) run more frequently than low-priority tasks.
21+
* Task priorities are encoded in a 16-bit value with simplified mapping:
22+
* - Bits 15-8: Base Priority (Static) - mapped to priority level 0-7
23+
* - Bits 7-0: Time Slice Counter - decremented each tick when running
2324
*
24-
* The enum values duplicate the base priority in both bytes for easy
25-
* initialization.
25+
* Lower base priority values mean higher priority (level 0 = highest).
2626
*/
2727
enum task_priorities {
28-
TASK_PRIO_CRIT = 0x0101, /* Critical, must-run tasks */
29-
TASK_PRIO_REALTIME = 0x0303, /* Real-time tasks */
30-
TASK_PRIO_HIGH = 0x0707, /* High priority tasks */
31-
TASK_PRIO_ABOVE = 0x0F0F, /* Above normal priority */
32-
TASK_PRIO_NORMAL = 0x1F1F, /* Default priority for new tasks */
33-
TASK_PRIO_BELOW = 0x3F3F, /* Below normal priority */
34-
TASK_PRIO_LOW = 0x7F7F, /* Low priority tasks */
35-
TASK_PRIO_IDLE = 0xFFFF /* Idle task runs when nothing else ready */
28+
TASK_PRIO_CRIT = 0x0101, /* Critical, must-run tasks (level 0) */
29+
TASK_PRIO_REALTIME = 0x0303, /* Real-time tasks (level 1) */
30+
TASK_PRIO_HIGH = 0x0707, /* High priority tasks (level 2) */
31+
TASK_PRIO_ABOVE = 0x0F0F, /* Above normal priority (level 3) */
32+
TASK_PRIO_NORMAL = 0x1F1F, /* Default priority for new tasks (level 4) */
33+
TASK_PRIO_BELOW = 0x3F3F, /* Below normal priority (level 5) */
34+
TASK_PRIO_LOW = 0x7F7F, /* Low priority tasks (level 6) */
35+
TASK_PRIO_IDLE = 0xFFFF /* runs when nothing else ready (level 7) */
3636
};
3737

3838
/* Task Lifecycle States */
3939
enum task_states {
4040
TASK_STOPPED, /* Task created but not yet scheduled */
41-
TASK_READY, /* Task in ready list, waiting to be scheduled */
41+
TASK_READY, /* Task in ready state, waiting to be scheduled */
4242
TASK_RUNNING, /* Task currently executing on CPU */
4343
TASK_BLOCKED, /* Task waiting for delay timer to expire */
4444
TASK_SUSPENDED /* Task paused/excluded from scheduling until resumed */
4545
};
4646

47+
/* Priority Level Constants for Priority-Aware Time Slicing */
48+
#define TASK_PRIORITY_LEVELS 8 /* Number of priority levels (0-7) */
49+
#define TASK_HIGHEST_PRIORITY 0 /* Highest priority level */
50+
#define TASK_LOWEST_PRIORITY 7 /* Lowest priority level */
51+
52+
/* Time slice allocation per priority level (in system ticks) */
53+
#define TASK_TIMESLICE_CRIT 1 /* Critical tasks: minimal slice */
54+
#define TASK_TIMESLICE_REALTIME 2 /* Real-time tasks: small slice */
55+
#define TASK_TIMESLICE_HIGH 3 /* High priority: normal slice */
56+
#define TASK_TIMESLICE_ABOVE 4 /* Above normal: normal slice */
57+
#define TASK_TIMESLICE_NORMAL 5 /* Normal priority: standard slice */
58+
#define TASK_TIMESLICE_BELOW 7 /* Below normal: longer slice */
59+
#define TASK_TIMESLICE_LOW 10 /* Low priority: longer slice */
60+
#define TASK_TIMESLICE_IDLE 15 /* Idle tasks: longest slice */
61+
4762
/* Task Control Block (TCB)
4863
*
4964
* Contains all essential information about a single task, including saved
5065
* context, stack details, and scheduling parameters.
5166
*/
52-
typedef struct {
67+
typedef struct tcb {
5368
/* Context and Stack Management */
5469
jmp_buf context; /* Saved CPU context (GPRs, SP, PC) for task switching */
5570
void *stack; /* Pointer to base of task's allocated stack memory */
5671
size_t stack_sz; /* Total size of the stack in bytes */
5772
void (*entry)(void); /* Task's entry point function */
5873

5974
/* Scheduling Parameters */
60-
uint16_t prio; /* Encoded priority (base and dynamic counter) */
61-
uint16_t delay; /* Ticks remaining for task in TASK_BLOCKED state */
62-
uint16_t id; /* Unique task ID, assigned by kernel upon creation */
63-
uint8_t state; /* Current lifecycle state (e.g., TASK_READY) */
64-
uint8_t flags; /* Task flags for future extensions (reserved) */
75+
uint16_t prio; /* Encoded priority (base and time slice counter) */
76+
uint8_t prio_level; /* Priority level (0-7, 0 = highest) */
77+
uint8_t time_slice; /* Current time slice remaining */
78+
uint16_t delay; /* Ticks remaining for task in TASK_BLOCKED state */
79+
uint16_t id; /* Unique task ID, assigned by kernel upon creation */
80+
uint8_t state; /* Current lifecycle state (e.g., TASK_READY) */
81+
uint8_t flags; /* Task flags for future extensions (reserved) */
6582

6683
/* Real-time Scheduling Support */
6784
void *rt_prio; /* Opaque pointer for custom real-time scheduler hook */
@@ -78,20 +95,15 @@ typedef struct {
7895
list_node_t *task_current; /* Node of currently running task */
7996
jmp_buf context; /* Saved context of main kernel thread before scheduling */
8097
uint16_t next_tid; /* Monotonically increasing ID for next new task */
81-
uint16_t task_count; /* Cached count of active tasks for O(1) access */
98+
uint16_t task_count; /* Cached count of active tasks for quick access */
8299
bool preemptive; /* true = preemptive; false = cooperative */
83100

84-
/* Scheduler Optimization */
85-
list_node_t
86-
*last_ready_hint; /* Cache last ready task found to reduce iterations */
87-
88101
/* Real-Time Scheduler Hook */
89102
int32_t (*rt_sched)(void); /* Custom real-time scheduler function */
90103

91104
/* Timer Management */
92-
list_t *timer_list; /* List of active software timers */
93-
volatile uint32_t
94-
ticks; /* Global system tick counter, incremented by timer ISR */
105+
list_t *timer_list; /* List of active software timers */
106+
volatile uint32_t ticks; /* Global system tick, incremented by timer */
95107
} kcb_t;
96108

97109
/* Global pointer to the singleton Kernel Control Block */

0 commit comments

Comments
 (0)