Closed vilhelmgray closed 7 years ago
This pull request has been accepted. I will most likely move the os_get_proc_time and os_set_proc_start_time functions into os_system_misc just to keep the call table tidy.
Great work!
Ah yes, os_system_misc
would have be a far more apt place to put those routines.
By the way, I suspect a naive solution to break down the process time between user time and system time may be rather quick to code. One solution I've thought of is to use an additional sysvar variable to keep track of system time: current time is saved at the start of a syscall, then elapsed time is added to the respective sysvar variable at the end of syscall. The sysvar variable would accumulate the total system time, while the total user time can be computed by subtracting total system time from the total elapsed process time.
How precise does this need to be overall? Currently os_ClockCounter is incremented 8 times per second.
The C standard leaves the granularity of clock_t
up to the implementation; but the existence of CLOCKS_PER_SECOND
does imply an update frequency of at least 1 Hz.
Still, however, 8 Hz is a rather slow frequency for CPU clock counter in general. A good future milestone to consider would be to reimplement the updates using the APIC timer so that the frequency can be much higher.
Agreed on the APIC timer. I've couldn't get it to work before but it will required for precision.
I discovered another option available which I would like to share: the Time Stamp Counter (TSC). Modern Intel processors feature a built-in clock counter which may be read via the RDTSC
instruction. For example, to grab the current TSC value for the current CPU and return it in register RAX
, you could do something like this:
push rdx
rdtsc
shl rdx, 32
or rax, rdx
pop rdx
Note that the RDTSC
instruction loads the high-order 32 bits in RDX
while the low-order 32 bits are loaded in RAX
.
While historically the TSC was unreliable and variable, modern 64-bit Intel processors have an invariant TSC in each which counts monotonically and is automatically reset to 0
when the respective core is reset. Since the counts are automatically maintained by the CPU, we don't need to use a timer IRQ to keep track of time.
Two caveats to keep in mind when working with the Intel processors' RTCs: RDTSC
is not a serializing instruction (i.e. it may read the counter out of order), and the TSC value on each core is independent. Therefore, it's recommended to use the RDTSCP
instruction instead, which is a serializing instruction and also loads the CPUID in register ECX
as well to identify which TSC was grabbed.
HPET (https://en.wikipedia.org/wiki/High_Precision_Event_Timer) may be another option.
This patch adds functionality to provide a simple working version of the
times
function. The current timer counter value is saved at the start of a new process (right before the main function is called). The elapsed process time can then be computed by subtracting the current timer counter value from the process start time (the timer counter value saved previously).Two new syscalls are introduced:
os_get_proc_time
andos_set_proc_start_time
. Theos_set_proc_start_time
syscall saves the current timer counter value to a new sysvar calledos_ProcessStartTime
. Theos_get_proc_time
syscall computes the elapsed process time by taking the currentos_ProcessStartTime
value and subtracting it from the current timer counter value.The
times
function implementation is not perfect quite yet: since BareMetal OS lacks a way to differentiate between user and system time, the elapsed process time is assumed to be entirely user time; system time is hardcoded to a value of0
. A future patch should be made to implement functionality to differentiate and keep track of user and system time.