menios icon indicating copy to clipboard operation
menios copied to clipboard

Extended clock IDs (MONOTONIC_RAW, BOOTTIME, CPU clocks)

Open pbalduino opened this issue 3 months ago • 0 comments

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

  1. Add CLOCK_MONOTONIC_RAW to clock_gettime() handler
  2. Return raw TSC time without adjustments
  3. Document that it's identical to CLOCK_MONOTONIC for now
  4. Reserve space for future NTP adjustments

Phase 2: CLOCK_BOOTTIME

  1. Add CLOCK_BOOTTIME to clock_gettime() handler
  2. Track suspend/resume time (stub for now)
  3. Return monotonic time + suspend time
  4. Prepare for future suspend/resume support

Phase 3: CLOCK_PROCESS_CPUTIME_ID

  1. Add CPU time tracking to struct process (depends on #328)
  2. Implement clock_gettime(CLOCK_PROCESS_CPUTIME_ID)
  3. Return user_time + kernel_time as timespec
  4. Support clock_getres() for CPU clock resolution

Phase 4: CLOCK_THREAD_CPUTIME_ID

  1. Wait for threading support (#109)
  2. Add CPU time tracking to struct thread
  3. Implement clock_gettime(CLOCK_THREAD_CPUTIME_ID)
  4. 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)

pbalduino avatar Oct 20 '25 15:10 pbalduino