| #include <arch/arch.h> | 
 | #include <time.h> | 
 | #include <stdio.h> | 
 | #include <schedule.h> | 
 | #include <multiboot.h> | 
 | #include <pmap.h> | 
 | #include <smp.h> | 
 | #include <ros/procinfo.h> | 
 |  | 
 | /* Determines the overhead of tsc timing.  Note the start/stop calls are | 
 |  * inlined, so we're trying to determine the lowest amount of overhead | 
 |  * attainable by using the TSC (or whatever timing source). | 
 |  * | 
 |  * For more detailed TSC measurements, use test_rdtsc() in k/a/i/rdtsc_test.c */ | 
 | static void train_timing(void) | 
 | { | 
 | 	uint64_t min_overhead = UINT64_MAX; | 
 | 	uint64_t max_overhead = 0; | 
 | 	uint64_t time, diff; | 
 | 	int8_t irq_state = 0; | 
 |  | 
 | 	/* Reset this, in case we run it again.  The use of start/stop to | 
 | 	 * determine the overhead relies on timing_overhead being 0. */ | 
 | 	__proc_global_info.tsc_overhead = 0; | 
 | 	/* timing might use cpuid, in which case we warm it up to avoid some | 
 | 	 * extra variance */ | 
 | 	time = start_timing(); | 
 |  	diff = stop_timing(time); | 
 | 	time = start_timing(); | 
 |  	diff = stop_timing(time); | 
 | 	time = start_timing(); | 
 |  	diff = stop_timing(time); | 
 | 	disable_irqsave(&irq_state); | 
 | 	for (int i = 0; i < 10000; i++) { | 
 | 		time = start_timing(); | 
 |  		diff = stop_timing(time); | 
 | 		min_overhead = MIN(min_overhead, diff); | 
 | 		max_overhead = MAX(max_overhead, diff); | 
 | 	} | 
 | 	enable_irqsave(&irq_state); | 
 | 	__proc_global_info.tsc_overhead = min_overhead; | 
 | 	printk("TSC overhead (Min: %llu, Max: %llu)\n", min_overhead, | 
 | 	       max_overhead); } | 
 |  | 
 | /* Convenience wrapper called when a core's timer interrupt goes off.  Not to be | 
 |  * confused with global timers (like the PIC).  Do not put your code here.  If | 
 |  * you want something to happen in the future, set an alarm. */ | 
 | void timer_interrupt(struct hw_trapframe *hw_tf, void *data) | 
 | { | 
 | 	__trigger_tchain(&per_cpu_info[core_id()].tchain, hw_tf); | 
 | } | 
 |  | 
 | /* | 
 |  * We use scaled integer arithmetic for converting between TSC clock cycles | 
 |  * and nanoseconds. In each case we use a fixed shift value of 32 which | 
 |  * gives a very high degree of accuracy. | 
 |  * | 
 |  * The actual scaling calculations rely on being able use the 128 bit | 
 |  * product of two unsigned 64 bit numbers as an intermediate result | 
 |  * in the calculation. Fortunately, on x86_64 at least, gcc's 128 bit | 
 |  * support is sufficiently good that it generates optimal code for this | 
 |  * calculation without the need to write any assembler. | 
 |  */ | 
 | static inline uint64_t mult_shift_64(uint64_t a, uint64_t b, uint8_t shift) | 
 | { | 
 | 	return ((unsigned __int128)a * b) >> shift; | 
 | } | 
 |  | 
 | static uint64_t cycles_to_nsec_mult; | 
 | static uint64_t nsec_to_cycles_mult; | 
 |  | 
 | #define CYCLES_TO_NSEC_SHIFT	32 | 
 | #define NSEC_TO_CYCLES_SHIFT	32 | 
 |  | 
 | static void cycles_to_nsec_init(uint64_t tsc_freq_hz) | 
 | { | 
 | 	cycles_to_nsec_mult = (NSEC_PER_SEC << CYCLES_TO_NSEC_SHIFT) / tsc_freq_hz; | 
 | } | 
 |  | 
 | static void nsec_to_cycles_init(uint64_t tsc_freq_hz) | 
 | { | 
 | 	uint64_t divisor = NSEC_PER_SEC; | 
 |  | 
 | 	/* | 
 | 	 * In the unlikely event that the TSC frequency is greater | 
 | 	 * than (1 << 32) we have to lose a little precision to | 
 | 	 * avoid overflow in the calculation of the multiplier. | 
 | 	 */ | 
 | 	while (tsc_freq_hz >= ((uint64_t)1 << NSEC_TO_CYCLES_SHIFT)) { | 
 | 		tsc_freq_hz >>= 1; | 
 | 		divisor >>= 1; | 
 | 	} | 
 | 	nsec_to_cycles_mult = (tsc_freq_hz << NSEC_TO_CYCLES_SHIFT) / divisor; | 
 | } | 
 |  | 
 | uint64_t tsc2nsec(uint64_t tsc_time) | 
 | { | 
 | 	return mult_shift_64(tsc_time, cycles_to_nsec_mult, CYCLES_TO_NSEC_SHIFT); | 
 | } | 
 |  | 
 | uint64_t nsec2tsc(uint64_t nsec) | 
 | { | 
 | 	return mult_shift_64(nsec, nsec_to_cycles_mult, NSEC_TO_CYCLES_SHIFT); | 
 | } | 
 |  | 
 | /* | 
 |  * Return nanoseconds since the UNIX epoch, 1st January, 1970. | 
 |  */ | 
 | uint64_t epoch_nsec(void) | 
 | { | 
 | 	uint64_t cycles = read_tsc() - __proc_global_info.tsc_cycles_last; | 
 |  | 
 | 	return __proc_global_info.walltime_ns_last + tsc2nsec(cycles); | 
 | } | 
 |  | 
 | void time_init(void) | 
 | { | 
 | 	train_timing(); | 
 |  | 
 | 	__proc_global_info.walltime_ns_last = read_persistent_clock(); | 
 | 	__proc_global_info.tsc_cycles_last  = read_tsc(); | 
 |  | 
 | 	cycles_to_nsec_init(__proc_global_info.tsc_freq); | 
 | 	nsec_to_cycles_init(__proc_global_info.tsc_freq); | 
 | } |