feat: selection policy in UART virtualizer#4802
Conversation
33269b3 to
2da4851
Compare
|
Thanks @frihetselsker, priority and queue managers in virtualizers is not something we've considered much so far. Before we dive into the code, may I ask to do revisit the "AI Use" section of the PR comment and, if applicable, detail whether and how you used Gen-AI to help with this PR? It's poorly worded right now, but we require checking this box even if you did not use any of these tools currently (which #4792 proposes to change). |
|
This is a long standing issue, and it's great you are looking at it. I do wonder, however, why a board would want the uart mux to prioritize apps in the order they are in the processes array (e.g., InsertionFirst) rather than round robin. Is InsertionFirst just for backwards compatibility and to not change current behavior, while still allowing RoundRobin? Or is there a specific use case you have in mind for wanting to use InsertionFirst or both for different virtualizers? I guess what I'm asking, is would it be better to just have a round robin iterator tool and just switch all capsules to use that rather than apps.each directly. |
This is not related to applications, but to the mux that serves capsules. For the UART specifically, the console capsule handles the applications order, the mux handles several capsules that require the UART.
|
Oh, right. A board could strategically assign its virtual devices in the mux, I suppose, a little bit more effectively than processes in the process array.
Personally, I don't think we ever guaranteed this behavior and I think virtualized devices should not have any guarantee about their priority. So I'm find changing the behavior. |
Even if we delete the |
Can you elaborate on that? If whoever created the first mux had implemented a generic round robin iterator that all other muxes copied, I'm dubious that anyone would now push to have the option to prioritize the first thing added to the mux. |
Sorry, I didn't check because I wasn't sure what to do since I hadn't used AI to write this code. |
The issue is more generic than having the first thing added to the mux. The idea is to allow downstream users to control the way in which the muxes select the next device. For instance, we may have capsules controlling hardware that have different priorities based on the state in which a device is. For a car, they would have to behave differently when the car is in PARK than when the car is in DRIVE. Adding the Whether we should use the |
I'm coming around to the idea of having the capability to implement dynamic list selection policies as useful. I think we should think through the trait. |
2da4851 to
1a37768
Compare
bradjc
left a comment
There was a problem hiding this comment.
We want to move forward with this approach, and we can just do the switch to round robin.
Hopefully board main.rs files don't need to change.
We do need to fix the CI test.
| /// Default policy which selects the first ready device starting from the beginning of the list. | ||
| pub struct InsertionFirstPolicy; | ||
|
|
||
| impl<I> SelectionPolicy<I> for InsertionFirstPolicy { | ||
| fn select<It>(&self, mut it: It, ready: impl Fn(&I) -> bool) -> Option<I> | ||
| where | ||
| It: Iterator<Item = I>, | ||
| { | ||
| it.find(|node| ready(node)) | ||
| } | ||
| } |
| impl Default for RoundRobinPolicy { | ||
| fn default() -> Self { | ||
| Self { | ||
| last_access_position: Cell::new(0), | ||
| } | ||
| } | ||
| } |
| pub const RX_BUF_LEN: usize = 64; | ||
|
|
||
| pub struct MuxUart<'a> { | ||
| pub struct MuxUart<'a, P: SelectionPolicy<&'a UartDevice<'a, P>> = InsertionFirstPolicy> { |
There was a problem hiding this comment.
| pub struct MuxUart<'a, P: SelectionPolicy<&'a UartDevice<'a, P>> = InsertionFirstPolicy> { | |
| pub struct MuxUart<'a, P: SelectionPolicy<&'a UartDevice<'a, P>>> { |
| /// Create a new Mux with the [`InsertionFirstPolicy`] selection policy. | ||
| pub fn new( | ||
| uart: &'a dyn uart::Uart<'a>, | ||
| buffer: &'static mut [u8], | ||
| speed: u32, | ||
| ) -> MuxUart<'a, InsertionFirstPolicy> { | ||
| MuxUart { | ||
| uart, |
There was a problem hiding this comment.
| /// Create a new Mux with the [`InsertionFirstPolicy`] selection policy. | |
| pub fn new( | |
| uart: &'a dyn uart::Uart<'a>, | |
| buffer: &'static mut [u8], | |
| speed: u32, | |
| ) -> MuxUart<'a, InsertionFirstPolicy> { | |
| MuxUart { | |
| uart, | |
| pub fn new( | |
| uart: &'a dyn uart::Uart<'a>, | |
| buffer: &'static mut [u8], | |
| speed: u32, | |
| ) -> Self { | |
| Self { | |
| uart, |
| /// | ||
| /// For the default implementation, please refer to [`MuxUart::new`] function | ||
| /// which uses [`InsertionFirstPolicy`] selection policy. | ||
| pub fn new_with_policy( |
| $P | ||
| ) | ||
| }}; | ||
| // By default, if no selection policy is provided we will use the `InsertionFirstPolicy`. |
Pull Request Overview
This pull request fixes the fairness problem of virtual devices. So far it only implements it for the UART Mux, but if approved, the same fix will be easily implemented for the rest of the affected Muxes.
The Fairness Problem
When searching for the next operation, multiplexers (except the Alarm) will always iterate the devices list from beginning to end. This means that if one device always has a job and it was inserted earlier, it will always be picked.
The following examples illustrates the problem for the UART Mux. If
debug!()is called frequently (for example in theUartMux), theDebugConsolehas a monopoly over the UART Multiplexer, as it will be the only devices chosen to print.Solution
We introduce the
SelectionPolicytrait that provides Muxes with the device selection logic. It is a generic type and should not add any overhead, neither in speed, neither in code space.We define two policies:
InsertionFirstPolicythat behaves like Muxes used to behave so far, it iterates the list from the beginning to the end. This provides backward compatibility.RoundRobinPolicythat iterates the devices list in a round robin manner. Using this policy with the previousdebug!examples allows all device to print.This solution offers a structural change that gives users the freedom to choose the policy they want. By default, the UART Mux uses the
InsertionFirstPolicyand there are no changes required in the code.Users will now able to implement their own selection policies for the UART Mux.
Testing Strategy
This pull request was tested by using a custom kernel of
qemu_rv32_virtwith UART peripheral, and three equivalent applications that try to useprintf()simultaneously.TODO or Help Wanted
Feedback
Documentation Updated
/docs, or no updates are required.We are unsure of the proper placement of the documentation in the
READMEfile. Help is needed here as well.Formatting
make prepush.AI Use
code in this PR, if any, and I have manually checked and
personally certify the entire contents of this PR.
No AI was used for this PR.