menios
menios copied to clipboard
Extended clock IDs (MONOTONIC_RAW, BOOTTIME, CPU clocks)
Goal
Implement extended clock IDs for clock_gettime() beyond CLOCK_REALTIME and CLOCK_MONOTONIC.
Context
clock_gettime() only honours CLOCK_REALTIME and CLOCK_MONOTONIC (src/kernel/syscall/syscall.c:2062). We're missing several important clock types.
Current State
- ✅ CLOCK_REALTIME - wall-clock time
- ✅ CLOCK_MONOTONIC - monotonic time since boot
- ❌ CLOCK_MONOTONIC_RAW - missing
- ❌ CLOCK_BOOTTIME - missing
- ❌ CLOCK_PROCESS_CPUTIME_ID - missing
- ❌ CLOCK_THREAD_CPUTIME_ID - missing
What's Needed
1. CLOCK_MONOTONIC_RAW
Monotonic time not adjusted by NTP/adjtime:
#define CLOCK_MONOTONIC_RAW 4
// Returns raw hardware counter time, no adjustments
// For meniOS: same as CLOCK_MONOTONIC until we have NTP
int clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
Use case: Measuring precise time intervals without NTP interference
2. CLOCK_BOOTTIME
Monotonic time including suspend time:
#define CLOCK_BOOTTIME 7
// Includes time system was suspended
// For meniOS: same as CLOCK_MONOTONIC (no suspend/resume yet)
int clock_gettime(CLOCK_BOOTTIME, &ts);
Use case: Measuring absolute time across suspend/resume cycles
3. CLOCK_PROCESS_CPUTIME_ID
Per-process CPU time:
#define CLOCK_PROCESS_CPUTIME_ID 2
// Returns CPU time consumed by this process (user + kernel)
int clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
Use case: Self-profiling, benchmarking, resource accounting
4. CLOCK_THREAD_CPUTIME_ID
Per-thread CPU time:
#define CLOCK_THREAD_CPUTIME_ID 3
// Returns CPU time consumed by this thread
int clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
Use case: Thread-level profiling (requires threading support)
Implementation Strategy
Phase 1: CLOCK_MONOTONIC_RAW
- Add CLOCK_MONOTONIC_RAW to clock_gettime() handler
- Return raw TSC time without adjustments
- Document that it's identical to CLOCK_MONOTONIC for now
- Reserve space for future NTP adjustments
Phase 2: CLOCK_BOOTTIME
- Add CLOCK_BOOTTIME to clock_gettime() handler
- Track suspend/resume time (stub for now)
- Return monotonic time + suspend time
- Prepare for future suspend/resume support
Phase 3: CLOCK_PROCESS_CPUTIME_ID
- Add CPU time tracking to struct process (depends on #328)
- Implement clock_gettime(CLOCK_PROCESS_CPUTIME_ID)
- Return user_time + kernel_time as timespec
- Support clock_getres() for CPU clock resolution
Phase 4: CLOCK_THREAD_CPUTIME_ID
- Wait for threading support (#109)
- Add CPU time tracking to struct thread
- Implement clock_gettime(CLOCK_THREAD_CPUTIME_ID)
- Return thread CPU time as timespec
Implementation Details
clock_gettime() handler
long sys_clock_gettime(clockid_t clk_id, struct timespec *tp) {
struct timespec ts;
switch (clk_id) {
case CLOCK_REALTIME:
get_wall_clock_time(&ts);
break;
case CLOCK_MONOTONIC:
get_monotonic_time(&ts);
break;
case CLOCK_MONOTONIC_RAW:
// Raw monotonic time (no NTP adjustments)
get_monotonic_raw_time(&ts);
break;
case CLOCK_BOOTTIME:
// Monotonic time including suspend
get_boottime(&ts);
break;
case CLOCK_PROCESS_CPUTIME_ID:
// Current process CPU time
get_process_cpu_time(current_process(), &ts);
break;
case CLOCK_THREAD_CPUTIME_ID:
// Current thread CPU time (requires threading)
if (!threading_enabled())
return -EINVAL;
get_thread_cpu_time(current_thread(), &ts);
break;
default:
return -EINVAL;
}
if (copy_to_user(tp, &ts, sizeof(ts)) < 0)
return -EFAULT;
return 0;
}
clock_getres() support
long sys_clock_getres(clockid_t clk_id, struct timespec *res) {
struct timespec ts;
switch (clk_id) {
case CLOCK_REALTIME:
case CLOCK_MONOTONIC:
case CLOCK_MONOTONIC_RAW:
case CLOCK_BOOTTIME:
// Nanosecond resolution
ts.tv_sec = 0;
ts.tv_nsec = 1;
break;
case CLOCK_PROCESS_CPUTIME_ID:
case CLOCK_THREAD_CPUTIME_ID:
// CPU timer tick resolution (e.g., 10ms)
ts.tv_sec = 0;
ts.tv_nsec = 10000000; // 10ms
break;
default:
return -EINVAL;
}
if (res && copy_to_user(res, &ts, sizeof(ts)) < 0)
return -EFAULT;
return 0;
}
Files to Modify
- include/time.h - Add clock ID constants
- src/kernel/syscall/syscall.c - Update clock_gettime/getres handlers
- src/kernel/time/timekeeper.c - Add getter functions
- src/kernel/process/process.c - Add CPU time tracking
- test/test_clock_ids.c (new) - Test all clock types
Usage Examples
CLOCK_MONOTONIC_RAW
#include <time.h>
// Measure precise time interval without NTP drift
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
do_work();
clock_gettime(CLOCK_MONOTONIC_RAW, &end);
uint64_t ns = (end.tv_sec - start.tv_sec) * 1000000000 +
(end.tv_nsec - start.tv_nsec);
printf("Work took %llu ns\n", ns);
CLOCK_PROCESS_CPUTIME_ID
#include <time.h>
// Self-profiling
struct timespec cpu_time;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &cpu_time);
printf("Process has consumed %ld.%09ld seconds of CPU time\n",
cpu_time.tv_sec, cpu_time.tv_nsec);
CLOCK_BOOTTIME
#include <time.h>
// Measure time including system suspend
struct timespec boot_time;
clock_gettime(CLOCK_BOOTTIME, &boot_time);
printf("Time since boot: %ld seconds\n", boot_time.tv_sec);
Testing
- Verify CLOCK_MONOTONIC_RAW never goes backwards
- Check CLOCK_BOOTTIME >= CLOCK_MONOTONIC
- CLOCK_PROCESS_CPUTIME_ID tracks CPU usage accurately
- clock_getres() returns correct resolution for each clock
- Invalid clock IDs return -EINVAL
- CLOCK_THREAD_CPUTIME_ID works with threading
Standards Compliance
- POSIX.1-2008 clock types
- Linux clock_gettime(2) compatibility
- Match Linux clock ID numbering
Dependencies
- #328 - ITIMER_VIRTUAL/ITIMER_PROF (for CPU time tracking)
- #326 - Centralized timekeeper
- #109 - pthread API (for CLOCK_THREAD_CPUTIME_ID)
Parent Issue
- #226 - RTC and time management
Future Work
- Per-process clock_getcpuclockid()
- pthread_getcpuclockid() for thread clocks
- CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC_COARSE for fast, low-res time
- CLOCK_TAI (International Atomic Time)