-
Notifications
You must be signed in to change notification settings - Fork 185
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
kern: stack watermark support #1956
base: master
Are you sure you want to change the base?
Conversation
sys/kern/src/arch/arm_m.rs
Outdated
let current = CURRENT_TASK_PTR.load(Ordering::Relaxed); | ||
uassert!(!current.is_null()); // irq before kernel started? | ||
|
||
let current_prio = { |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, very straightforward! Looks good to me once Clippy is made happy again.
|
||
// We don't need the current task pointer in this routine, but we'll access | ||
// it briefly to update the stack watermark: | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i wonder if this whole block should be conditional on the feature flag? I see that update_stack_watermark
is a nop if the feature isn't enabled, and the compiler is probably smart enough to eliminate the CURRENT_TASK_PTR
access when the function that's called on it doesn't do anything, but... I just kinda don't trust it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was trying to make as little code conditional as possible, so that it always gets compiled; this is why it's only the body of update_watermark that's cfg'd. The compiler does appear to optimize this load out, fwiw.
sys/kern/src/task.rs
Outdated
@@ -49,6 +49,20 @@ pub struct Task { | |||
/// Pointer to the ROM descriptor used to create this task, so it can be | |||
/// restarted. | |||
descriptor: &'static TaskDesc, | |||
|
|||
/// Tracks the lowest stack pointer value (e.g. fullest stack) observed on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Vibes – I'd vote to put this into a separate object with helper functions, e.g.
#[cfg(feature = "stack-watermark")]
struct StackWatermark {
/// Tracks the lowest stack pointer value (e.g. fullest stack) observed on
/// any kernel entry for this instance of this task.
///
/// Initialized to `u32::MAX` if the task has not yet run.
#[cfg(feature = "stack-watermark")]
stack_pointer_low: u32,
/// Tracks the lowest stack pointer value (e.g. fullest stack) observed on
/// any kernel entry across *any* instance of this task.
///
/// Initialized to `u32::MAX` if the task has not yet run.
#[cfg(feature = "stack-watermark")]
past_stack_pointer_low: u32,
}
#[cfg(feature = "stack-watermark")]
impl Default for StackWatermark {
fn default() -> Self {
StackWatermark {
stack_pointer_low: u32::MAX,
past_stack_pointer_low: u32::MAX,
}
}
}
#[cfg(feature = "stack-watermark")]
impl StackWatermark {
fn reinitialize() {
self.past_stack_pointer_low =
u32::min(self.past_stack_pointer_low, self.stack_pointer_low);
self.stack_pointer_low = u32::MAX;
}
fn update(&mut self, stack_pointer: u32) {
self.stack_pointer_low =
u32::min(self.stack_pointer_low, self.save().stack_pointer());
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sold.
sys/kern/src/arch/arm_m.rs
Outdated
@@ -1108,6 +1119,14 @@ pub unsafe extern "C" fn DefaultHandler() { | |||
ipsr & 0x1FF | |||
}; | |||
|
|||
let current = CURRENT_TASK_PTR.load(Ordering::Relaxed); | |||
uassert!(!current.is_null()); // irq before kernel started? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: why is this chunk of code different from the diff above, with the uassert!
and no safety comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Probably some historical reason and/or author-in-a-hurry. I'll take a pass over it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, I have rearranged the code and added more explanatory comments. Will post the new commits shortly.
Each task has grown a new field, `low_stack_pointer`, that tracks the lowest stack pointer value seen so far (because stacks grow down). We update this value on any kernel entry (interrupt, timer, fault, syscall), so while we will miss very brief excursions of stack _between_ syscalls or interrupts, we should still get a useful value. In addition, the field `past_low_stack_pointer` tracks the lowest stack pointer value across _all previous incarnations_ of the task. This way if the task is periodically restarting, we can still get useful stack stats, including at stack overflow.
b885386
to
5b7b031
Compare
Alright, pushed fixes for your comments, PTAL! |
Each task has grown a new field,
low_stack_pointer
, that tracks the lowest stack pointer value seen so far (because stacks grow down). We update this value on any kernel entry (interrupt, timer, fault, syscall), so while we will miss very brief excursions of stack between syscalls or interrupts, we should still get a useful value.In addition, the field
past_low_stack_pointer
tracks the lowest stack pointer value across all previous incarnations of the task. This way if the task is periodically restarting, we can still get useful stack stats, including at stack overflow.All of this stuff is conditional on the
stack-watermark
feature, since it increases the kernel RAM requirement, which is explicit in Oxide's Hubris build system.