-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathopt_time.h
190 lines (167 loc) · 4.97 KB
/
opt_time.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// opt_time_r.h
//
// thread safe version of opt_time.h
// Optimized system time functions and Attr_API based on them
// [email protected] 2014-06-12
//
#ifndef __OPT_TIME_H__
#define __OPT_TIME_H__
#include <stdint.h>
#include <sys/time.h>
#include <string.h>
//
// optimized gettimeofday()/time()
//
// Limitations:
// 1, here we assume the CPU speed is 1GB, if your CPU is 4GB, it will run well, but if your CPU is 10GB, please adjust CPU_SPEED_GB
// 2, these functions have precision of 1ms, if you wish higher precision, please adjust REGET_TIME_US, but it will degrade performance
//
#ifdef __x86_64__
#define RDTSC() ({ register uint32_t a,d; __asm__ __volatile__( "rdtsc" : "=a"(a), "=d"(d)); (((uint64_t)a)+(((uint64_t)d)<<32)); })
#else
#define RDTSC() ({ register uint64_t tim; __asm__ __volatile__( "rdtsc" : "=A"(tim)); tim; })
#endif
// atomic operations
#ifdef __x86_64__
#define ASUFFIX "q"
#else
#define ASUFFIX "l"
#endif
#define XCHG(ptr, val) __asm__ __volatile__("xchg"ASUFFIX" %2,%0" :"+m"(*ptr), "=r"(val) :"1"(val))
#define AADD(ptr, val) __asm__ __volatile__("lock ; add"ASUFFIX" %1,%0" :"+m" (*ptr) :"ir" (val))
#define CAS(ptr, val_old, val_new)({ char ret; __asm__ __volatile__("lock; cmpxchg"ASUFFIX" %2,%0; setz %1": "+m"(*ptr), "=q"(ret): "r"(val_new),"a"(val_old): "memory"); ret;})
#define REGET_TIME_US_GTOD 1
#define REGET_TIME_US_TIME 1
#define CPU_SPEED_GB 1 // assume a 1GB CPU
static inline int opt_gettimeofday(struct timeval *tv, void *restrict not_used)
{
static __thread volatile uint64_t walltick;
static __thread volatile struct timeval walltime;
static __thread volatile long lock = 0;
const unsigned int max_ticks = CPU_SPEED_GB*1000*REGET_TIME_US_GTOD;
if(walltime.tv_sec==0 || (RDTSC()-walltick) > max_ticks)
{
if(lock==0 && CAS(&lock, 0UL, 1UL)) // try lock
{
gettimeofday((struct timeval*)&walltime, not_used);
walltick = RDTSC();
lock = 0; // unlock
}
else // try lock failed, use system time
{
return gettimeofday(tv, not_used);
}
}
memcpy(tv, (void*)&walltime, sizeof(struct timeval));
return 0;
}
// same algorithm with gettimeofday, except with different precision defined as REGET_TIME_US_TIME
static inline time_t opt_time(time_t *t)
{
static __thread volatile uint64_t walltick;
static __thread volatile struct timeval walltime;
static __thread volatile long lock = 0;
const unsigned int max_ticks = CPU_SPEED_GB*1000*REGET_TIME_US_TIME;
if(walltime.tv_sec==0 || (RDTSC()-walltick) > max_ticks)
{
if(lock==0 && CAS(&lock, 0UL, 1UL)) // try lock
{
gettimeofday((struct timeval*)&walltime, NULL);
walltick = RDTSC();
lock = 0; // unlock
}
else // try lock failed, use system time
{
struct timeval tv;
gettimeofday(&tv, NULL);
if(t) *t = tv.tv_sec;
return tv.tv_sec;
}
}
if(t) *t = walltime.tv_sec;
return walltime.tv_sec;
}
#ifndef gettimeofday
#define gettimeofday(a, b) opt_gettimeofday(a, b)
#endif
#ifndef time
#define time(t) opt_time(t)
#endif
//
// Optimized Attr_API based on opt_time()
// Add to a static counter and report once in a second
// Limitations:
// 1, attr should be a const value, you must not call Frequent_Attr_API(iAttr, 1) when iAttr differs for each call
// 2, should only be used for frequent reports rather than exception cases, since Frequent_Attr_API does not call Attr_API at once
//
// If you don't wish to call opt_time() frequently, supply your own current time
#define Frequent_Attr_API_Ext(attr, count, curtime) do { \
static volatile time_t tPrevReport##attr = 0; \
static volatile long iReportNum##attr = 0; \
AADD(&iReportNum##attr, count); \
if(tPrevReport##attr != curtime) \
{ \
long cnt = 0; \
XCHG(&iReportNum##attr, cnt);\
if(cnt) \
{ \
Attr_API(attr, cnt); \
} \
tPrevReport##attr = curtime; \
} \
} while(0)
#define Frequent_Attr_API(attr, count) do { time_t t=opt_time(NULL); Frequent_Attr_API_Ext(attr, count, t); } while(0)
#ifdef TEST_TIME
#include <stdio.h>
int main(int argc, char *argv[])
{
if(argc!=2)
{
printf("usage:\n");
printf(" %s time # test time performance\n", argv[0]);
printf(" %s gettimeofday # test gettimeofday performance\n", argv[0]);
printf(" %s attr # test attr api performance\n", argv[0]);
return -1;
}
if(argv[1][0]=='g')
{
int i;
struct timeval tv;
for(i=0; i<100000000; i++)
{
opt_gettimeofday(&tv, NULL);
if(i%10000000==0)
printf("%u-%u\n", tv.tv_sec, tv.tv_usec);
}
}
else if(argv[1][0]=='t')
{
int i;
time_t t;
for(i=0; i<100000000; i++)
{
t = opt_time(NULL);
if(i%10000000==0)
printf("%u\n", t);
}
}
else
{
int i;
for(i=0; i<10000000; i++)
{
Frequent_Attr_API(51830, 1);
Frequent_Attr_API(51831, 1);
Frequent_Attr_API(51832, 1);
Frequent_Attr_API(51833, 1);
Frequent_Attr_API(51834, 1);
Frequent_Attr_API(51835, 1);
Frequent_Attr_API(51836, 1);
Frequent_Attr_API(51837, 1);
Frequent_Attr_API(51838, 1);
Frequent_Attr_API(51839, 1);
}
}
}
#endif
#endif //__OPT_TIME_H__