4 * License : GNU GPL v.2
5 * Description : PowerPC timestamping function
6 * Author : Martin Zidek
15 #include <timing_config.h>
18 #define TS_SIZE 4500000
19 #define TB_TO_NS_SHIFT 5
21 //#define mulhdu(a,b) ((uint64_t)((double)a * (double)b)>>64)
22 #define tb_to_sched_clock(tb,shift) (tb << shift)
24 #ifdef CONFIG_TIMING_IPOINT_ASM
25 typedef struct timestamp_str {
31 #ifdef CONFIG_TIMING_IPOINT_CLOCK_GETTIME
32 typedef struct timestamp_str {
38 unsigned long long tb_to_ns_scale = 0xf26c9b26c9b26c9bULL;
40 clockid_t clk_id = -1;
41 timestamp_t ts[TS_SIZE];
42 timestamp_t *timestamp_ptr = ts;
43 timestamp_t *timestamp_buff_end = &ts[TS_SIZE];
44 bool timestamp_enabled = true;
46 struct timespec meas_start_ts;
50 void timing_statistics_asm(void);
51 void timing_output_trace_screen(void);
52 void timing_output_trace_file(void);
53 void timing_statistics_clock_gettime(void);
55 uint64_t mulhdu(uint64_t a, uint64_t b)
58 res = ((long double)a*(long double)b)/pow(2.0,64.0);
70 // "1: beqlr cr1\n" /* all done if high part of A is 0 */
90 #ifdef CONFIG_TIMING_IPOINT_ASM
91 uint64_t restore_tb(uint32_t tbu, uint32_t tbl)
102 uint64_t get_boot_tb(void)
107 f = fopen("boot_tb","r");
108 if(fscanf(f, "%llu", &boot_tb)==0)
109 printf("timing: boot_tb not read successfuly!\n");
114 void print_tstamp_to_schedclock(timestamp_t *ts)
117 uint64_t sched_clock;
118 unsigned long int sec, usec;
120 tb = restore_tb(ts->tbu, ts->tbl);
121 // printf("tb=%llu\n",tb);
122 // printf("mulhdu=%llu\n",mulhdu(tb - get_boot_tb(), tb_to_ns_scale));
123 sched_clock = (uint64_t)((long double)(mulhdu(tb - get_boot_tb(), tb_to_ns_scale))*pow(2.0,5.0));
124 // printf("sched_clock=%llu\n",sched_clock);
127 sched_clock=sched_clock / 1000;
129 sec = (uint32_t) (sched_clock/1000000);
130 usec = (sched_clock % 1000000ULL);
132 #ifdef CONFIG_TIMING_OUTPUT_SCREEN
133 printf("%d %5lu.%06lu\n", ts->id, sec, usec);
135 #ifdef CONFIG_TIMING_OUTPUT_FILE
136 fprintf(file, "%5lu.%06lu\t%d\t%d\tR\t%llu\n", sec, usec, pid, ts->id, tb);
141 timestamp_t * timestamp_handle_overflow(void)
143 static bool first_overflow = true;
144 /* Here we can also implement atomic wrap-around and return
146 timestamp_enabled = false;
148 printf("timestamp overflow\n");
149 first_overflow = false;
155 void timing_ipoint_dummy(unsigned char id)
157 printf("timing: Instrumentation point type not set!\n");
160 #ifdef CONFIG_TIMING_IPOINT_ASM
161 void timing_ipoint_asm(unsigned char id)
163 timestamp_t *p, *pinc;
164 uint32_t tbu, tb, tbu2;
166 /* Store current TB */
174 : "=r" (tbu), "=r" (tb), "=r" (tbu2) /* Outputs */
176 : "cr0" ); /* CR0 changes */
183 : "=&b" (p), "=&b" (pinc), "=m" (timestamp_ptr)
184 : "n" (sizeof(timestamp_t)), "b" (×tamp_ptr)
187 if (p >= timestamp_buff_end) {
188 p = timestamp_handle_overflow();
199 #ifdef CONFIG_TIMING_IPOINT_CLOCK_GETTIME
200 void timing_ipoint_clock_gettime(unsigned char id)
202 timestamp_t *p, *pinc;
206 clock_gettime(clk_id, &(p->ts));
208 // timestamp_ptr = pinc;
209 if (p >= timestamp_buff_end) {
210 p = timestamp_handle_overflow();
221 void timing_init(void)
223 printf("Timing analysis turned on - initialising\n");
225 /*just for case no ipoint function configured during compile-time*/
226 timing_ipoint = timing_ipoint_dummy;
227 #ifdef CONFIG_TIMING_IPOINT_ASM
228 timing_ipoint = timing_ipoint_asm;
229 timing_statistics = timing_statistics_asm;
231 #ifdef CONFIG_TIMING_IPOINT_CLOCK_GETTIME
232 timing_ipoint = timing_ipoint_clock_gettime;
233 timing_statistics = timing_statistics_clock_gettime;
235 system("mount -t debugfs trace /debug");
236 system("echo sched_switch > /debug/tracing/current_tracer");
238 #ifdef CONFIG_CLOCK_RT
239 clk_id = CLOCK_REALTIME;
241 #ifdef CONFIG_CLOCK_MONOTONIC
242 clk_id = CLOCK_MONOTONIC;
244 #ifdef CONFIG_CLOCK_MONOTONIC_RAW
245 clk_id = CLOCK_MONOTONIC_RAW;
247 #ifdef CONFIG_CLOCK_PROCESS
248 clk_id = CLOCK_PROCESS_CPUTIME_ID;
250 #ifdef CONFIG_CLOCK_THREAD
251 clk_id = CLOCK_THREAD_CPUTIME_ID;
254 printf("timing: Clock source not set during compile time! Unable to perform timestamping!\n");
258 #ifdef CONFIG_TIMING_OUTPUT_SCREEN
259 timing_output_trace = timing_output_trace_screen;
261 #ifdef CONFIG_TIMING_OUTPUT_FILE
262 timing_output_trace = timing_output_trace_file;
264 printf("Timing library initialized!\n");
265 system("dmesg | grep boot_tb | sed 's#.*boot_tb\\=\\([0-9]*\\).*#\\1#' | tee boot_tb");
266 system("echo 1 > /debug/tracing/tracing_enabled");
267 clock_gettime(clk_id, &meas_start_ts);
272 system("echo 0 > /debug/tracing/tracing_enabled");
273 #ifdef CONFIG_TIMING_OUTPUT_FILE
274 system("cat /debug/tracing/trace | tee taskswitch.log");
276 #ifdef CONFIG_TIMING_OUTPUT_SCREEN
277 system("cat /debug/tracing/trace");
279 system("echo nop > /debug/tracing/current_tracer");
282 #ifdef CONFIG_TIMING_IPOINT_ASM
283 void print_ts_asm(timestamp_t *ts)
285 printf("%d %llu\n", ts->id, restore_tb(ts->tbu, ts->tbl));
289 void timing_output_trace_screen(void)
291 timestamp_t *ts_iter;
293 printf("Timing analysis application trace\n");
295 if(timestamp_enabled)
296 while(ts_iter != (timestamp_ptr+1))
298 #ifdef CONFIG_TIMING_IPOINT_ASM
299 // print_ts_asm(ts_iter);
300 print_tstamp_to_schedclock(ts_iter);
306 printf("got %d timestamps over limit\n",cnt);
309 double timespec2sec(struct timespec *tspec)
313 result = tspec->tv_sec + (tspec->tv_nsec*0.000000001);
318 void timing_output_trace_file(void)
320 timestamp_t *ts_iter;
323 file = fopen(CONFIG_TIMING_OUTPUT_FILENAME, "w+");
325 perror("timing file open error");
328 fprintf(file, "Timing analysis application trace\n");
330 if(timestamp_enabled)
331 while(ts_iter != (timestamp_ptr+1))
333 #ifdef CONFIG_TIMING_IPOINT_ASM
334 print_tstamp_to_schedclock(ts_iter);
335 // fprintf(file, "%d %llu\n", ts_iter->id, restore_tb(ts_iter->tbu, ts_iter->tbl));
337 #ifdef CONFIG_TIMING_IPOINT_CLOCK_GETTIME
338 fprintf(file, "%d %.6f\n", ts_iter->id, timespec2sec(&ts_iter->ts));
344 fprintf(file, "got %d timestamps over limit\n",cnt);
349 #ifdef CONFIG_TIMING_IPOINT_ASM
350 double sub_timestamps_us(timestamp_t *t1, timestamp_t *t2)
353 uint64_t t1_val, t2_val;
362 result = (double)(t2_val - t1_val)/CONFIG_TIMING_TB_FREQ;
368 void timing_statistics_asm(void)
370 timestamp_t *ts_iter;
373 printf("Timing Statistics\n");
374 printf("-----------------\n");
377 if(timestamp_enabled)
378 while(ts_iter != (timestamp_ptr+1))
381 printf("%3.2f\n", sub_timestamps_us(ts_iter-1, ts_iter));
387 printf("got %d timestamps over limit\n",cnt);
391 double sub_ts_us(struct timespec start, struct timespec end)
393 struct timespec temp;
396 if ((end.tv_nsec-start.tv_nsec)<0) {
397 temp.tv_sec = end.tv_sec-start.tv_sec-1;
398 temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
400 temp.tv_sec = end.tv_sec-start.tv_sec;
401 temp.tv_nsec = end.tv_nsec-start.tv_nsec;
404 ret = (temp.tv_sec * 1000000.0) + (temp.tv_nsec/1000.0);
409 #ifdef CONFIG_TIMING_IPOINT_CLOCK_GETTIME
410 void timing_statistics_clock_gettime(void)
412 timestamp_t *ts_iter;
415 printf("Highrest_Statistics\n");
418 if(timestamp_enabled)
419 while(ts_iter != (timestamp_ptr+1))
422 printf("%3.2f\n", sub_ts_us((ts_iter-1)->ts,(ts_iter)->ts));
428 printf("got %d timestamps over limit\n",cnt);
432 void timing_set_pid(pid_t set_pid)