menios
menios copied to clipboard
ITIMER_VIRTUAL and ITIMER_PROF support
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
- Add process_times to struct process
- Track user vs kernel mode on every timer tick
- Update times on context switch
- Implement getter functions
Phase 2: ITIMER_VIRTUAL
- Add itimer_virtual to struct process
- Update setitimer() to accept ITIMER_VIRTUAL
- Check virtual timer on user-mode ticks
- Send SIGVTALRM on expiry
- Update getitimer() to return virtual timer state
Phase 3: ITIMER_PROF
- Add itimer_prof to struct process
- Update setitimer() to accept ITIMER_PROF
- Check prof timer on all ticks
- Send SIGPROF on expiry
- Update getitimer() to return prof timer state
Phase 4: Testing & Integration
- Test CPU time tracking accuracy
- Test virtual timer with CPU-bound workload
- Test prof timer with mixed user/kernel workload
- Verify signals delivered correctly
- 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