]> 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 be9471a41d843363992f2c86e1a063d3669dff73..89583df7b8bcc568c59fb9eb0e4c2365058896a3 100644 (file)
@@ -3,6 +3,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 12137e2e27d4e13731789d461d5ae25f254d35ad..d91fc6b45a6abd877fbae772100bf39277353348 100644 (file)
@@ -6,6 +6,10 @@
 
 #include "hal/timer.h"
 
+#if defined(__i386__)
+#include "arch/x86/lapic.h"
+#endif
+
 static uint32_t tick = 0;
 
 uint32_t get_tick_count(void) {
@@ -13,11 +17,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 52e4cf77706f06db120afb39bc1f18e1ea87afbe..d3c71b5b846fd72e808147996024283cbbae43d6 100644 (file)
@@ -208,6 +208,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 bdd8ad38cb3ada328766e87ca131f3d0edbec2b7..ff80841bfa60e98476aa1c36bc544681f39500d8 100644 (file)
@@ -74,8 +74,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 de6b0ecc6fa96d034f3fd11aa3d9de433386639d..7af36042aa5b2f722e16f622c3ad4bda7f2a9ba6 100644 (file)
@@ -104,8 +104,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 6eb78d23e19f7de4de5a2ad0d219cfc241e47f16..526ab6426528b1ccf33a184b48d53513349a33e6 100644 (file)
@@ -1,6 +1,7 @@
 #include "sync.h"
 #include "process.h"
 #include "utils.h"
+#include "timer.h"
 
 extern uint32_t get_tick_count(void);
 extern void schedule(void);
@@ -43,10 +44,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 c7b5738495f8a89b056ca89fd451b04171a92708..46c7aa0e6790bd6289dda6e139d1983db2e36042 100644 (file)
@@ -18,9 +18,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"
@@ -49,8 +49,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;
@@ -1705,9 +1705,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) {
@@ -1736,8 +1735,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 f91f7678722eaf0969d533225fdde2deb61d6a0d..c73661e169f8b38a31ae4bd3d1bab719ddacd35e 100644 (file)
@@ -11,6 +11,7 @@
 #include "sync.h"
 #include "process.h"
 #include "spinlock.h"
+#include "timer.h"
 
 #include <stddef.h>
 
@@ -19,9 +20,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 08284f1339366f527eaaf7787c71997bafd05b71..a5ae9c8d4168d3b251bc02de89a5df1882ceeead 100644 (file)
@@ -20,6 +20,7 @@
 #include "process.h"
 #include "net.h"
 #include "e1000.h"
+#include "timer.h"
 
 #include <stdint.h>
 #include <stddef.h>
@@ -135,7 +136,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);
@@ -168,7 +169,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",
@@ -179,7 +180,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 */