menios icon indicating copy to clipboard operation
menios copied to clipboard

ITIMER_VIRTUAL and ITIMER_PROF support

Open pbalduino opened this issue 3 months ago • 0 comments

Goal

Implement ITIMER_VIRTUAL and ITIMER_PROF interval timers for CPU time profiling.

Context

Currently ITIMER_VIRTUAL and ITIMER_PROF return -EINVAL because proc_get_itimer() only exposes ITIMER_REAL (src/kernel/syscall/syscall.c:2162). Only wall-clock timers work.

Current State

  • ✅ ITIMER_REAL implemented (#288)
  • ❌ ITIMER_VIRTUAL returns -EINVAL
  • ❌ ITIMER_PROF returns -EINVAL
  • No per-process CPU time tracking

What's Needed

Timer Types

#define ITIMER_REAL    0  // Real time (SIGALRM) ✅ COMPLETE
#define ITIMER_VIRTUAL 1  // Process user time (SIGVTALRM) ❌ MISSING
#define ITIMER_PROF    2  // Process user+kernel time (SIGPROF) ❌ MISSING

1. CPU Time Tracking

Track per-process CPU time usage:

struct process_times {
    uint64_t user_ticks;    // Time spent in user mode
    uint64_t kernel_ticks;  // Time spent in kernel mode
    uint64_t total_ticks;   // user + kernel
};

// Called on each timer tick
void process_update_cpu_time(struct process *proc, bool in_kernel);

// Get CPU time for process
uint64_t process_get_user_time_us(struct process *proc);
uint64_t process_get_kernel_time_us(struct process *proc);
uint64_t process_get_total_time_us(struct process *proc);

2. Virtual Timer (ITIMER_VIRTUAL)

Counts only when process is executing in user mode:

// Check on each timer tick if process is running in user mode
void timer_tick_virtual(struct process *proc) {
    if (!is_kernel_mode()) {
        proc->times.user_ticks++;
        
        // Check if virtual timer should fire
        if (proc->itimer_virtual.enabled &&
            proc->times.user_ticks >= proc->itimer_virtual.next_expiry) {
            send_signal(proc, SIGVTALRM);
            
            // Reset for interval timer
            if (proc->itimer_virtual.interval_us > 0) {
                proc->itimer_virtual.next_expiry = 
                    proc->times.user_ticks + 
                    us_to_ticks(proc->itimer_virtual.interval_us);
            }
        }
    }
}

3. Profiling Timer (ITIMER_PROF)

Counts when process is executing (user mode or kernel mode):

// Check on each timer tick if process is running
void timer_tick_prof(struct process *proc) {
    proc->times.total_ticks++;
    
    // Check if profiling timer should fire
    if (proc->itimer_prof.enabled &&
        proc->times.total_ticks >= proc->itimer_prof.next_expiry) {
        send_signal(proc, SIGPROF);
        
        // Reset for interval timer
        if (proc->itimer_prof.interval_us > 0) {
            proc->itimer_prof.next_expiry = 
                proc->times.total_ticks + 
                us_to_ticks(proc->itimer_prof.interval_us);
        }
    }
}

4. Process Structure Updates

struct process {
    // ... existing fields ...
    
    // CPU time tracking
    struct process_times times;
    
    // Interval timers
    struct {
        bool enabled;
        uint64_t interval_us;
        uint64_t next_expiry;  // In ticks
    } itimer_real;     // ✅ Already exists
    
    struct {
        bool enabled;
        uint64_t interval_us;
        uint64_t next_expiry;  // In user-mode ticks
    } itimer_virtual;  // ❌ NEW
    
    struct {
        bool enabled;
        uint64_t interval_us;
        uint64_t next_expiry;  // In total ticks
    } itimer_prof;     // ❌ NEW
};

Implementation Strategy

Phase 1: CPU Time Tracking

  1. Add process_times to struct process
  2. Track user vs kernel mode on every timer tick
  3. Update times on context switch
  4. Implement getter functions

Phase 2: ITIMER_VIRTUAL

  1. Add itimer_virtual to struct process
  2. Update setitimer() to accept ITIMER_VIRTUAL
  3. Check virtual timer on user-mode ticks
  4. Send SIGVTALRM on expiry
  5. Update getitimer() to return virtual timer state

Phase 3: ITIMER_PROF

  1. Add itimer_prof to struct process
  2. Update setitimer() to accept ITIMER_PROF
  3. Check prof timer on all ticks
  4. Send SIGPROF on expiry
  5. Update getitimer() to return prof timer state

Phase 4: Testing & Integration

  1. Test CPU time tracking accuracy
  2. Test virtual timer with CPU-bound workload
  3. Test prof timer with mixed user/kernel workload
  4. Verify signals delivered correctly
  5. Check interval timer reset

Files to Modify

  • include/kernel/process.h - Add timer fields
  • src/kernel/process/process.c - Initialize timers
  • src/kernel/timer/timer.c - Implement virtual/prof timer logic
  • src/kernel/syscall/syscall.c - Update setitimer/getitimer handlers
  • src/kernel/sched/scheduler.c - Track CPU time on context switch
  • test/test_itimer.c - Add virtual/prof timer tests

Usage Example

#include <sys/time.h>
#include <signal.h>

void prof_handler(int sig) {
    printf("Profiling timer expired (CPU time)\n");
}

void vtalrm_handler(int sig) {
    printf("Virtual timer expired (user time)\n");
}

// Set up profiling timer
signal(SIGPROF, prof_handler);
struct itimerval prof_timer = {
    .it_interval = { .tv_sec = 0, .tv_usec = 100000 },  // 100ms
    .it_value = { .tv_sec = 0, .tv_usec = 100000 }
};
setitimer(ITIMER_PROF, &prof_timer, NULL);

// Set up virtual timer  
signal(SIGVTALRM, vtalrm_handler);
struct itimerval virt_timer = {
    .it_interval = { .tv_sec = 1, .tv_usec = 0 },  // 1s
    .it_value = { .tv_sec = 1, .tv_usec = 0 }
};
setitimer(ITIMER_VIRTUAL, &virt_timer, NULL);

// Do CPU-intensive work
while (1) {
    compute_something();
}

Testing

  • CPU time tracking with user-mode workload
  • CPU time tracking with syscall-heavy workload
  • ITIMER_VIRTUAL fires based on user time
  • ITIMER_PROF fires based on total CPU time
  • Interval timers reset correctly
  • Signal delivery to correct process
  • Multiple timers active simultaneously

Performance Considerations

  • CPU time tracking adds overhead to every timer tick
  • Need efficient check (compare, not iterate)
  • Consider per-CPU data structures for SMP

Dependencies

  • #288 - Interval timers (ITIMER_REAL) (✅ complete)
  • #213 - Signal delivery (✅ complete)
  • #34 - Preemptive scheduler (✅ complete)

Parent Issue

  • #226 - RTC and time management

References

  • POSIX setitimer(2) specification
  • Linux getrusage(2) for CPU time semantics
  • BSD profiling timer implementation

pbalduino avatar Oct 20 '25 15:10 pbalduino