Implemented system_time() for x86_64.

* Uses 64-bit multiplication, special handling for CPUs clocked < 1 GHz
  in system_time_nsecs() not required like on x86.
* Tested against a straight conversion of the x86 version, noticably
  faster with a large number of system_time() calls.
This commit is contained in:
Alex Smith 2012-07-08 10:16:44 +01:00
parent 7444a55ce5
commit 5c7d52183c
3 changed files with 45 additions and 111 deletions

View File

@ -367,9 +367,14 @@ extern "C" {
struct arch_thread;
#ifdef __x86_64__
void __x86_setup_system_time(uint64 conversionFactor,
uint64 conversionFactorNsecs);
#else
void __x86_setup_system_time(uint32 conversionFactor,
uint32 conversionFactorNsecs, bool conversionFactorNsecsShift);
#endif
void x86_context_switch(struct arch_thread* oldState,
struct arch_thread* newState);
void x86_userspace_thread_exit(void);

View File

@ -820,6 +820,12 @@ arch_cpu_init(kernel_args* args)
uint32 conversionFactor = args->arch_args.system_time_cv_factor;
uint64 conversionFactorNsecs = (uint64)conversionFactor * 1000;
#ifdef __x86_64__
// The x86_64 system_time() implementation uses 64-bit multiplication and
// therefore shifting is not necessary for low frequencies (it's also not
// too likely that there'll be any x86_64 CPUs clocked under 1GHz).
__x86_setup_system_time(conversionFactor, conversionFactorNsecs);
#else
if (conversionFactorNsecs >> 32 != 0) {
// the TSC frequency is < 1 GHz, which forces us to shift the factor
__x86_setup_system_time(conversionFactor, conversionFactorNsecs >> 16,
@ -828,6 +834,7 @@ arch_cpu_init(kernel_args* args)
// the TSC frequency is >= 1 GHz
__x86_setup_system_time(conversionFactor, conversionFactorNsecs, false);
}
#endif
return B_OK;
}

View File

@ -7,143 +7,65 @@
* Distributed under the terms of the NewOS License.
*/
#include <asm_defs.h>
FUNCTION(__x86_setup_system_time):
ret
FUNCTION_END(__x86_setup_system_time)
// TODO: Implement these.
/* int64 system_time(); */
FUNCTION(system_time):
ud2a
ret
FUNCTION_END(system_time)
/* int64 system_time_nsecs(); */
FUNCTION(system_time_nsecs):
ud2a
ret
FUNCTION_END(system_time_nsecs)
#if 0
/* saves the conversion factor needed for system_time */
.lcomm cv_factor 4
.lcomm cv_factor_nsecs 4
.lcomm cv_factor_nsecs_shift 1
.lcomm cv_factor 8
.lcomm cv_factor_nsecs 8
.text
FUNCTION(__x86_setup_system_time):
movl 4(%esp), %eax
movl %eax, cv_factor
movl 8(%esp), %eax
movl %eax, cv_factor_nsecs
movb 12(%esp), %al
movb %al, cv_factor_nsecs_shift
movq %rdi, cv_factor
movq %rsi, cv_factor_nsecs
ret
FUNCTION_END(__x86_setup_system_time)
/* int64 system_time(); */
FUNCTION(system_time):
pushl %ebx
pushl %ecx
movl cv_factor, %ebx
movq cv_factor, %rcx
/* load 64-bit factor into %eax (low), %edx (high) */
rdtsc /* time in %edx,%eax */
// Load 64-bit TSC into %eax (low), %edx (high).
rdtsc
movl %edx, %ecx /* save high half */
mull %ebx /* truncate %eax, but keep %edx */
movl %ecx, %eax
movl %edx, %ecx /* save high half of low */
mull %ebx /*, %eax*/
/* now compute [%edx, %eax] + [%ecx], propagating carry */
subl %ebx, %ebx /* need zero to propagate carry */
addl %ecx, %eax
adc %ebx, %edx
popl %ecx
popl %ebx
// Convert into a single 64-bit value.
shl $32, %rdx
orq %rdx, %rax
// Multiply by conversion factor, result in %rax (low), %rdx (high).
mulq %rcx
// Shift the result right by 32 bits.
shr $32, %rax
shl $32, %rdx
orq %rdx, %rax
ret
FUNCTION_END(system_time)
/* int64 system_time_nsecs(); */
FUNCTION(system_time_nsecs):
testb $0, cv_factor_nsecs_shift
jne 1f
// Same algorithm as system_time(), just with a different factor.
movq cv_factor_nsecs, %rcx
/* same algorithm as system_time(), just with a different factor */
// Load 64-bit TSC into %eax (low), %edx (high).
rdtsc
pushl %ebx
pushl %ecx
movl cv_factor_nsecs, %ebx
// Convert into a single 64-bit value.
shl $32, %rdx
orq %rdx, %rax
/* load 64-bit factor into %eax (low), %edx (high) */
rdtsc /* time in %edx,%eax */
// Multiply by conversion factor, result in %rax (low), %rdx (high).
mulq %rcx
movl %edx, %ecx /* save high half */
mull %ebx /* truncate %eax, but keep %edx */
movl %ecx, %eax
movl %edx, %ecx /* save high half of low */
mull %ebx /*, %eax*/
/* now compute [%edx, %eax] + [%ecx], propagating carry */
subl %ebx, %ebx /* need zero to propagate carry */
addl %ecx, %eax
adc %ebx, %edx
popl %ecx
popl %ebx
ret
1:
/* TSC frequency is less than 1 GHz -- we shift everything up 16 bit */
pushl %ebx
pushl %ecx
pushl %esi
movl cv_factor_nsecs, %ebx
/* load 64-bit factor into %eax (low), %edx (high) */
rdtsc /* time in %edx,%eax */
/* save high half */
movl %edx, %ecx
/* multiply low half by conversion factor */
mull %ebx
/* save result */
movl %eax, %esi /* low half -> %esi */
movl %ecx, %eax
movl %edx, %ecx /* high half -> %ecx */
/* multiply high half by conversion factor */
mull %ebx
/* now compute [%edx, %eax] + [%ecx], propagating carry */
xorl %ebx, %ebx /* need zero to propagate carry */
addl %ecx, %eax
adc %ebx, %edx
/* shift the result left 16 bit */
shl $16, %edx
movl %eax, %ebx
shr $16, %ebx
orw %bx, %dx
shl $16, %eax
/* add the high 16 bit of the low half of the low product */
shr $16, %esi
orw %si, %ax
popl %esi
popl %ecx
popl %ebx
// Shift the result right by 32 bits.
shr $32, %rax
shl $32, %rdx
orq %rdx, %rax
ret
FUNCTION_END(system_time_nsecs)
#endif