4e3723e4bd70dc225ad595bea1b4f1fadfa21d9e
[akaros.git] / user / c3po / util / clock.c
1 /**
2  * routines for getting timing info from the cycle clock
3  **/
4
5 //#include <stdio.h>
6 #include <sys/time.h>
7 #include <sys/syscall.h>
8 #include <time.h>
9 #include <string.h>
10 #include <unistd.h>
11
12 #include "clock.h"
13 #include "debug.h"
14
15
16 #ifdef USE_PERFCTR
17
18 // perfctr specific declarations
19 static struct vperfctr *self = NULL;
20 struct vperfctr *clock_perfctr = NULL;
21
22 static struct perfctr_info info;
23 static struct vperfctr_control control;
24
25 static void init_perfctr() {
26     unsigned int tsc_on = 1;
27     unsigned int nractrs = 1;
28     unsigned int pmc_map0 = 0;
29     unsigned int evntsel0 = 0;
30
31     self = vperfctr_open();
32     clock_perfctr = self;
33     if( !self ) {
34       char *str = "vperfctr_open() failed!!\n";
35       syscall(SYS_write, 2, str, strlen(str));
36       exit(1);
37     }
38     if( vperfctr_info(clock_perfctr, &info) < 0 ) {
39       char *str = "vperfctr_info() failed!!\n";
40       syscall(SYS_write, 2, str, strlen(str));
41       exit(1);
42     }
43
44     memset(&control, 0, sizeof control);
45
46     /* Attempt to set up control to count clocks via the TSC
47        and retired instructions via PMC0. */
48     switch( info.cpu_type ) {
49       case PERFCTR_X86_GENERIC:
50         nractrs = 0;            /* no PMCs available */
51         break;
52       case PERFCTR_X86_INTEL_P5:
53       case PERFCTR_X86_INTEL_P5MMX:
54       case PERFCTR_X86_CYRIX_MII:
55         /* event 0x16 (INSTRUCTIONS_EXECUTED), count at CPL 3 */
56         evntsel0 = 0x16 | (2 << 6);
57         break;
58       case PERFCTR_X86_INTEL_P6:
59       case PERFCTR_X86_INTEL_PII:
60       case PERFCTR_X86_INTEL_PIII:
61       case PERFCTR_X86_AMD_K7:
62       case PERFCTR_X86_AMD_K8:
63         /* event 0xC0 (INST_RETIRED), count at CPL > 0, Enable */
64         evntsel0 = 0xC0 | (1 << 16) | (1 << 22);
65         break;
66       case PERFCTR_X86_WINCHIP_C6:
67         tsc_on = 0;             /* no working TSC available */
68         evntsel0 = 0x02;        /* X86_INSTRUCTIONS */
69         break;
70       case PERFCTR_X86_WINCHIP_2:
71         tsc_on = 0;             /* no working TSC available */
72         evntsel0 = 0x16;        /* INSTRUCTIONS_EXECUTED */
73         break;
74       case PERFCTR_X86_VIA_C3:
75         pmc_map0 = 1;           /* redirect PMC0 to PERFCTR1 */
76         evntsel0 = 0xC0;        /* INSTRUCTIONS_EXECUTED */  
77         break;
78       case PERFCTR_X86_INTEL_P4:
79       case PERFCTR_X86_INTEL_P4M2:
80         /* PMC0: IQ_COUNTER0 with fast RDPMC */
81         pmc_map0 = 0x0C | (1 << 31);
82         /* IQ_CCCR0: required flags, ESCR 4 (CRU_ESCR0), Enable */
83         evntsel0 = (0x3 << 16) | (4 << 13) | (1 << 12);
84         /* CRU_ESCR0: event 2 (instr_retired), NBOGUSNTAG, CPL>0 */
85         control.cpu_control.p4.escr[0] = (2 << 25) | (1 << 9) | (1 << 2);
86         break;
87     default: {
88           char *str = "cpu type not supported - perfctr init failed!!\n";
89           syscall(SYS_write, 2, str, strlen(str));
90           exit(1);
91         }
92     }
93     control.cpu_control.tsc_on = tsc_on;
94     control.cpu_control.nractrs = nractrs;
95     control.cpu_control.pmc_map[0] = pmc_map0;
96     control.cpu_control.evntsel[0] = evntsel0;
97
98     if (!nractrs) {
99       //output("error: your CPU (%s) doesn't support PMC timing\n", perfctr_info_cpu_name(&info));
100       char *str = "error: your CPU doesn't support PMC timing\n";
101       syscall(SYS_write, 2, str, strlen(str));
102       exit(1);
103     }
104
105     // start the perfctr
106     if( vperfctr_control(clock_perfctr, &control) < 0 ) {
107       char *str = "vperfctr_control failed!!!\n";
108       syscall(SYS_write, 2, str, strlen(str));
109       exit(1);
110     }
111 }
112
113 #endif
114
115
116
117
118 /**
119  * calibrate the cycle clock to wall-clock time. This is rough, but
120  * hopefully good enough for our purposes.
121  **/
122
123 cpu_tick_t ticks_per_nanosecond  = 6*10e2;
124 cpu_tick_t ticks_per_microsecond = 6*10e5;
125 cpu_tick_t ticks_per_millisecond = 6*10e8;
126 cpu_tick_t ticks_per_second      = 6*10e11;
127 cpu_tick_t real_start_ticks = 0;
128 cpu_tick_t virtual_start_ticks = 0;
129
130
131 #define __usecs(t) (1e6*(long long)t.tv_sec + t.tv_usec)
132
133 static long long timing_loop()
134 {
135   struct timeval start_tv, end_tv;
136   long usec;
137   cpu_tick_t start_ticks, end_ticks;
138
139   while( 1 ) {
140     // start the counter right when the clock changes
141     gettimeofday(&start_tv, NULL);
142     usec = start_tv.tv_usec;
143     do {
144       gettimeofday(&start_tv, NULL);
145       GET_REAL_CPU_TICKS( start_ticks );
146     } while( start_tv.tv_usec == usec );
147
148     // now do the timing loop
149     do {
150       gettimeofday(&end_tv, NULL);
151       GET_REAL_CPU_TICKS( end_ticks );
152     } while( __usecs(end_tv) < __usecs(start_tv)+1000 );
153
154     if(__usecs(end_tv) == __usecs(start_tv)+1000)
155       break;
156   }
157   
158   return end_ticks - start_ticks;
159 }
160
161
162 void init_cycle_clock() __attribute__((constructor));
163 void init_cycle_clock(void)
164 {
165   static int init_done = 0;
166   int i;
167   long long val = 0;
168
169   if(init_done) return;
170   init_done = 1;
171
172 #ifdef USE_PERFCTR
173   init_perfctr();
174 #endif
175   
176   // collect some samples
177   for(i=0; i<10; i++) {
178     val += timing_loop();
179   }
180   val = val / 10;
181
182   ticks_per_second      = val * 1e3;
183   ticks_per_millisecond = val * 1e0;
184   ticks_per_microsecond = val / 1e3;
185   ticks_per_nanosecond  = val / 1e6;
186
187   GET_REAL_CPU_TICKS( real_start_ticks );
188   GET_CPU_TICKS( virtual_start_ticks );
189 }
190
191
192
193
194 /*
195
196 #include <sys/time.h>
197 #include <unistd.h>
198
199 #include "misc.h"
200 #include "debug.h"
201
202 #ifndef DEBUG_misc_c
203 #undef debug
204 #define debug(...)
205 #undef tdebug
206 #define tdebug(...)
207 #endif
208
209
210 long long current_usecs()
211 {
212   struct timeval tv;
213   int rv;
214   rv = gettimeofday(&tv,NULL);
215   assert (rv == 0);
216
217   return ((long long)tv.tv_sec * 1000000) + tv.tv_usec;
218 }
219
220 */