Multiple changes for June release
[samplevnf.git] / VNFs / DPPD-PROX / clock.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include "clock.h"
18
19 #include <stdio.h>
20 #include <string.h>
21
22 #include <rte_cycles.h>
23
24 /* Calibrate TSC overhead by reading NB_READ times and take the smallest value.
25    Bigger values are caused by external influence and can be discarded. The best
26    estimate is the smallest read value. */
27 #define NB_READ 10000
28
29 uint32_t rdtsc_overhead;
30 uint32_t rdtsc_overhead_stats;
31
32 uint64_t thresh;
33 uint64_t tsc_hz;
34
35 /* calculate how much overhead is involved with calling rdtsc. This value has
36    to be taken into account where the time spent running a small piece of code
37    is measured */
38 static void init_tsc_overhead(void)
39 {
40         volatile uint32_t min_without_overhead = UINT32_MAX;
41         volatile uint32_t min_with_overhead = UINT32_MAX;
42         volatile uint32_t min_stats_overhead = UINT32_MAX;
43         volatile uint64_t start1, end1;
44         volatile uint64_t start2, end2;
45
46         for (uint32_t i = 0; i < NB_READ; ++i) {
47                 start1 = rte_rdtsc();
48                 end1   = rte_rdtsc();
49
50                 start2 = rte_rdtsc();
51                 end2   = rte_rdtsc();
52                 end2   = rte_rdtsc();
53
54                 if (min_without_overhead > end1 - start1) {
55                         min_without_overhead = end1 - start1;
56                 }
57
58                 if (min_with_overhead > end2 - start2) {
59                         min_with_overhead = end2 - start2;
60                 }
61         }
62
63         rdtsc_overhead = min_with_overhead - min_without_overhead;
64
65         start1 = rte_rdtsc();
66         end1   = rte_rdtsc();
67         /* forbid the compiler to optimize this dummy variable */
68         volatile int dummy = 0;
69         for (uint32_t i = 0; i < NB_READ; ++i) {
70                 start1 = rte_rdtsc();
71                 dummy += 32;
72                 end1   = rte_rdtsc();
73
74                 if (min_stats_overhead > end2 - start2) {
75                         min_stats_overhead = end1 - start1;
76                 }
77         }
78
79         rdtsc_overhead_stats = rdtsc_overhead + min_stats_overhead - min_without_overhead;
80 }
81
82 void clock_init(void)
83 {
84         init_tsc_overhead();
85         tsc_hz = rte_get_tsc_hz();
86         thresh = UINT64_MAX/tsc_hz;
87 }
88
89 uint64_t str_to_tsc(const char *from)
90 {
91         const uint64_t hz = rte_get_tsc_hz();
92         uint64_t ret;
93         char str[16];
94
95         strncpy(str, from, sizeof(str));
96
97         char *frac = strchr(str, '.');
98
99         if (frac) {
100                 *frac = 0;
101                 frac++;
102         }
103
104         ret = hz * atoi(str);
105
106         if (!frac)
107                 return ret;
108
109         uint64_t nsec = 0;
110         uint64_t multiplier = 100000000;
111
112         for (size_t i = 0; i < strlen(frac); ++i) {
113                 nsec += (frac[i] - '0') * multiplier;
114                 multiplier /= 10;
115         }
116
117         /* Wont overflow until CPU freq is ~18.44 GHz */
118         ret += hz * nsec/1000000000;
119
120         return ret;
121 }
122
123 uint64_t sec_to_tsc(uint64_t sec)
124 {
125         if (sec < UINT64_MAX/rte_get_tsc_hz())
126                 return sec * rte_get_tsc_hz();
127         else
128                 return UINT64_MAX;
129 }
130
131 uint64_t msec_to_tsc(uint64_t msec)
132 {
133         if (msec < UINT64_MAX/rte_get_tsc_hz())
134                 return msec * rte_get_tsc_hz() / 1000;
135         else
136                 return msec / 1000 * rte_get_tsc_hz();
137 }
138
139 uint64_t usec_to_tsc(uint64_t usec)
140 {
141         if (usec < UINT64_MAX/rte_get_tsc_hz())
142                 return usec * rte_get_tsc_hz() / 1000000;
143         else
144                 return usec / 1000000 * rte_get_tsc_hz();
145 }
146
147 uint64_t nsec_to_tsc(uint64_t nsec)
148 {
149         if (nsec < UINT64_MAX/rte_get_tsc_hz())
150                 return nsec * rte_get_tsc_hz() / 1000000000;
151         else
152                 return nsec / 1000000000 * rte_get_tsc_hz();
153 }
154
155 uint64_t tsc_to_msec(uint64_t tsc)
156 {
157         if (tsc < UINT64_MAX / 1000) {
158                 return tsc * 1000 / rte_get_tsc_hz();
159         } else {
160                 return tsc / (rte_get_tsc_hz() / 1000);
161         }
162 }
163
164 uint64_t tsc_to_usec(uint64_t tsc)
165 {
166         if (tsc < UINT64_MAX / 1000000) {
167                 return tsc * 1000000 / rte_get_tsc_hz();
168         } else {
169                 return tsc / (rte_get_tsc_hz() / 1000000);
170         }
171 }
172
173 uint64_t tsc_to_nsec(uint64_t tsc)
174 {
175         if (tsc < UINT64_MAX / 1000000000) {
176                 return tsc * 1000000000 / rte_get_tsc_hz();
177         } else {
178                 return tsc / (rte_get_tsc_hz() / 1000000000);
179         }
180 }
181
182 uint64_t tsc_to_sec(uint64_t tsc)
183 {
184         return tsc / rte_get_tsc_hz();
185 }
186
187 struct time_unit tsc_to_time_unit(uint64_t tsc)
188 {
189         struct time_unit ret;
190         uint64_t hz = rte_get_tsc_hz();
191
192         ret.sec = tsc/hz;
193         ret.nsec = (tsc - ret.sec*hz)*1000000000/hz;
194
195         return ret;
196 }
197
198 uint64_t time_unit_to_usec(struct time_unit *time_unit)
199 {
200         return time_unit->sec * 1000000 + time_unit->nsec/1000;
201 }
202
203 uint64_t time_unit_to_nsec(struct time_unit *time_unit)
204 {
205         return time_unit->sec * 1000000000 + time_unit->nsec;
206 }
207
208 int time_unit_cmp(struct time_unit *left, struct time_unit *right)
209 {
210         if (left->sec < right->sec)
211                 return -1;
212         if (left->sec > right->sec)
213                 return 1;
214
215         if (left->nsec < right->nsec)
216                 return -1;
217         if (left->nsec > right->nsec)
218                 return -1;
219         return 0;
220 }
221
222 uint64_t freq_to_tsc(uint64_t times_per_sec)
223 {
224         return rte_get_tsc_hz()/times_per_sec;
225 }
226
227 void tsc_to_tv(struct timeval *tv, const uint64_t tsc)
228 {
229         uint64_t hz = rte_get_tsc_hz();
230         uint64_t sec = tsc/hz;
231
232         tv->tv_sec = sec;
233         tv->tv_usec = ((tsc - sec * hz) * 1000000) / hz;
234 }
235
236 void tv_to_tsc(const struct timeval *tv, uint64_t *tsc)
237 {
238         uint64_t hz = rte_get_tsc_hz();
239         *tsc = tv->tv_sec * hz;
240         *tsc += tv->tv_usec * hz / 1000000;
241 }
242
243 struct timeval tv_diff(const struct timeval *cur, const struct timeval *next)
244 {
245         uint64_t sec, usec;
246
247         sec = next->tv_sec - cur->tv_sec;
248         if (next->tv_usec < cur->tv_usec) {
249                 usec = next->tv_usec + 1000000 - cur->tv_usec;
250                 sec -= 1;
251         }
252         else
253                 usec = next->tv_usec - cur->tv_usec;
254
255         struct timeval ret = {
256                 .tv_sec  = sec,
257                 .tv_usec = usec,
258         };
259
260         return ret;
261 }