Fixed up sysenter/sysexit semantics to allow another environment to be run on exit
[akaros.git] / kern / src / timer.c
1 #include <arch/x86.h>
2 #include <arch/timer.h>
3
4 /* timing_overhead
5  * Any user space process that links to this file will get its own copy.  
6  * This means it will manually have to call tune_timing itself before it 
7  * makes its first measurement.
8  */
9 uint64_t timing_overhead = 0;
10
11 /* start_timing()
12  * This function simply reads the tsc in a serialized fashion and returns its
13  * value.  It is pusposefully annotated with a noinline so that the overheads 
14  * assocaited with calling it are as deterministic as possible.
15  */
16 uint64_t start_timing() __attribute__((noinline))
17 {
18     return read_tsc_serialized();
19 }
20
21 /* stop_timing()
22  * This function reads the tsc in a serialized fashion and subtracts the value
23  * it reads from the value passed in as a paramter in order to determine the 
24  * difference between the two values.  A global timing_overhead value is also 
25  * subtracted to compensate for the overhead associated with calling both
26  * start and stop timing and returning their values.
27  * This function is purposefully annotated with a noinline so that 
28  * the overheads assocaited with calling it are as deterministic as possible.
29  */
30 uint64_t stop_timing(uint64_t val) __attribute__((noinline))
31 {
32     uint64_t diff = (read_tsc_serialized() - val - timing_overhead);
33         if ((int64_t) diff < 0) 
34                 return 1;
35         return diff;
36 }
37
38 /* train_timing()
39  * This function is intended to train the timing_overhead variable for use by
40  * stop_timing().  It runs through a loop calling start/stop and averaging the 
41  * overhead of calling them without doing any useful work in between.
42  */
43 void train_timing() 
44 {
45         int i;
46         // set training overhead to be something large
47         register uint64_t training_overhead = 0xffffffff;
48         register uint64_t time, diff;
49
50         //Do this 3 times outside the loop to warm up cpuid
51         time = start_timing();
52         diff = stop_timing(time);
53         time = start_timing();
54         diff = stop_timing(time);
55         time = start_timing();
56         diff = stop_timing(time);
57         for(i=0; i<10000; i++) {
58                 time = start_timing();
59                 diff = stop_timing(time);
60                 
61                 /* In case diff was negative, I want to add its absolute value
62                  * to the cumulative error, otherwise, just diff itself
63                  */
64                 if((int64_t)diff < 0)
65                         diff = (uint64_t)(~0) - diff + 1;
66                 training_overhead = MIN(training_overhead, diff);
67         }
68         timing_overhead = training_overhead;
69 }