]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: increase timer frequency to 100Hz (like Linux)
authorTulio A M Mendes <[email protected]>
Sat, 14 Feb 2026 07:58:29 +0000 (04:58 -0300)
committerTulio A M Mendes <[email protected]>
Sat, 14 Feb 2026 07:58:29 +0000 (04:58 -0300)
- Central TIMER_HZ=100 and TIMER_MS_PER_TICK=10 constants in timer.h
- Replace all hardcoded 50Hz / 20ms-per-tick assumptions:
  syscall.c (nanosleep, clock_gettime), procfs.c (/proc/uptime),
  net_ping.c (sleep/time calculations), sys_arch.c (sys_now),
  sync.c (ksem_wait_timeout ms-to-ticks conversion)
- Use timer_init(TIMER_HZ) instead of hardcoded 50
- BSP-only timer tick via lapic_get_id() — APs return early to
  eliminate sched_lock/vga_lock contention at higher tick rates
- vga_flush() skips spinlock + cursor update when nothing dirty
- Preempt every 2nd tick (effective 50Hz preemption) to avoid
  excessive CR3 reloads in emulated environments (QEMU TLB flush
  overhead). Sleep/timing resolution remains at full 100Hz via
  process_wake_check on every tick.

Tests: 20/20 smoke (11s), 16/16 battery, cppcheck clean

include/timer.h
src/drivers/timer.c
src/drivers/vga_console.c
src/kernel/main.c
src/kernel/procfs.c
src/kernel/sync.c
src/kernel/syscall.c
src/net/lwip_port/sys_arch.c
src/net/net_ping.c

index 0134bb191f2e69f7cc89c945c5ee1d6ce30456e8..ee9edc552dee48cc33233cda8b003f22312ad894 100644 (file)
@@ -12,6 +12,9 @@
 
 #include <stdint.h>
 
+#define TIMER_HZ           100
+#define TIMER_MS_PER_TICK  (1000 / TIMER_HZ)   /* 10 ms */
+
 void timer_init(uint32_t frequency);
 uint32_t get_tick_count(void);
 
index b3f37d180b4ba428133255accdddf9e533afd972..b3496f79c758710facea4dd1ba350eb8c977b155 100644 (file)
 
 #include "hal/timer.h"
 
+#if defined(__i386__)
+#include "arch/x86/lapic.h"
+#endif
+
 static uint32_t tick = 0;
 
 uint32_t get_tick_count(void) {
@@ -22,11 +26,19 @@ uint32_t get_tick_count(void) {
 }
 
 static void hal_tick_bridge(void) {
+#if defined(__i386__)
+    if (lapic_is_enabled() && lapic_get_id() != 0) return;
+#endif
     tick++;
     vdso_update_tick(tick);
     vga_flush();
     process_wake_check(tick);
-    schedule();
+    /* Preempt every SCHED_DIVISOR ticks to reduce context-switch
+     * overhead in emulated environments (QEMU TLB flush on CR3
+     * reload is expensive).  Sleeping processes still wake at full
+     * TIMER_HZ resolution via process_wake_check above. */
+    if (tick % 2 == 0)
+        schedule();
 }
 
 void timer_init(uint32_t frequency) {
index cd96890f8e606dff3f5aee832755f2c7039be109..23204e892063b5d0db52bc39af653a8a581aca8e 100644 (file)
@@ -217,6 +217,11 @@ void vga_print(const char* str) {
 }
 
 void vga_flush(void) {
+    /* Quick unlocked check: if nothing is dirty, skip entirely.
+     * All write paths (vga_write_buf, vga_put_char, vga_print) already
+     * flush immediately, so this timer-tick path is just a safety net. */
+    if (dirty_lo > dirty_hi) return;
+
     uintptr_t flags = spin_lock_irqsave(&vga_lock);
     vga_flush_to_hw();
     spin_unlock_irqrestore(&vga_lock, flags);
index 75188b1de0b13486cfbecb29f33be9b7758f9d02..24236fbbd1bb398d4327298aa4e0ded8d2e8ec6e 100644 (file)
@@ -83,8 +83,8 @@ void kernel_main(const struct boot_info* bi) {
         vdso_init();
     }
 
-    // 8. Start Timer (Preemption!) - 50Hz
-    timer_init(50);
+    // 8. Start Timer (Preemption!) - 100Hz (like Linux CONFIG_HZ=100)
+    timer_init(TIMER_HZ);
 
     hal_cpu_enable_interrupts();
 
index 6422ba0a26bb9bf10c7543d11495e192d13cc0fd..9328c9eadbb4eaa9a1426cc8e5d466f8b86627e0 100644 (file)
@@ -113,8 +113,8 @@ static uint32_t proc_cmdline_read(fs_node_t* node, uint32_t offset, uint32_t siz
 static uint32_t proc_uptime_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
     (void)node;
     uint32_t ticks = get_tick_count();
-    uint32_t secs = (ticks * 20) / 1000;
-    uint32_t frac = ((ticks * 20) % 1000) / 10;
+    uint32_t secs = (ticks * TIMER_MS_PER_TICK) / 1000;
+    uint32_t frac = ((ticks * TIMER_MS_PER_TICK) % 1000) / 10;
 
     char tmp[64];
     uint32_t len = 0;
index d6c54f4916d5b9eb6e18f072adca5624669f704a..bb3b999bfc259dfb2c5b5777bc88a76568b80c4f 100644 (file)
@@ -10,6 +10,7 @@
 #include "sync.h"
 #include "process.h"
 #include "utils.h"
+#include "timer.h"
 
 extern uint32_t get_tick_count(void);
 extern void schedule(void);
@@ -52,10 +53,10 @@ int ksem_wait_timeout(ksem_t* s, uint32_t timeout_ms) {
     s->waiters[s->nwaiters++] = current_process;
     current_process->state = PROCESS_BLOCKED;
 
-    /* Set a wake timeout if requested (convert ms to ticks at 50 Hz) */
+    /* Set a wake timeout if requested (convert ms to ticks) */
     uint32_t deadline = 0;
     if (timeout_ms > 0) {
-        uint32_t ticks = (timeout_ms + 19) / 20; /* round up */
+        uint32_t ticks = (timeout_ms + TIMER_MS_PER_TICK - 1) / TIMER_MS_PER_TICK;
         deadline = get_tick_count() + ticks;
         current_process->wake_at_tick = deadline;
         current_process->state = PROCESS_SLEEPING; /* timer will wake us */
index ba535821a20ac1d1981bbfac949669c38740a8a9..e61a58ca29d3543713d1877ece450c71e8f83fcf 100644 (file)
@@ -27,9 +27,9 @@
 
 #include "elf.h"
 #include "stat.h"
+#include "timer.h"
 #include "vmm.h"
 #include "pmm.h"
-#include "timer.h"
 #include "hal/mm.h"
 
 #include "hal/cpu.h"
@@ -58,8 +58,8 @@ struct k_itimerval {
 #define ITIMER_REAL    0
 #define ITIMER_VIRTUAL 1
 #define ITIMER_PROF    2
-#define TICKS_PER_SEC  50
-#define USEC_PER_TICK  (1000000U / TICKS_PER_SEC)  /* 20000 */
+#define TICKS_PER_SEC  TIMER_HZ
+#define USEC_PER_TICK  (1000000U / TICKS_PER_SEC)
 
 static uint32_t timeval_to_ticks(const struct k_timeval* tv) {
     return tv->tv_sec * TICKS_PER_SEC + tv->tv_usec / USEC_PER_TICK;
@@ -1714,9 +1714,8 @@ static int syscall_nanosleep_impl(const struct timespec* user_req, struct timesp
 
     if (req.tv_nsec >= 1000000000U) return -EINVAL;
 
-    const uint32_t TICK_MS = 20;
     uint32_t ms = req.tv_sec * 1000U + req.tv_nsec / 1000000U;
-    uint32_t ticks = (ms + TICK_MS - 1) / TICK_MS;
+    uint32_t ticks = (ms + TIMER_MS_PER_TICK - 1) / TIMER_MS_PER_TICK;
     if (ticks == 0 && (req.tv_sec > 0 || req.tv_nsec > 0)) ticks = 1;
 
     if (ticks > 0) {
@@ -1745,8 +1744,7 @@ static int syscall_clock_gettime_impl(uint32_t clk_id, struct timespec* user_tp)
         tp.tv_nsec = 0;
     } else {
         uint32_t ticks = get_tick_count();
-        const uint32_t TICK_MS = 20;
-        uint32_t total_ms = ticks * TICK_MS;
+        uint32_t total_ms = ticks * TIMER_MS_PER_TICK;
         tp.tv_sec = total_ms / 1000U;
         tp.tv_nsec = (total_ms % 1000U) * 1000000U;
     }
index 06f730dada522cf1a443fac28479fd8be1d8af95..b0507b7f20e86e906fc815e59c72d1b9d68519d2 100644 (file)
@@ -20,6 +20,7 @@
 #include "sync.h"
 #include "process.h"
 #include "spinlock.h"
+#include "timer.h"
 
 #include <stddef.h>
 
@@ -28,9 +29,9 @@ extern void* kmalloc(uint32_t size);
 extern void  kfree(void* ptr);
 extern struct process* process_create_kernel(void (*entry)(void));
 
-/* Return milliseconds since boot. Timer runs at 50 Hz → 20 ms per tick. */
+/* Return milliseconds since boot. */
 u32_t sys_now(void) {
-    return (u32_t)(get_tick_count() * 20);
+    return (u32_t)(get_tick_count() * TIMER_MS_PER_TICK);
 }
 
 /* ------------------------------------------------------------------ */
index 574d3f6eec12c604f3b1ca9fe9d57bf68c5d173e..ebe15c97d7713a0124b5eb1d2582a2902b4441f7 100644 (file)
@@ -29,6 +29,7 @@
 #include "process.h"
 #include "net.h"
 #include "e1000.h"
+#include "timer.h"
 
 #include <stdint.h>
 #include <stddef.h>
@@ -144,7 +145,7 @@ void net_ping_test(void) {
     }
 
     /* Wait for the E1000 link to stabilize in QEMU */
-    process_sleep(100); /* ~2 seconds at 50 Hz */
+    process_sleep(2 * TIMER_HZ); /* ~2 seconds */
 
     ip_addr_t target;
     IP4_ADDR(&target, 10, 0, 2, 2);
@@ -177,7 +178,7 @@ void net_ping_test(void) {
             process_sleep(1); /* yield for 1 tick */
         }
 
-        uint32_t dt = (get_tick_count() - t0) * 20;
+        uint32_t dt = (get_tick_count() - t0) * TIMER_MS_PER_TICK;
 
         if (ping_got_reply) {
             kprintf("[PING] reply from 10.0.2.2: seq=%d time=%dms\n",
@@ -188,7 +189,7 @@ void net_ping_test(void) {
         }
 
         if (i + 1 < PING_COUNT)
-            process_sleep(50); /* ~1 second between pings */
+            process_sleep(TIMER_HZ); /* ~1 second between pings */
     }
 
     /* Cleanup in tcpip thread */