erroneously checked in
[codemux.git] / gettimeofdayex.c
1 #ifndef _GNU_SOURCE
2 #define _GNU_SOURCE
3 #endif
4
5 #include <stdio.h>
6 #include <sys/types.h>
7 #include <sys/unistd.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "gettimeofdayex.h"
11
12 #if defined(__linux) && !defined(ALPHA)
13
14 /* Macros */
15 #define rdtsc(low, high) \
16    asm volatile("rdtsc":"=a" (low), "=d" (high))
17
18 /* get cycle counts */
19 #define GET_CC(cc)                       \
20 do                                       \
21 {                                        \
22    cc = 0;                               \
23    unsigned long __cc_low__,__cc_high__; \
24    rdtsc(__cc_low__,__cc_high__);        \
25    cc = __cc_high__;                     \
26    cc = (cc << 32) + __cc_low__;         \
27 }                                        \
28 while(0)
29
30 /*-------------------------------------------------------------------------*/
31 static int
32 get_cpu_speed(double* cpu_speed) 
33 {
34    FILE* fp = NULL;
35    char  *line = NULL;
36    size_t len = 0;
37    ssize_t num;
38    char* ptr  = 0;
39
40    if (cpu_speed == NULL) 
41      return -1;
42
43    if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) 
44      return -1;
45
46    while ((num = getline(&line, &len, fp)) != -1) {
47       ptr = strtok(line, ":\n");
48       if (ptr && strstr(ptr, "cpu MHz")) {
49          ptr = strtok(0," \r\t\n");
50          *cpu_speed = strtod(ptr, 0);
51          break;
52       }
53    }
54    if (line) 
55      free(line);
56
57    fclose(fp);
58    return (*cpu_speed == 0) ? -1 : 0;
59 }
60
61 /*--------------------------------------------------------------------------*/
62 int 
63 gettimeofdayex(struct timeval *tv, struct timezone *tz)
64 {
65 #define MAX_64_BIT_NUM ((unsigned long long)(-1))
66
67   /* TO DO: timezone adjustment */
68   static int first = 1, impossible = 0;
69   static double cpu_speed;
70   static struct timeval start;
71   static unsigned long long cc_start;
72   unsigned long long cc_now, cc_diff, usec;
73
74   /* initialize : get the current time 
75      and fix it as a starting point */
76   if (first) {
77     if (get_cpu_speed(&cpu_speed) < 0)
78       impossible = 1;
79
80     GET_CC(cc_start);
81     gettimeofday(&start, 0);
82     if (tv)
83       *tv = start;
84     first = 0;
85     return 0;
86   }
87
88   /* if it's impossible to get cycle counts, 
89      then use original gettimeofday() */
90   if (impossible)
91     return gettimeofday(tv, tz);
92
93   if (tv) {
94     GET_CC(cc_now);
95
96     /* when overflow happens, we need to take care of the carry bit,
97        otherwise we get wrong result since we are using unsigned variables.
98        assuming cycle counter starts from zero at time zero,
99        this would happen after 136 years on 4GHz CPU.
100        however, lets just play on the safer side.
101     */
102
103     cc_diff = (cc_now < cc_start) ? cc_now + (MAX_64_BIT_NUM - cc_start)
104                                   : cc_now - cc_start;
105     usec = (unsigned long long)(cc_diff / cpu_speed);
106
107     *tv = start;
108     tv->tv_sec  += (usec / 1000000);
109     tv->tv_usec += (usec % 1000000);
110
111     if (tv->tv_usec >= 1000000) {
112       tv->tv_sec++;
113       tv->tv_usec -= 1000000;
114     }
115   }
116
117   return 0;
118 }
119
120 /*--------------------------------------------------------------------------*/
121 time_t 
122 timeex(time_t *t)
123 {
124   /* simple version of time() */
125   struct timeval s;
126
127   gettimeofdayex(&s, NULL);
128   if (t)
129     *t = (time_t)s.tv_sec;
130
131   return (time_t)s.tv_sec;
132 }
133
134 #else
135 #include <time.h>
136 /*--------------------------------------------------------------------------*/
137 int 
138 gettimeofdayex(struct timeval *tv, struct timezone *tz)
139 {
140   return(gettimeofday(tv, tz));
141 }
142 /*--------------------------------------------------------------------------*/
143 time_t 
144 timeex(time_t *t)
145 {
146   return(time(t));
147 }
148 /*--------------------------------------------------------------------------*/
149 #endif