diff --git a/Applications/SystemMonitor/ProcessModel.cpp b/Applications/SystemMonitor/ProcessModel.cpp index 885320b30d..ac9717f1bc 100644 --- a/Applications/SystemMonitor/ProcessModel.cpp +++ b/Applications/SystemMonitor/ProcessModel.cpp @@ -355,12 +355,12 @@ void ProcessModel::update() auto previous_pid_count = m_pids.size(); auto all_processes = Core::ProcessStatisticsReader::get_all(); - unsigned last_sum_times_scheduled = 0; + u64 last_sum_ticks_scheduled = 0; for (auto& it : m_threads) - last_sum_times_scheduled += it.value->current_state.times_scheduled; + last_sum_ticks_scheduled += it.value->current_state.ticks_user + it.value->current_state.ticks_kernel; HashTable live_pids; - unsigned sum_times_scheduled = 0; + u64 sum_ticks_scheduled = 0; for (auto& it : all_processes) { for (auto& thread : it.value.threads) { ThreadState state; @@ -393,12 +393,14 @@ void ProcessModel::update() state.pgid = it.value.pgid; state.sid = it.value.sid; state.times_scheduled = thread.times_scheduled; + state.ticks_user = thread.ticks_user; + state.ticks_kernel = thread.ticks_kernel; state.cpu = thread.cpu; state.cpu_percent = 0; state.priority = thread.priority; state.effective_priority = thread.effective_priority; state.state = thread.state; - sum_times_scheduled += thread.times_scheduled; + sum_ticks_scheduled += thread.ticks_user + thread.ticks_kernel; { auto pit = m_threads.find({ it.value.pid, thread.tid }); if (pit == m_threads.end()) @@ -423,8 +425,9 @@ void ProcessModel::update() continue; } auto& process = *it.value; - u32 times_scheduled_diff = process.current_state.times_scheduled - process.previous_state.times_scheduled; - process.current_state.cpu_percent = ((float)times_scheduled_diff * 100) / (float)(sum_times_scheduled - last_sum_times_scheduled); + u32 times_scheduled_diff = (process.current_state.ticks_user + process.current_state.ticks_kernel) + - (process.previous_state.ticks_user + process.previous_state.ticks_kernel); + process.current_state.cpu_percent = ((float)times_scheduled_diff * 100) / (float)(sum_ticks_scheduled - last_sum_ticks_scheduled); if (it.key.pid != 0) { m_cpus[process.current_state.cpu].total_cpu_percent += process.current_state.cpu_percent; m_pids.append(it.key); diff --git a/Applications/SystemMonitor/ProcessModel.h b/Applications/SystemMonitor/ProcessModel.h index 921fa964c2..8739a2df69 100644 --- a/Applications/SystemMonitor/ProcessModel.h +++ b/Applications/SystemMonitor/ProcessModel.h @@ -116,6 +116,8 @@ private: pid_t pgid; pid_t sid; unsigned times_scheduled; + unsigned ticks_user; + unsigned ticks_kernel; String name; String state; String user; diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index 8c41de2106..f223f40dd3 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -884,7 +884,8 @@ static OwnPtr procfs$all(InodeIdentifier) thread_object.add("tid", thread.tid().value()); thread_object.add("name", thread.name()); thread_object.add("times_scheduled", thread.times_scheduled()); - thread_object.add("ticks", thread.ticks()); + thread_object.add("ticks_user", thread.ticks_in_user()); + thread_object.add("ticks_kernel", thread.ticks_in_kernel()); thread_object.add("state", thread.state_string()); thread_object.add("cpu", thread.cpu()); thread_object.add("priority", thread.priority()); diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 41395e311c..7283630f97 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -64,10 +64,10 @@ void Scheduler::init_thread(Thread& thread) static u32 time_slice_for(const Thread& thread) { - // One time slice unit == 1ms + // One time slice unit == 4ms (assuming 250 ticks/second) if (&thread == Processor::current().idle_thread()) return 1; - return 10; + return 2; } Thread* g_finalizer; @@ -219,6 +219,7 @@ bool Scheduler::pick_next() // but since we're still holding the scheduler lock we're still in a critical section critical.leave(); + thread_to_schedule->set_ticks_left(time_slice_for(*thread_to_schedule)); return context_switch(thread_to_schedule); } @@ -317,7 +318,6 @@ bool Scheduler::donate_to(RefPtr& beneficiary, const char* reason) bool Scheduler::context_switch(Thread* thread) { - thread->set_ticks_left(time_slice_for(*thread)); thread->did_schedule(); auto from_thread = Thread::current(); @@ -480,7 +480,7 @@ void Scheduler::timer_tick(const RegisterState& regs) } } - if (current_thread->tick()) + if (current_thread->tick((regs.cs & 3) == 0)) return; ASSERT_INTERRUPTS_DISABLED(); diff --git a/Kernel/Syscalls/alarm.cpp b/Kernel/Syscalls/alarm.cpp index f740fd0c47..8282572acc 100644 --- a/Kernel/Syscalls/alarm.cpp +++ b/Kernel/Syscalls/alarm.cpp @@ -46,9 +46,9 @@ unsigned Process::sys$alarm(unsigned seconds) } if (seconds > 0) { - auto deadline = TimeManagement::the().current_time(CLOCK_REALTIME).value(); + auto deadline = TimeManagement::the().current_time(CLOCK_REALTIME_COARSE).value(); timespec_add(deadline, { seconds, 0 }, deadline); - m_alarm_timer = TimerQueue::the().add_timer_without_id(CLOCK_REALTIME, deadline, [this]() { + m_alarm_timer = TimerQueue::the().add_timer_without_id(CLOCK_REALTIME_COARSE, deadline, [this]() { [[maybe_unused]] auto rc = send_signal(SIGALRM, nullptr); }); } diff --git a/Kernel/Syscalls/clock.cpp b/Kernel/Syscalls/clock.cpp index a48c2df98a..c28552953d 100644 --- a/Kernel/Syscalls/clock.cpp +++ b/Kernel/Syscalls/clock.cpp @@ -78,25 +78,21 @@ int Process::sys$clock_nanosleep(Userspacesleep_until(params.clock_id, requested_sleep).was_interrupted(); - } else { - timespec remaining_sleep; - was_interrupted = Thread::current()->sleep(params.clock_id, requested_sleep, &remaining_sleep).was_interrupted(); - if (was_interrupted && params.remaining_sleep && !copy_to_user(params.remaining_sleep, &remaining_sleep)) - return -EFAULT; - } - if (was_interrupted) - return -EINTR; - return 0; - } - default: + if (!TimeManagement::is_valid_clock_id(params.clock_id)) return -EINVAL; + + bool was_interrupted; + if (is_absolute) { + was_interrupted = Thread::current()->sleep_until(params.clock_id, requested_sleep).was_interrupted(); + } else { + timespec remaining_sleep; + was_interrupted = Thread::current()->sleep(params.clock_id, requested_sleep, &remaining_sleep).was_interrupted(); + if (was_interrupted && params.remaining_sleep && !copy_to_user(params.remaining_sleep, &remaining_sleep)) + return -EFAULT; } + if (was_interrupted) + return -EINTR; + return 0; } int Process::sys$adjtime(Userspace user_delta, Userspace user_old_delta) diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index a863780586..ddc8e8b001 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -400,13 +400,15 @@ void Thread::finalize_dying_threads() } } -bool Thread::tick() +bool Thread::tick(bool in_kernel) { - ++m_ticks; - if (tss().cs & 3) - ++m_process->m_ticks_in_user; - else + if (in_kernel) { ++m_process->m_ticks_in_kernel; + ++m_ticks_in_kernel; + } else { + ++m_process->m_ticks_in_user; + ++m_ticks_in_user; + } return --m_ticks_left; } diff --git a/Kernel/Thread.h b/Kernel/Thread.h index 5a1c51702c..77c543872e 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -211,7 +211,7 @@ public: : m_infinite(true) { } - explicit BlockTimeout(bool is_absolute, const timeval* time, const timespec* start_time = nullptr, clockid_t clock_id = CLOCK_MONOTONIC) + explicit BlockTimeout(bool is_absolute, const timeval* time, const timespec* start_time = nullptr, clockid_t clock_id = CLOCK_MONOTONIC_COARSE) : m_clock_id(clock_id) , m_infinite(!time) { @@ -225,7 +225,7 @@ public: timespec_add(m_time, m_start_time, m_time); } } - explicit BlockTimeout(bool is_absolute, const timespec* time, const timespec* start_time = nullptr, clockid_t clock_id = CLOCK_MONOTONIC) + explicit BlockTimeout(bool is_absolute, const timespec* time, const timespec* start_time = nullptr, clockid_t clock_id = CLOCK_MONOTONIC_COARSE) : m_clock_id(clock_id) , m_infinite(!time) { @@ -249,7 +249,7 @@ public: private: timespec m_time { 0, 0 }; timespec m_start_time { 0, 0 }; - clockid_t m_clock_id { CLOCK_MONOTONIC }; + clockid_t m_clock_id { CLOCK_MONOTONIC_COARSE }; bool m_infinite { false }; bool m_should_block { false }; }; @@ -756,7 +756,6 @@ public: const TSS32& tss() const { return m_tss; } State state() const { return m_state; } const char* state_string() const; - u32 ticks() const { return m_ticks; } VirtualAddress thread_specific_data() const { return m_thread_specific_data; } size_t thread_specific_region_size() const { return m_thread_specific_region_size; } @@ -921,12 +920,12 @@ public: BlockResult sleep(clockid_t, const timespec&, timespec* = nullptr); BlockResult sleep(const timespec& duration, timespec* remaining_time = nullptr) { - return sleep(CLOCK_MONOTONIC, duration, remaining_time); + return sleep(CLOCK_MONOTONIC_COARSE, duration, remaining_time); } BlockResult sleep_until(clockid_t, const timespec&); BlockResult sleep_until(const timespec& duration) { - return sleep_until(CLOCK_MONOTONIC, duration); + return sleep_until(CLOCK_MONOTONIC_COARSE, duration); } // Tell this thread to unblock if needed, @@ -937,7 +936,7 @@ public: void exit(void* = nullptr); - bool tick(); + bool tick(bool in_kernel); void set_ticks_left(u32 t) { m_ticks_left = t; } u32 ticks_left() const { return m_ticks_left; } @@ -1070,6 +1069,9 @@ public: static constexpr u32 default_kernel_stack_size = 65536; static constexpr u32 default_userspace_stack_size = 4 * MiB; + u32 ticks_in_user() const { return m_ticks_in_user; } + u32 ticks_in_kernel() const { return m_ticks_in_kernel; } + RecursiveSpinLock& get_lock() const { return m_lock; } #ifdef LOCK_DEBUG @@ -1188,9 +1190,10 @@ private: TSS32 m_tss; Atomic m_cpu { 0 }; u32 m_cpu_affinity { THREAD_AFFINITY_DEFAULT }; - u32 m_ticks { 0 }; u32 m_ticks_left { 0 }; u32 m_times_scheduled { 0 }; + u32 m_ticks_in_user { 0 }; + u32 m_ticks_in_kernel { 0 }; u32 m_pending_signals { 0 }; u32 m_signal_mask { 0 }; u32 m_kernel_stack_base { 0 }; diff --git a/Kernel/Time/APICTimer.h b/Kernel/Time/APICTimer.h index 15f12a31b1..7e9b24e630 100644 --- a/Kernel/Time/APICTimer.h +++ b/Kernel/Time/APICTimer.h @@ -44,6 +44,7 @@ public: virtual bool is_periodic_capable() const override { return true; } virtual void set_periodic() override; virtual void set_non_periodic() override; + virtual void disable() override { } virtual void reset_to_default_ticks_per_second() override; virtual bool try_to_set_frequency(size_t frequency) override; diff --git a/Kernel/Time/HPET.cpp b/Kernel/Time/HPET.cpp index ed4c5a5e1c..12014476bd 100644 --- a/Kernel/Time/HPET.cpp +++ b/Kernel/Time/HPET.cpp @@ -197,10 +197,14 @@ void HPET::update_periodic_comparator_value() auto& regs = registers(); u64 previous_main_value = (u64)regs.main_counter_value.low | ((u64)regs.main_counter_value.high << 32); + m_main_counter_drift += previous_main_value - m_main_counter_last_read; + m_main_counter_last_read = 0; regs.main_counter_value.low = 0; regs.main_counter_value.high = 0; for (auto& comparator : m_comparators) { auto& timer = regs.timers[comparator.comparator_number()]; + if (!comparator.is_enabled()) + continue; if (comparator.is_periodic()) { // Note that this means we're restarting all periodic timers. There is no // way to resume periodic timers properly because we reset the main counter @@ -242,6 +246,33 @@ void HPET::update_non_periodic_comparator_value(const HPETComparator& comparator timer.comparator_value.low = (u32)new_counter_value; } +u64 HPET::update_time(u64& seconds_since_boot, u32& ticks_this_second, bool query_only) +{ + // Should only be called by the time keeper interrupt handler! + u64 current_value = read_register_safe64(registers().main_counter_value); + u64 delta_ticks = m_main_counter_drift; + if (current_value >= m_main_counter_last_read) + delta_ticks += current_value - m_main_counter_last_read; + else + delta_ticks += m_main_counter_last_read - current_value; // the counter wrapped around + u64 ticks_since_last_second = (u64)ticks_this_second + delta_ticks; + auto ticks_per_second = frequency(); + if (ticks_since_last_second > ticks_per_second) { + seconds_since_boot += ticks_since_last_second / ticks_per_second; + ticks_this_second = ticks_since_last_second % ticks_per_second; + } else { + ticks_this_second = ticks_since_last_second; + } + + if (!query_only) { + m_main_counter_drift = 0; + m_main_counter_last_read = current_value; + } + + // Return the time passed (in ns) since last time update_time was called + return (delta_ticks * 1000000000ull) / ticks_per_second; +} + void HPET::enable_periodic_interrupt(const HPETComparator& comparator) { #ifdef HPET_DEBUG @@ -253,7 +284,8 @@ void HPET::enable_periodic_interrupt(const HPETComparator& comparator) auto capabilities = timer.capabilities; ASSERT(capabilities & (u32)HPETFlags::TimerConfiguration::PeriodicInterruptCapable); timer.capabilities = capabilities | (u32)HPETFlags::TimerConfiguration::GeneratePeriodicInterrupt; - enable(comparator); + if (comparator.is_enabled()) + enable(comparator); } void HPET::disable_periodic_interrupt(const HPETComparator& comparator) { @@ -266,7 +298,8 @@ void HPET::disable_periodic_interrupt(const HPETComparator& comparator) auto capabilities = timer.capabilities; ASSERT(capabilities & (u32)HPETFlags::TimerConfiguration::PeriodicInterruptCapable); timer.capabilities = capabilities & ~(u32)HPETFlags::TimerConfiguration::GeneratePeriodicInterrupt; - enable(comparator); + if (comparator.is_enabled()) + enable(comparator); } void HPET::disable(const HPETComparator& comparator) @@ -288,11 +321,6 @@ void HPET::enable(const HPETComparator& comparator) timer.capabilities = timer.capabilities | (u32)HPETFlags::TimerConfiguration::InterruptEnable; } -u64 HPET::frequency() const -{ - return m_frequency; -} - Vector HPET::capable_interrupt_numbers(const HPETComparator& comparator) { ASSERT(comparator.comparator_number() <= m_comparators.size()); @@ -394,7 +422,7 @@ HPET::HPET(PhysicalAddress acpi_hpet) klog() << "HPET: frequency " << m_frequency << " Hz (" << MEGAHERTZ_TO_HERTZ(m_frequency) << " MHz) resolution: " << calculate_ticks_in_nanoseconds() << "ns"; ASSERT(regs.capabilities.main_counter_tick_period <= ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD); - // Reset the counter, just in case... + // Reset the counter, just in case... (needs to match m_main_counter_last_read) regs.main_counter_value.high = 0; regs.main_counter_value.low = 0; if (regs.capabilities.attributes & (u32)HPETFlags::Attributes::LegacyReplacementRouteCapable) diff --git a/Kernel/Time/HPET.h b/Kernel/Time/HPET.h index d60adc4839..e9460d3484 100644 --- a/Kernel/Time/HPET.h +++ b/Kernel/Time/HPET.h @@ -45,7 +45,7 @@ public: static bool check_for_exisiting_periodic_timers(); static HPET& the(); - u64 frequency() const; + u64 frequency() const { return m_frequency; } const NonnullRefPtrVector& comparators() const { return m_comparators; } void disable(const HPETComparator&); @@ -59,6 +59,8 @@ public: void enable_periodic_interrupt(const HPETComparator& comparator); void disable_periodic_interrupt(const HPETComparator& comparator); + u64 update_time(u64& seconds_since_boot, u32& ticks_this_second, bool query_only); + Vector capable_interrupt_numbers(u8 comparator_number); Vector capable_interrupt_numbers(const HPETComparator&); @@ -80,7 +82,9 @@ private: PhysicalAddress m_physical_acpi_hpet_registers; OwnPtr m_hpet_mmio_region; - u64 m_main_counter_clock_period { 0 }; + u64 m_main_counter_last_read { 0 }; + u64 m_main_counter_drift { 0 }; + u16 m_vendor_id; u16 m_minimum_tick; u64 m_frequency; diff --git a/Kernel/Time/HPETComparator.cpp b/Kernel/Time/HPETComparator.cpp index f902b92ea8..9507cee02e 100644 --- a/Kernel/Time/HPETComparator.cpp +++ b/Kernel/Time/HPETComparator.cpp @@ -41,20 +41,31 @@ HPETComparator::HPETComparator(u8 number, u8 irq, bool periodic_capable) : HardwareTimer(irq) , m_periodic(false) , m_periodic_capable(periodic_capable) + , m_enabled(false) , m_comparator_number(number) { } +void HPETComparator::disable() +{ + if (!m_enabled) + return; + m_enabled = false; + HPET::the().disable(*this); +} + void HPETComparator::set_periodic() { ASSERT(m_periodic_capable); m_periodic = true; + m_enabled = true; HPET::the().enable_periodic_interrupt(*this); } void HPETComparator::set_non_periodic() { ASSERT(m_periodic_capable); m_periodic = false; + m_enabled = true; HPET::the().disable_periodic_interrupt(*this); } @@ -79,7 +90,7 @@ size_t HPETComparator::ticks_per_second() const void HPETComparator::reset_to_default_ticks_per_second() { - ASSERT(is_capable_of_frequency(OPTIMAL_TICKS_PER_SECOND_RATE)); + dbg() << "reset_to_default_ticks_per_second"; m_frequency = OPTIMAL_TICKS_PER_SECOND_RATE; if (!is_periodic()) set_new_countdown(); @@ -89,13 +100,16 @@ void HPETComparator::reset_to_default_ticks_per_second() bool HPETComparator::try_to_set_frequency(size_t frequency) { InterruptDisabler disabler; - if (!is_capable_of_frequency(frequency)) + if (!is_capable_of_frequency(frequency)) { + dbg() << "HPETComparator: not cable of frequency: " << frequency; return false; - if (m_frequency == frequency) - return true; + } + auto hpet_frequency = HPET::the().frequency(); ASSERT(frequency <= hpet_frequency); m_frequency = frequency; + m_enabled = true; + #ifdef HPET_COMPARATOR_DEBUG dbg() << "HPET Comparator: Max frequency " << hpet_frequency << " Hz, want to set " << frequency << " Hz, periodic: " << is_periodic(); #endif @@ -112,16 +126,17 @@ bool HPETComparator::is_capable_of_frequency(size_t frequency) const { if (frequency > HPET::the().frequency()) return false; - if ((HPET::the().frequency() % frequency) != 0) - return false; + // HPET::update_periodic_comparator_value and HPET::update_non_periodic_comparator_value + // calculate the best counter based on the desired frequency. return true; } size_t HPETComparator::calculate_nearest_possible_frequency(size_t frequency) const { - if (frequency >= HPET::the().frequency()) + if (frequency > HPET::the().frequency()) return HPET::the().frequency(); - // FIXME: Use better math here - return (frequency + (HPET::the().frequency() % frequency)); + // HPET::update_periodic_comparator_value and HPET::update_non_periodic_comparator_value + // calculate the best counter based on the desired frequency. + return frequency; } } diff --git a/Kernel/Time/HPETComparator.h b/Kernel/Time/HPETComparator.h index d4c79f2a0b..771eca1887 100644 --- a/Kernel/Time/HPETComparator.h +++ b/Kernel/Time/HPETComparator.h @@ -42,6 +42,7 @@ public: virtual const char* model() const override { return "HPET"; } u8 comparator_number() const { return m_comparator_number; } + bool is_enabled() const { return m_enabled; } virtual size_t ticks_per_second() const override; @@ -49,6 +50,7 @@ public: virtual bool is_periodic_capable() const override { return m_periodic_capable; } virtual void set_periodic() override; virtual void set_non_periodic() override; + virtual void disable() override; virtual void reset_to_default_ticks_per_second() override; virtual bool try_to_set_frequency(size_t frequency) override; @@ -61,7 +63,7 @@ private: HPETComparator(u8 number, u8 irq, bool periodic_capable); bool m_periodic : 1; bool m_periodic_capable : 1; - bool m_edge_triggered : 1; + bool m_enabled : 1; u8 m_comparator_number { 0 }; }; } diff --git a/Kernel/Time/HardwareTimer.h b/Kernel/Time/HardwareTimer.h index f88435ac86..5dbbb76f35 100644 --- a/Kernel/Time/HardwareTimer.h +++ b/Kernel/Time/HardwareTimer.h @@ -57,6 +57,7 @@ public: virtual bool is_periodic_capable() const = 0; virtual void set_periodic() = 0; virtual void set_non_periodic() = 0; + virtual void disable() = 0; virtual size_t ticks_per_second() const = 0; diff --git a/Kernel/Time/PIT.h b/Kernel/Time/PIT.h index b00eee520e..3a1efaa6da 100644 --- a/Kernel/Time/PIT.h +++ b/Kernel/Time/PIT.h @@ -63,6 +63,7 @@ public: virtual bool is_periodic_capable() const override { return true; } virtual void set_periodic() override; virtual void set_non_periodic() override; + virtual void disable() override { } virtual void reset_to_default_ticks_per_second() override; virtual bool try_to_set_frequency(size_t frequency) override; diff --git a/Kernel/Time/RTC.h b/Kernel/Time/RTC.h index e2427dff01..76d263be9c 100644 --- a/Kernel/Time/RTC.h +++ b/Kernel/Time/RTC.h @@ -42,6 +42,7 @@ public: virtual bool is_periodic_capable() const override { return true; } virtual void set_periodic() override { } virtual void set_non_periodic() override { } + virtual void disable() override { } virtual void reset_to_default_ticks_per_second() override; virtual bool try_to_set_frequency(size_t frequency) override; diff --git a/Kernel/Time/TimeManagement.cpp b/Kernel/Time/TimeManagement.cpp index bcf0d8f8ea..d255b87fe7 100644 --- a/Kernel/Time/TimeManagement.cpp +++ b/Kernel/Time/TimeManagement.cpp @@ -52,13 +52,33 @@ TimeManagement& TimeManagement::the() return *s_the; } +bool TimeManagement::is_valid_clock_id(clockid_t clock_id) +{ + switch (clock_id) { + case CLOCK_MONOTONIC: + case CLOCK_MONOTONIC_COARSE: + case CLOCK_MONOTONIC_RAW: + case CLOCK_REALTIME: + case CLOCK_REALTIME_COARSE: + return true; + default: + return false; + }; +} + KResultOr TimeManagement::current_time(clockid_t clock_id) const { switch (clock_id) { case CLOCK_MONOTONIC: - return monotonic_time(); + return monotonic_time(TimePrecision::Precise); + case CLOCK_MONOTONIC_COARSE: + return monotonic_time(TimePrecision::Coarse); + case CLOCK_MONOTONIC_RAW: + return monotonic_time_raw(); case CLOCK_REALTIME: - return epoch_time(); + return epoch_time(TimePrecision::Precise); + case CLOCK_REALTIME_COARSE: + return epoch_time(TimePrecision::Coarse); default: return KResult(EINVAL); } @@ -69,22 +89,6 @@ bool TimeManagement::is_system_timer(const HardwareTimerBase& timer) const return &timer == m_system_timer.ptr(); } -timespec TimeManagement::ticks_to_time(u64 ticks, time_t ticks_per_second) -{ - timespec tspec; - tspec.tv_sec = ticks / ticks_per_second; - tspec.tv_nsec = (ticks % ticks_per_second) * (1'000'000'000 / ticks_per_second); - ASSERT(tspec.tv_nsec <= 1'000'000'000); - return tspec; -} - -u64 TimeManagement::time_to_ticks(const timespec& tspec, time_t ticks_per_second) -{ - u64 ticks = (u64)tspec.tv_sec * ticks_per_second; - ticks += ((u64)tspec.tv_nsec * ticks_per_second) / 1'000'000'000; - return ticks; -} - void TimeManagement::set_epoch_time(timespec ts) { InterruptDisabler disabler; @@ -92,27 +96,40 @@ void TimeManagement::set_epoch_time(timespec ts) m_remaining_epoch_time_adjustment = { 0, 0 }; } -u64 TimeManagement::monotonic_ticks() const +timespec TimeManagement::monotonic_time(TimePrecision precision) const { - long seconds; - u64 ticks; + // This is the time when last updated by an interrupt. + u64 seconds; + u32 ticks; + + bool do_query = precision == TimePrecision::Precise && m_can_query_precise_time; u32 update_iteration; do { update_iteration = m_update1.load(AK::MemoryOrder::memory_order_acquire); seconds = m_seconds_since_boot; ticks = m_ticks_this_second; + + if (do_query) { + // We may have to do this over again if the timer interrupt fires + // while we're trying to query the information. In that case, our + // seconds and ticks became invalid, producing an incorrect time. + // Be sure to not modify m_seconds_since_boot and m_ticks_this_second + // because this may only be modified by the interrupt handler + HPET::the().update_time(seconds, ticks, true); + } } while (update_iteration != m_update2.load(AK::MemoryOrder::memory_order_acquire)); - return ticks + (u64)seconds * (u64)ticks_per_second(); + + ASSERT(m_time_ticks_per_second > 0); + ASSERT(ticks < m_time_ticks_per_second); + u64 ns = ((u64)ticks * 1000000000ull) / m_time_ticks_per_second; + ASSERT(ns < 1000000000ull); + return { (long)seconds, (long)ns }; } -timespec TimeManagement::monotonic_time() const -{ - return ticks_to_time(monotonic_ticks(), ticks_per_second()); -} - -timespec TimeManagement::epoch_time() const +timespec TimeManagement::epoch_time(TimePrecision) const { + // TODO: Take into account precision timespec ts; u32 update_iteration; do { @@ -155,7 +172,9 @@ void TimeManagement::initialize(u32 cpu) void TimeManagement::set_system_timer(HardwareTimerBase& timer) { + ASSERT(Processor::current().id() == 0); // This should only be called on the BSP! auto original_callback = m_system_timer->set_callback(nullptr); + m_system_timer->disable(); timer.set_callback(move(original_callback)); m_system_timer = timer; } @@ -259,28 +278,36 @@ bool TimeManagement::probe_and_set_non_legacy_hardware_timers() if (is_hpet_periodic_mode_allowed()) ASSERT(!periodic_timers.is_empty()); - ASSERT(periodic_timers.size() + non_periodic_timers.size() >= 2); + ASSERT(periodic_timers.size() + non_periodic_timers.size() > 0); - if (periodic_timers.size() >= 2) { - m_time_keeper_timer = periodic_timers[1]; + if (periodic_timers.size() > 0) m_system_timer = periodic_timers[0]; - } else { - if (periodic_timers.size() == 1) { - m_time_keeper_timer = periodic_timers[0]; - m_system_timer = non_periodic_timers[0]; - } else { - m_time_keeper_timer = non_periodic_timers[1]; - m_system_timer = non_periodic_timers[0]; + else + m_system_timer = non_periodic_timers[0]; + + m_system_timer->set_callback([this](const RegisterState& regs) { + // Update the time. We don't really care too much about the + // frequency of the interrupt because we'll query the main + // counter to get an accurate time. + if (Processor::current().id() == 0) { + // TODO: Have the other CPUs call system_timer_tick directly + increment_time_since_boot_hpet(); } - } - m_system_timer->set_callback(TimeManagement::timer_tick); - m_time_keeper_timer->set_callback(TimeManagement::update_time); + system_timer_tick(regs); + }); - dbg() << "Reset timers"; - m_system_timer->try_to_set_frequency(m_system_timer->calculate_nearest_possible_frequency(1024)); - m_time_keeper_timer->try_to_set_frequency(OPTIMAL_TICKS_PER_SECOND_RATE); + // Use the HPET main counter frequency for time purposes. This is likely + // a much higher frequency than the interrupt itself and allows us to + // keep a more accurate time + m_can_query_precise_time = true; + m_time_ticks_per_second = HPET::the().frequency(); + m_system_timer->try_to_set_frequency(m_system_timer->calculate_nearest_possible_frequency(OPTIMAL_TICKS_PER_SECOND_RATE)); + + // We don't need an interrupt for time keeping purposes because we + // can query the timer. + m_time_keeper_timer = m_system_timer; return true; } @@ -296,18 +323,43 @@ bool TimeManagement::probe_and_set_legacy_hardware_timers() } m_hardware_timers.append(PIT::initialize(TimeManagement::update_time)); - m_hardware_timers.append(RealTimeClock::create(TimeManagement::timer_tick)); + m_hardware_timers.append(RealTimeClock::create(TimeManagement::system_timer_tick)); m_time_keeper_timer = m_hardware_timers[0]; m_system_timer = m_hardware_timers[1]; + + // The timer is only as accurate as the interrupts... + m_time_ticks_per_second = m_time_keeper_timer->ticks_per_second(); return true; } -void TimeManagement::update_time(const RegisterState& regs) +void TimeManagement::update_time(const RegisterState&) { - TimeManagement::the().increment_time_since_boot(regs); + TimeManagement::the().increment_time_since_boot(); } -void TimeManagement::increment_time_since_boot(const RegisterState&) +void TimeManagement::increment_time_since_boot_hpet() +{ + ASSERT(!m_time_keeper_timer.is_null()); + ASSERT(m_time_keeper_timer->timer_type() == HardwareTimerType::HighPrecisionEventTimer); + + // NOTE: m_seconds_since_boot and m_ticks_this_second are only ever + // updated here! So we can safely read that information, query the clock, + // and when we're all done we can update the information. This reduces + // contention when other processors attempt to read the clock. + auto seconds_since_boot = m_seconds_since_boot; + auto ticks_this_second = m_ticks_this_second; + auto delta_ns = HPET::the().update_time(seconds_since_boot, ticks_this_second, false); + + // Now that we have a precise time, go update it as quickly as we can + u32 update_iteration = m_update1.fetch_add(1, AK::MemoryOrder::memory_order_acquire); + m_seconds_since_boot = seconds_since_boot; + m_ticks_this_second = ticks_this_second; + // TODO: Apply m_remaining_epoch_time_adjustment + timespec_add(m_epoch_time, { (time_t)(delta_ns / 1000000000), (long)(delta_ns % 1000000000) }, m_epoch_time); + m_update2.store(update_iteration + 1, AK::MemoryOrder::memory_order_release); +} + +void TimeManagement::increment_time_since_boot() { ASSERT(!m_time_keeper_timer.is_null()); @@ -318,7 +370,7 @@ void TimeManagement::increment_time_since_boot(const RegisterState&) constexpr time_t MaxSlewNanos = NanosPerTick / 100; static_assert(MaxSlewNanos < NanosPerTick); - u32 update_iteration = m_update1.fetch_add(1, AK::MemoryOrder::memory_order_relaxed); + u32 update_iteration = m_update1.fetch_add(1, AK::MemoryOrder::memory_order_acquire); // Clamp twice, to make sure intermediate fits into a long. long slew_nanos = clamp(clamp(m_remaining_epoch_time_adjustment.tv_sec, (time_t)-1, (time_t)1) * 1'000'000'000 + m_remaining_epoch_time_adjustment.tv_nsec, -MaxSlewNanos, MaxSlewNanos); @@ -338,7 +390,7 @@ void TimeManagement::increment_time_since_boot(const RegisterState&) m_update2.store(update_iteration + 1, AK::MemoryOrder::memory_order_release); } -void TimeManagement::timer_tick(const RegisterState& regs) +void TimeManagement::system_timer_tick(const RegisterState& regs) { if (Processor::current().in_irq() <= 1) { // Don't expire timers while handling IRQs diff --git a/Kernel/Time/TimeManagement.h b/Kernel/Time/TimeManagement.h index 009f345742..bed0fd281d 100644 --- a/Kernel/Time/TimeManagement.h +++ b/Kernel/Time/TimeManagement.h @@ -34,10 +34,15 @@ namespace Kernel { -#define OPTIMAL_TICKS_PER_SECOND_RATE 1000 +#define OPTIMAL_TICKS_PER_SECOND_RATE 250 class HardwareTimerBase; +enum class TimePrecision { + Coarse = 0, + Precise +}; + class TimeManagement { AK_MAKE_ETERNAL; @@ -47,12 +52,15 @@ public: static void initialize(u32 cpu); static TimeManagement& the(); - static timespec ticks_to_time(u64 ticks, time_t ticks_per_second); - static u64 time_to_ticks(const timespec& tspec, time_t ticks_per_second); - - KResultOr current_time(clockid_t clock_id) const; - timespec monotonic_time() const; - timespec epoch_time() const; + static bool is_valid_clock_id(clockid_t); + KResultOr current_time(clockid_t) const; + timespec monotonic_time(TimePrecision = TimePrecision::Coarse) const; + timespec monotonic_time_raw() const + { + // TODO: implement + return monotonic_time(TimePrecision::Precise); + } + timespec epoch_time(TimePrecision = TimePrecision::Precise) const; void set_epoch_time(timespec); time_t ticks_per_second() const; time_t boot_time() const; @@ -60,12 +68,13 @@ public: bool is_system_timer(const HardwareTimerBase&) const; static void update_time(const RegisterState&); - void increment_time_since_boot(const RegisterState&); + static void update_time_hpet(const RegisterState&); + void increment_time_since_boot_hpet(); + void increment_time_since_boot(); static bool is_hpet_periodic_mode_allowed(); u64 uptime_ms() const; - u64 monotonic_ticks() const; static timeval now_as_timeval(); timespec remaining_epoch_time_adjustment() const { return m_remaining_epoch_time_adjustment; } @@ -78,16 +87,19 @@ private: Vector scan_for_non_periodic_timers(); NonnullRefPtrVector m_hardware_timers; void set_system_timer(HardwareTimerBase&); - static void timer_tick(const RegisterState&); + static void system_timer_tick(const RegisterState&); // Variables between m_update1 and m_update2 are synchronized Atomic m_update1 { 0 }; u32 m_ticks_this_second { 0 }; - u32 m_seconds_since_boot { 0 }; + u64 m_seconds_since_boot { 0 }; timespec m_epoch_time { 0, 0 }; timespec m_remaining_epoch_time_adjustment { 0, 0 }; Atomic m_update2 { 0 }; + u32 m_time_ticks_per_second { 0 }; // may be different from interrupts/second (e.g. hpet) + bool m_can_query_precise_time { false }; + RefPtr m_system_timer; RefPtr m_time_keeper_timer; }; diff --git a/Kernel/TimerQueue.cpp b/Kernel/TimerQueue.cpp index a14058ebcf..1e9face90f 100644 --- a/Kernel/TimerQueue.cpp +++ b/Kernel/TimerQueue.cpp @@ -38,16 +38,45 @@ namespace Kernel { static AK::Singleton s_the; static SpinLock g_timerqueue_lock; +ALWAYS_INLINE static u64 time_to_ns(const timespec& ts) +{ + return (u64)ts.tv_sec * 1000000000ull + ts.tv_nsec; +} + +ALWAYS_INLINE static timespec ns_to_time(u64 ns) +{ + return { (time_t)(ns / 1000000000ull), (long)(ns % 1000000000ull) }; +} + timespec Timer::remaining() const { if (m_remaining == 0) return {}; - return TimerQueue::the().ticks_to_time(m_clock_id, m_remaining); + return ns_to_time(m_remaining); } -u64 Timer::now() const +u64 Timer::now(bool is_firing) const { - return TimerQueue::the().time_to_ticks(m_clock_id, TimeManagement::the().current_time(m_clock_id).value()); + // NOTE: If is_firing is true then TimePrecision::Precise isn't really useful here. + // We already have a quite precise time stamp because we just updated the time in the + // interrupt handler. In those cases, just use coarse timestamps. + auto clock_id = m_clock_id; + if (is_firing) { + switch (clock_id) { + case CLOCK_MONOTONIC: + clock_id = CLOCK_MONOTONIC_COARSE; + break; + case CLOCK_MONOTONIC_RAW: + // TODO: use a special CLOCK_MONOTONIC_RAW_COARSE like mechanism here + break; + case CLOCK_REALTIME: + clock_id = CLOCK_REALTIME_COARSE; + break; + default: + break; + } + } + return time_to_ns(TimeManagement::the().current_time(clock_id).value()); } TimerQueue& TimerQueue::the() @@ -70,7 +99,7 @@ RefPtr TimerQueue::add_timer_without_id(clockid_t clock_id, const timespe // *must* be a RefPtr. Otherwise calling cancel_timer() could // inadvertently cancel another timer that has been created between // returning from the timer handler and a call to cancel_timer(). - auto timer = adopt(*new Timer(clock_id, time_to_ticks(clock_id, deadline), move(callback))); + auto timer = adopt(*new Timer(clock_id, time_to_ns(deadline), move(callback))); ScopedSpinLock lock(g_timerqueue_lock); timer->m_id = 0; // Don't generate a timer id @@ -91,7 +120,6 @@ TimerId TimerQueue::add_timer(NonnullRefPtr&& timer) void TimerQueue::add_timer_locked(NonnullRefPtr timer) { u64 timer_expiration = timer->m_expires; - ASSERT(timer_expiration >= time_to_ticks(timer->m_clock_id, TimeManagement::the().current_time(timer->m_clock_id).value())); ASSERT(!timer->is_queued()); @@ -123,43 +151,7 @@ TimerId TimerQueue::add_timer(clockid_t clock_id, timeval& deadline, Function now) timer.m_remaining = timer.m_expires - now; @@ -270,7 +262,7 @@ void TimerQueue::fire() ASSERT(timer); ASSERT(queue.next_timer_due == timer->m_expires); - while (timer && timer->now() > timer->m_expires) { + while (timer && timer->now(true) > timer->m_expires) { queue.list.remove(timer); timer->set_queued(false); diff --git a/Kernel/TimerQueue.h b/Kernel/TimerQueue.h index f4eda76c41..a70911e972 100644 --- a/Kernel/TimerQueue.h +++ b/Kernel/TimerQueue.h @@ -80,7 +80,7 @@ private: } bool is_queued() const { return m_queued.load(AK::MemoryOrder::memory_order_relaxed); } void set_queued(bool queued) { m_queued.store(queued, AK::MemoryOrder::memory_order_relaxed); } - u64 now() const; + u64 now(bool) const; }; class TimerQueue { @@ -114,17 +114,17 @@ private: { switch (timer.m_clock_id) { case CLOCK_MONOTONIC: + case CLOCK_MONOTONIC_COARSE: + case CLOCK_MONOTONIC_RAW: return m_timer_queue_monotonic; case CLOCK_REALTIME: + case CLOCK_REALTIME_COARSE: return m_timer_queue_realtime; default: ASSERT_NOT_REACHED(); } } - timespec ticks_to_time(clockid_t, u64 ticks) const; - u64 time_to_ticks(clockid_t, const timespec&) const; - u64 m_timer_id_count { 0 }; u64 m_ticks_per_second { 0 }; Queue m_timer_queue_monotonic; diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h index d942603044..02af314b50 100644 --- a/Kernel/UnixTypes.h +++ b/Kernel/UnixTypes.h @@ -548,6 +548,9 @@ typedef int clockid_t; #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 1 +#define CLOCK_MONOTONIC_RAW 4 +#define CLOCK_REALTIME_COARSE 5 +#define CLOCK_MONOTONIC_COARSE 6 #define TIMER_ABSTIME 99 #define UTSNAME_ENTRY_LEN 65 diff --git a/Libraries/LibC/time.h b/Libraries/LibC/time.h index 24c1c10b83..05fcb883d3 100644 --- a/Libraries/LibC/time.h +++ b/Libraries/LibC/time.h @@ -72,6 +72,9 @@ typedef int clockid_t; #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 1 +#define CLOCK_MONOTONIC_RAW 4 +#define CLOCK_REALTIME_COARSE 5 +#define CLOCK_MONOTONIC_COARSE 6 #define TIMER_ABSTIME 99 int clock_gettime(clockid_t, struct timespec*); diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index edcedd20de..65a74f54b5 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -339,7 +339,7 @@ char* getwd(char* buf) int sleep(unsigned seconds) { struct timespec ts = { seconds, 0 }; - if (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, nullptr) < 0) + if (clock_nanosleep(CLOCK_MONOTONIC_COARSE, 0, &ts, nullptr) < 0) return ts.tv_sec; return 0; } @@ -347,7 +347,7 @@ int sleep(unsigned seconds) int usleep(useconds_t usec) { struct timespec ts = { (long)(usec / 1000000), (long)(usec % 1000000) * 1000 }; - return clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, nullptr); + return clock_nanosleep(CLOCK_MONOTONIC_COARSE, 0, &ts, nullptr); } int gethostname(char* buffer, size_t size) diff --git a/Libraries/LibCore/ElapsedTimer.cpp b/Libraries/LibCore/ElapsedTimer.cpp index 1d7d37009d..9d0fc95378 100644 --- a/Libraries/LibCore/ElapsedTimer.cpp +++ b/Libraries/LibCore/ElapsedTimer.cpp @@ -36,7 +36,7 @@ void ElapsedTimer::start() { m_valid = true; timespec now_spec; - clock_gettime(CLOCK_MONOTONIC, &now_spec); + clock_gettime(m_precise ? CLOCK_MONOTONIC : CLOCK_MONOTONIC_COARSE, &now_spec); m_origin_time.tv_sec = now_spec.tv_sec; m_origin_time.tv_usec = now_spec.tv_nsec / 1000; } @@ -46,7 +46,7 @@ int ElapsedTimer::elapsed() const ASSERT(is_valid()); struct timeval now; timespec now_spec; - clock_gettime(CLOCK_MONOTONIC, &now_spec); + clock_gettime(m_precise ? CLOCK_MONOTONIC : CLOCK_MONOTONIC_COARSE, &now_spec); now.tv_sec = now_spec.tv_sec; now.tv_usec = now_spec.tv_nsec / 1000; struct timeval diff; diff --git a/Libraries/LibCore/ElapsedTimer.h b/Libraries/LibCore/ElapsedTimer.h index 4759c0ede0..224eb139e3 100644 --- a/Libraries/LibCore/ElapsedTimer.h +++ b/Libraries/LibCore/ElapsedTimer.h @@ -32,7 +32,10 @@ namespace Core { class ElapsedTimer { public: - ElapsedTimer() { } + ElapsedTimer(bool precise = false) + : m_precise(precise) + { + } bool is_valid() const { return m_valid; } void start(); @@ -41,6 +44,7 @@ public: const struct timeval& origin_time() const { return m_origin_time; } private: + bool m_precise { false }; bool m_valid { false }; struct timeval m_origin_time { 0, 0 diff --git a/Libraries/LibCore/EventLoop.cpp b/Libraries/LibCore/EventLoop.cpp index 646e8d3e8c..4e45d3852f 100644 --- a/Libraries/LibCore/EventLoop.cpp +++ b/Libraries/LibCore/EventLoop.cpp @@ -580,7 +580,7 @@ retry: auto next_timer_expiration = get_next_timer_expiration(); if (next_timer_expiration.has_value()) { timespec now_spec; - clock_gettime(CLOCK_MONOTONIC, &now_spec); + clock_gettime(CLOCK_MONOTONIC_COARSE, &now_spec); now.tv_sec = now_spec.tv_sec; now.tv_usec = now_spec.tv_nsec / 1000; timeval_sub(next_timer_expiration.value(), now, timeout); @@ -631,7 +631,7 @@ try_select_again: if (!s_timers->is_empty()) { timespec now_spec; - clock_gettime(CLOCK_MONOTONIC, &now_spec); + clock_gettime(CLOCK_MONOTONIC_COARSE, &now_spec); now.tv_sec = now_spec.tv_sec; now.tv_usec = now_spec.tv_nsec / 1000; } @@ -709,7 +709,7 @@ int EventLoop::register_timer(Object& object, int milliseconds, bool should_relo timer->interval = milliseconds; timeval now; timespec now_spec; - clock_gettime(CLOCK_MONOTONIC, &now_spec); + clock_gettime(CLOCK_MONOTONIC_COARSE, &now_spec); now.tv_sec = now_spec.tv_sec; now.tv_usec = now_spec.tv_nsec / 1000; timer->reload(now); diff --git a/Libraries/LibCore/ProcessStatisticsReader.cpp b/Libraries/LibCore/ProcessStatisticsReader.cpp index 69928d5b46..5a0ff949c6 100644 --- a/Libraries/LibCore/ProcessStatisticsReader.cpp +++ b/Libraries/LibCore/ProcessStatisticsReader.cpp @@ -85,7 +85,8 @@ HashMap ProcessStatisticsReader::get_all() thread.times_scheduled = thread_object.get("times_scheduled").to_u32(); thread.name = thread_object.get("name").to_string(); thread.state = thread_object.get("state").to_string(); - thread.ticks = thread_object.get("ticks").to_u32(); + thread.ticks_user = thread_object.get("ticks_user").to_u32(); + thread.ticks_kernel = thread_object.get("ticks_kernel").to_u32(); thread.cpu = thread_object.get("cpu").to_u32(); thread.priority = thread_object.get("priority").to_u32(); thread.effective_priority = thread_object.get("effective_priority").to_u32(); diff --git a/Libraries/LibCore/ProcessStatisticsReader.h b/Libraries/LibCore/ProcessStatisticsReader.h index 3afcac4f60..9c3bd93a80 100644 --- a/Libraries/LibCore/ProcessStatisticsReader.h +++ b/Libraries/LibCore/ProcessStatisticsReader.h @@ -35,7 +35,8 @@ namespace Core { struct ThreadStatistics { pid_t tid; unsigned times_scheduled; - unsigned ticks; + unsigned ticks_user; + unsigned ticks_kernel; unsigned syscall_count; unsigned inode_faults; unsigned zero_faults; diff --git a/Libraries/LibPthread/pthread.cpp b/Libraries/LibPthread/pthread.cpp index fd53b91fb7..74fcab0302 100644 --- a/Libraries/LibPthread/pthread.cpp +++ b/Libraries/LibPthread/pthread.cpp @@ -474,7 +474,7 @@ int pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* attr) { cond->value = 0; cond->previous = 0; - cond->clockid = attr ? attr->clockid : CLOCK_MONOTONIC; + cond->clockid = attr ? attr->clockid : CLOCK_MONOTONIC_COARSE; return 0; } @@ -502,7 +502,7 @@ int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) int pthread_condattr_init(pthread_condattr_t* attr) { - attr->clockid = CLOCK_MONOTONIC; + attr->clockid = CLOCK_MONOTONIC_COARSE; return 0; } diff --git a/Libraries/LibPthread/pthread.h b/Libraries/LibPthread/pthread.h index 9c6888c233..f397367054 100644 --- a/Libraries/LibPthread/pthread.h +++ b/Libraries/LibPthread/pthread.h @@ -82,9 +82,9 @@ int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param { \ 0, 0, 0, PTHREAD_MUTEX_DEFAULT \ } -#define PTHREAD_COND_INITIALIZER \ - { \ - 0, 0, CLOCK_MONOTONIC \ +#define PTHREAD_COND_INITIALIZER \ + { \ + 0, 0, CLOCK_MONOTONIC_COARSE \ } int pthread_key_create(pthread_key_t* key, void (*destructor)(void*)); diff --git a/MenuApplets/ResourceGraph/main.cpp b/MenuApplets/ResourceGraph/main.cpp index cff7c7efae..38d47a3bb1 100644 --- a/MenuApplets/ResourceGraph/main.cpp +++ b/MenuApplets/ResourceGraph/main.cpp @@ -135,9 +135,9 @@ private: for (auto& it : all_processes) { for (auto& jt : it.value.threads) { if (it.value.pid == 0) - idle += jt.times_scheduled; + idle += jt.ticks_user + jt.ticks_kernel; else - busy += jt.times_scheduled; + busy += jt.ticks_user + jt.ticks_kernel; } } } diff --git a/Userland/watch.cpp b/Userland/watch.cpp index 8aeccc674b..5188685e08 100644 --- a/Userland/watch.cpp +++ b/Userland/watch.cpp @@ -56,7 +56,7 @@ static struct timeval get_current_time() { struct timespec ts; struct timeval tv; - clock_gettime(CLOCK_MONOTONIC, &ts); + clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); timespec_to_timeval(ts, tv); return tv; }