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