]> rtime.felk.cvut.cz Git - eurobot/public.git/blob - src/timing/timing.c
timing: clock_gettime() version working
[eurobot/public.git] / src / timing / timing.c
1 /*
2  * rpt.c       08/09/29
3  * 
4  * License      : GNU GPL v.2
5  * Description  : PowerPC timestamping function
6  * Author       : Martin Zidek
7  */
8
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stdint.h>
13 #include <timing.h>
14 #include <time.h>
15 #include <timing_config.h>
16
17 #define TS_SIZE 4500000
18
19 #ifdef CONFIG_TIMING_IPOINT_ASM
20 typedef struct timestamp_str {
21         uint32_t tbu, tbl;
22         uint16_t id;
23 } timestamp_t;
24 #endif
25
26 #ifdef CONFIG_TIMING_IPOINT_CLOCK_GETTIME
27 typedef struct timestamp_str {
28         struct timespec ts;
29         uint16_t id;
30 } timestamp_t;
31 #endif
32
33 clockid_t clk_id = -1;
34 timestamp_t ts[TS_SIZE];
35 timestamp_t *timestamp_ptr = ts;
36 timestamp_t *timestamp_buff_end = &ts[TS_SIZE];
37 bool timestamp_enabled = true;
38 static int cnt=0;
39 static int freq=0;
40 struct timespec meas_start_ts;
41
42 void timing_statistics_asm(void);
43 void timing_output_trace_screen(void);
44 void timing_output_trace_file(void);
45 void timing_statistics_clock_gettime(void);
46
47 timestamp_t * timestamp_handle_overflow(void)
48 {
49         static bool first_overflow = true;
50         /* Here we can also implement atomic wrap-around and return
51          * true. */
52         timestamp_enabled = false;
53         if(first_overflow) {
54                 printf("timestamp overflow\n");
55                 first_overflow = false;
56         }
57         cnt++;
58         return 0;
59 }
60
61 void timing_ipoint_dummy(unsigned char id)
62 {
63         printf("timing: Instrumentation point type not set!\n");
64 }
65
66 #ifdef CONFIG_TIMING_IPOINT_ASM
67 void timing_ipoint_asm(unsigned char id)
68 {   
69         timestamp_t *p, *pinc; 
70         uint32_t tbu, tb, tbu2;
71
72         /* Store current TB */
73         asm volatile (
74                 "1:\n"  
75                 "       mftbu %0\n"
76                 "       mftb  %1\n"
77                 "       mftbu %2\n"
78                 "       cmpw  0,%0,%2\n"
79                 "       bne-  1b\n"
80                 : "=r" (tbu), "=r" (tb), "=r" (tbu2) /* Outputs */
81                 : /* No inputs */
82                 : "cr0" ); /* CR0 changes */
83
84         asm volatile (
85                 "1:       lwarx   %0,0,%4\n"
86                 "         addi    %1,%0,%3\n"
87                 "         stwcx.  %1,0,%4\n"
88                 "         bne-    1b\n"
89                 : "=&b" (p), "=&b" (pinc), "=m" (timestamp_ptr)
90                 : "n" (sizeof(timestamp_t)), "b" (&timestamp_ptr)
91                 : "cr0");
92
93         if (p >= timestamp_buff_end) {
94                 p = timestamp_handle_overflow();
95                 if (!p) 
96                         return;
97         }
98
99         p->id = id;
100         p->tbu = tbu;
101         p->tbl = tb;
102 }
103 #endif
104
105 #ifdef CONFIG_TIMING_IPOINT_CLOCK_GETTIME
106 void timing_ipoint_clock_gettime(unsigned char id)
107 {
108         timestamp_t *p, *pinc;
109         
110         p = timestamp_ptr;
111
112         clock_gettime(clk_id, &(p->ts));
113 //      pinc = p+1;
114 //      timestamp_ptr = pinc;
115         if (p >= timestamp_buff_end) {
116                 p = timestamp_handle_overflow();
117                 if (!p) 
118                         return;
119         }
120         else {
121                 p->id = id;
122                 timestamp_ptr++;
123         }
124 }
125 #endif
126
127 void timing_init(int init_freq)
128 {
129         printf("Timing analysis turned on - initialising\n");
130
131         /*just for case no ipoint function configured during compile-time*/
132         timing_ipoint = timing_ipoint_dummy;
133 #ifdef CONFIG_TIMING_IPOINT_ASM
134         timing_ipoint = timing_ipoint_asm;
135         timing_statistics = timing_statistics_asm;
136 #endif
137 #ifdef CONFIG_TIMING_IPOINT_CLOCK_GETTIME
138         timing_ipoint = timing_ipoint_clock_gettime;
139         timing_statistics = timing_statistics_clock_gettime;
140 #endif
141         system("mount -t debugfs trace /debug");
142         system("echo sched_switch > /debug/tracing/current_tracer");
143
144         freq = init_freq;
145 #ifdef CONFIG_CLOCK_RT
146         clk_id = CLOCK_REALTIME;
147 #endif
148 #ifdef CONFIG_CLOCK_MONOTONIC
149         clk_id = CLOCK_MONOTONIC;
150 #endif
151 #ifdef CONFIG_CLOCK_MONOTONIC_RAW
152         clk_id = CLOCK_MONOTONIC_RAW;
153 #endif
154 #ifdef CONFIG_CLOCK_PROCESS
155         clk_id = CLOCK_PROCESS_CPUTIME_ID;
156 #endif
157 #ifdef CONFIG_CLOCK_THREAD
158         clk_id = CLOCK_THREAD_CPUTIME_ID;
159 #endif
160         if(clk_id == -1) {
161                 printf("timing: Clock source not set during compile time! Unable to perform timestamping!\n");
162                 return;
163         }
164
165 #ifdef CONFIG_TIMING_OUTPUT_SCREEN
166         timing_output_trace = timing_output_trace_screen;
167 #endif
168 #ifdef CONFIG_TIMING_OUTPUT_FILE
169         timing_output_trace = timing_output_trace_file;
170 #endif
171         printf("Timing library initialized!\n");
172         system("dmesg | grep tb_orig_stamp | sed 's#.*tb_orig_stamp\\=\\([0-9]*\\).*#\\1#' | tee tb_orig_stamp");
173         system("echo 1 > /debug/tracing/tracing_enabled");
174         clock_gettime(clk_id, &meas_start_ts);
175 }
176
177 void timing_finish()
178 {
179         system("echo 0 > /debug/tracing/tracing_enabled");
180 #ifdef CONFIG_TIMING_OUTPUT_FILE
181         system("cat /debug/tracing/trace | tee taskswitch.log");
182 #endif
183         system("echo nop > /debug/tracing/current_tracer");
184 }
185
186 #ifdef CONFIG_TIMING_IPOINT_ASM
187 void print_ts_asm(timestamp_t *ts)
188 {
189         printf("%d %llu\n", ts->id, (uint64_t)((uint64_t)ts->tbu << 32 | ts->tbl));
190 }
191 #endif
192
193 void timing_output_trace_screen(void)
194 {
195         timestamp_t *ts_iter;
196         int i=0;
197         printf("Timing analysis application trace\n");
198         ts_iter = ts;
199         if(timestamp_enabled)
200         while(ts_iter != (timestamp_ptr+1))
201         {
202 #ifdef CONFIG_TIMING_IPOINT_ASM
203                 print_ts_asm(ts_iter);
204 #endif
205                 ts_iter++;
206                 i++;
207         }
208         else
209         printf("got %d timestamps over limit\n",cnt);
210 }
211
212 double timespec2sec(struct timespec *tspec)
213 {
214         double result;
215
216         result = tspec->tv_sec + (tspec->tv_nsec*0.000000001);
217
218         return result;
219 }
220
221 void timing_output_trace_file(void)
222 {
223         FILE *file;
224         timestamp_t *ts_iter;
225         int i=0;
226
227         file = fopen(CONFIG_TIMING_OUTPUT_FILENAME, "w+");
228         if(file == NULL) {
229                 perror("timing file open error");
230                 return;
231         }
232         fprintf(file, "Timing analysis application trace\n");
233         ts_iter = ts;
234         if(timestamp_enabled)
235         while(ts_iter != (timestamp_ptr+1))
236         {
237 #ifdef CONFIG_TIMING_IPOINT_ASM
238                 fprintf(file, "%d %llu\n", ts_iter->id, 
239                                 (uint64_t)((uint64_t)ts_iter->tbu << 32 | ts_iter->tbl));
240 #endif
241 #ifdef CONFIG_TIMING_IPOINT_CLOCK_GETTIME
242                 fprintf(file, "%d %.6f\n", ts_iter->id, timespec2sec(&ts_iter->ts));
243 #endif
244                 ts_iter++;
245                 i++;
246         }
247         else
248                 fprintf(file, "got %d timestamps over limit\n",cnt);
249
250         fclose(file);
251 }
252
253 #ifdef CONFIG_TIMING_IPOINT_ASM
254 double sub_timestamps_us(timestamp_t *t1, timestamp_t *t2)
255 {
256         double result;
257         uint64_t t1_val, t2_val;
258
259         t1_val = t1->tbu;
260         t1_val <<= 32;
261         t1_val |= t1->tbl;
262         t2_val = t2->tbu;
263         t2_val <<= 32;
264         t2_val |= t2->tbl;
265
266         result = (double)(t2_val - t1_val)/freq;
267         result *= 1000000.0;
268
269         return result;
270 }
271
272 void timing_statistics_asm(void)
273 {
274         timestamp_t *ts_iter;
275         int i=1;
276
277         printf("Timing Statistics\n");
278         printf("-----------------\n");
279         ts_iter = ts;
280
281         if(timestamp_enabled)
282                 while(ts_iter != (timestamp_ptr+1))
283                 {
284                         if(i%2 == 0) {
285                                 printf("%3.2f\n", sub_timestamps_us(ts_iter-1, ts_iter));
286                         }
287                         ts_iter++;
288                         i++;
289                 }
290         else
291         printf("got %d timestamps over limit\n",cnt);
292 }
293 #endif
294
295 double sub_ts_us(struct timespec start, struct timespec end)
296 {
297         struct timespec temp;
298         double ret;
299         
300         if ((end.tv_nsec-start.tv_nsec)<0) {
301                 temp.tv_sec = end.tv_sec-start.tv_sec-1;
302                 temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
303         } else {
304                 temp.tv_sec = end.tv_sec-start.tv_sec;
305                 temp.tv_nsec = end.tv_nsec-start.tv_nsec;
306         }
307
308         ret = (temp.tv_sec * 1000000.0) + (temp.tv_nsec/1000.0);
309         
310         return ret;
311 }
312
313 #ifdef CONFIG_TIMING_IPOINT_CLOCK_GETTIME
314 void timing_statistics_clock_gettime(void)
315 {
316         timestamp_t *ts_iter;
317         int i=1;
318
319         printf("Highrest_Statistics\n");
320         ts_iter = ts;
321
322         if(timestamp_enabled)
323                 while(ts_iter != (timestamp_ptr+1))
324                 {
325                         if(i%2 == 0) {
326                                 printf("%3.2f\n", sub_ts_us((ts_iter-1)->ts,(ts_iter)->ts));
327                         }
328                         ts_iter++;
329                         i++;
330                 }
331         else
332                 printf("got %d timestamps over limit\n",cnt);
333 }
334 #endif
335