RTOS:上下文切换 - 计算 TCB 查找与内存访问
RTOS: Context Switching - Calculate TCB Lookup vs. Memory Access
目前我正在为带有 Cortex-M4 处理器的 STM32F4VE 编写一个轻量级的 RTOS。几个进程之间以round robin的方式进行上下文切换效果很好,但是尽可能优化内核机制是我的爱好。
TCB 堆叠在 SRAM 底部保留区域的顶部。
在每次上下文切换时,我都会像这样搜索下一个 TCB:
((pid + 1) * TCB_Size) + TCB_BASE_ADRESS
.
如果 pid 等于任务数量,我将其重置为 0。这是使用 if 三元运算符而不是昂贵的模运算来完成的。
切换时,例如每 8 毫秒,CPU 每次都必须执行此乘法。
我想知道在生成每个任务时预先计算这些 tcb 地址并将它们直接写入内存是否会更有效。
第二种变体将在每次上下文切换时访问内存 2 次——获取 tcb 的地址,获取 tcb。否则会有一个“昂贵”的乘法。
哪种变体更有效?
如果没有人有绝对的答案,我会重写这个概念并做一个简单的基准测试。
谢谢!
On each context switch i search the next TCB like this: ((pid + 1) * TCB_Size) + TCB_BASE_ADRESS .
就用循环链表;喜欢:
pointer_to_next_task_TCB = pointer_to_this_task_TCB->next;
switch_to_task(pointer_to_next_task_TCB);
... 其中 pointer_to_this_task_TCB
是全局变量(仅限单个 CPU)或 CPU 特定变量; switch_to_task(pointer_to_next_task_TCB);
确保 pointer_to_this_task_TCB = pointer_to_next_task_TCB;
作为任务切换的一部分(或紧随其后)完成。
请注意,当任务阻塞时(睡眠、等待磁盘 IO、等待获取互斥锁,...)您需要将它们从链表中删除以确保它们没有 CPU 时间通过调度器,然后尽快进行任务切换(在任务的时间片结束之前不会浪费 CPU 时间);当任务解除阻塞时(时间延迟到期,数据从磁盘到达,......)它们需要被插入回链表以便调度程序将再次给它们 CPU 时间,并且它们需要被插入正确的位置(列表的当前末尾)以防止拒绝 service/CPU hogs(例如,任务故意阻塞极短的时间以不断回到列表的开头并获得全新的时间切片而其他任务没有 CPU 时间)。
不要忘记,在正常情况下,大多数任务大部分时间都是阻塞的(并且它们的 TCB 大部分时间不在调度程序的链表上);并且列表几乎从不按 PID 顺序排列。
例如;如果有 100 个任务,其中 96 个被阻塞等待某事,那么调度程序的链表可能是“PID 9、PID 74、PID 31、PID 46,然后再次回到 PID 9”。
目前我正在为带有 Cortex-M4 处理器的 STM32F4VE 编写一个轻量级的 RTOS。几个进程之间以round robin的方式进行上下文切换效果很好,但是尽可能优化内核机制是我的爱好。 TCB 堆叠在 SRAM 底部保留区域的顶部。
在每次上下文切换时,我都会像这样搜索下一个 TCB:
((pid + 1) * TCB_Size) + TCB_BASE_ADRESS
.
如果 pid 等于任务数量,我将其重置为 0。这是使用 if 三元运算符而不是昂贵的模运算来完成的。
切换时,例如每 8 毫秒,CPU 每次都必须执行此乘法。 我想知道在生成每个任务时预先计算这些 tcb 地址并将它们直接写入内存是否会更有效。
第二种变体将在每次上下文切换时访问内存 2 次——获取 tcb 的地址,获取 tcb。否则会有一个“昂贵”的乘法。
哪种变体更有效? 如果没有人有绝对的答案,我会重写这个概念并做一个简单的基准测试。
谢谢!
On each context switch i search the next TCB like this: ((pid + 1) * TCB_Size) + TCB_BASE_ADRESS .
就用循环链表;喜欢:
pointer_to_next_task_TCB = pointer_to_this_task_TCB->next;
switch_to_task(pointer_to_next_task_TCB);
... 其中 pointer_to_this_task_TCB
是全局变量(仅限单个 CPU)或 CPU 特定变量; switch_to_task(pointer_to_next_task_TCB);
确保 pointer_to_this_task_TCB = pointer_to_next_task_TCB;
作为任务切换的一部分(或紧随其后)完成。
请注意,当任务阻塞时(睡眠、等待磁盘 IO、等待获取互斥锁,...)您需要将它们从链表中删除以确保它们没有 CPU 时间通过调度器,然后尽快进行任务切换(在任务的时间片结束之前不会浪费 CPU 时间);当任务解除阻塞时(时间延迟到期,数据从磁盘到达,......)它们需要被插入回链表以便调度程序将再次给它们 CPU 时间,并且它们需要被插入正确的位置(列表的当前末尾)以防止拒绝 service/CPU hogs(例如,任务故意阻塞极短的时间以不断回到列表的开头并获得全新的时间切片而其他任务没有 CPU 时间)。
不要忘记,在正常情况下,大多数任务大部分时间都是阻塞的(并且它们的 TCB 大部分时间不在调度程序的链表上);并且列表几乎从不按 PID 顺序排列。
例如;如果有 100 个任务,其中 96 个被阻塞等待某事,那么调度程序的链表可能是“PID 9、PID 74、PID 31、PID 46,然后再次回到 PID 9”。