numeric_enum_macro::numeric_enum! {
#[repr(i32)]
#[allow(non_camel_case_types)]
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum TimerType {
NONE = -1,
REAL = 0,
VIRTUAL = 1,
PROF = 2,
}
}
impl From<usize> for TimerType {
fn from(num: usize) -> Self {
match Self::try_from(num as i32) {
Ok(val) => val,
Err(_) => Self::NONE,
}
}
}
pub struct TimeStat {
utime_ns: usize,
stime_ns: usize,
user_timestamp: usize,
kernel_timestamp: usize,
timer_type: TimerType,
timer_interval_ns: usize,
timer_remained_ns: usize,
pending_timer_signal: bool,
}
impl Default for TimeStat {
fn default() -> Self {
Self::new()
}
}
impl TimeStat {
pub fn new() -> Self {
Self {
utime_ns: 0,
stime_ns: 0,
user_timestamp: 0,
kernel_timestamp: 0,
timer_type: TimerType::NONE,
timer_interval_ns: 0,
timer_remained_ns: 0,
pending_timer_signal: false,
}
}
pub fn output(&self) -> (usize, usize) {
(self.utime_ns, self.stime_ns)
}
pub fn reset(&mut self, current_timestamp: usize) {
self.utime_ns = 0;
self.stime_ns = 0;
self.user_timestamp = 0;
self.kernel_timestamp = current_timestamp;
}
pub fn switch_into_kernel_mode(&mut self, tid: isize, current_timestamp: usize) {
let now_time_ns = current_timestamp;
let delta = now_time_ns - self.user_timestamp;
self.utime_ns += delta;
self.kernel_timestamp = now_time_ns;
if self.timer_type != TimerType::NONE {
self.update_timer(delta, tid);
};
}
pub fn switch_into_user_mode(&mut self, tid: isize, current_timestamp: usize) {
let now_time_ns = current_timestamp;
let delta = now_time_ns - self.kernel_timestamp;
self.stime_ns += delta;
self.user_timestamp = now_time_ns;
if self.timer_type == TimerType::REAL || self.timer_type == TimerType::PROF {
self.update_timer(delta, tid);
};
}
pub fn swtich_from_old_task(&mut self, tid: isize, current_timestamp: usize) {
let now_time_ns = current_timestamp;
let delta = now_time_ns - self.kernel_timestamp;
self.stime_ns += delta;
self.kernel_timestamp = now_time_ns;
if self.timer_type == TimerType::REAL || self.timer_type == TimerType::PROF {
self.update_timer(delta, tid);
};
}
pub fn switch_to_new_task(&mut self, tid: isize, current_timestamp: usize) {
let now_time_ns = current_timestamp;
let delta = now_time_ns - self.kernel_timestamp;
self.kernel_timestamp = now_time_ns;
if self.timer_type == TimerType::REAL {
self.update_timer(delta, tid)
}
}
pub fn output_timer_as_us(&self) -> (usize, usize) {
(self.timer_interval_ns / 1000, self.timer_remained_ns / 1000)
}
pub fn set_timer(
&mut self,
timer_interval_ns: usize,
timer_remained_ns: usize,
timer_type: usize,
) -> bool {
self.timer_type = timer_type.into();
self.timer_interval_ns = timer_interval_ns;
self.timer_remained_ns = timer_remained_ns;
self.pending_timer_signal = false;
self.timer_type != TimerType::NONE
}
pub fn update_timer(&mut self, delta: usize, _tid: isize) {
if self.timer_remained_ns == 0 {
return;
}
if self.timer_remained_ns > delta {
self.timer_remained_ns -= delta;
return;
}
self.pending_timer_signal = true;
}
pub fn check_pending_timer_signal(&mut self) -> Option<usize> {
if self.pending_timer_signal {
self.pending_timer_signal = false;
self.timer_remained_ns = self.timer_interval_ns;
match self.timer_type {
TimerType::REAL => Some(14),
TimerType::VIRTUAL => Some(26),
TimerType::PROF => Some(27),
_ => None,
}
} else {
None
}
}
}