Support packets in flight
[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 #include "prox_compat.h"
24
25 /* Calibrate TSC overhead by reading NB_READ times and take the smallest value.
26    Bigger values are caused by external influence and can be discarded. The best
27    estimate is the smallest read value. */
28 #define NB_READ 10000
29
30 uint32_t rdtsc_overhead;
31 uint32_t rdtsc_overhead_stats;
32
33 uint64_t thresh;
34 uint64_t tsc_hz;
35
36 /* calculate how much overhead is involved with calling rdtsc. This value has
37    to be taken into account where the time spent running a small piece of code
38    is measured */
39 static void init_tsc_overhead(void)
40 {
41         volatile uint32_t min_without_overhead = UINT32_MAX;
42         volatile uint32_t min_with_overhead = UINT32_MAX;
43         volatile uint32_t min_stats_overhead = UINT32_MAX;
44         volatile uint64_t start1, end1;
45         volatile uint64_t start2, end2;
46
47         for (uint32_t i = 0; i < NB_READ; ++i) {
48                 start1 = rte_rdtsc();
49                 end1   = rte_rdtsc();
50
51                 start2 = rte_rdtsc();
52                 end2   = rte_rdtsc();
53                 end2   = rte_rdtsc();
54
55                 if (min_without_overhead > end1 - start1) {
56                         min_without_overhead = end1 - start1;
57                 }
58
59                 if (min_with_overhead > end2 - start2) {
60                         min_with_overhead = end2 - start2;
61                 }
62         }
63
64         rdtsc_overhead = min_with_overhead - min_without_overhead;
65
66         start1 = rte_rdtsc();
67         end1   = rte_rdtsc();
68         /* forbid the compiler to optimize this dummy variable */
69         volatile int dummy = 0;
70         for (uint32_t i = 0; i < NB_READ; ++i) {
71                 start1 = rte_rdtsc();
72                 dummy += 32;
73                 end1   = rte_rdtsc();
74
75                 if (min_stats_overhead > end2 - start2) {
76                         min_stats_overhead = end1 - start1;
77                 }
78         }
79
80         rdtsc_overhead_stats = rdtsc_overhead + min_stats_overhead - min_without_overhead;
81 }
82
83 void clock_init(void)
84 {
85         init_tsc_overhead();
86         tsc_hz = rte_get_tsc_hz();
87         thresh = UINT64_MAX/tsc_hz;
88 }
89
90 uint64_t str_to_tsc(const char *from)
91 {
92         const uint64_t hz = rte_get_tsc_hz();
93         uint64_t ret;
94         char str[16];
95
96         prox_strncpy(str, from, sizeof(str));
97
98         char *frac = strchr(str, '.');
99
100         if (frac) {
101                 *frac = 0;
102                 frac++;
103         }
104
105         ret = hz * atoi(str);
106
107         if (!frac)
108                 return ret;
109
110         uint64_t nsec = 0;
111         uint64_t multiplier = 100000000;
112
113         for (size_t i = 0; i < strlen(frac); ++i) {
114                 nsec += (frac[i] - '0') * multiplier;
115                 multiplier /= 10;
116         }
117
118         /* Wont overflow until CPU freq is ~18.44 GHz */
119         ret += hz * nsec/1000000000;
120
121         return ret;
122 }
123
124 uint64_t sec_to_tsc(uint64_t sec)
125 {
126         if (sec < UINT64_MAX/rte_get_tsc_hz())
127                 return sec * rte_get_tsc_hz();
128         else
129                 return UINT64_MAX;
130 }
131
132 uint64_t msec_to_tsc(uint64_t msec)
133 {
134         if (msec < UINT64_MAX/rte_get_tsc_hz())
135                 return msec * rte_get_tsc_hz() / 1000;
136         else
137                 return msec / 1000 * rte_get_tsc_hz();
138 }
139
140 uint64_t usec_to_tsc(uint64_t usec)
141 {
142         if (usec < UINT64_MAX/rte_get_tsc_hz())
143                 return usec * rte_get_tsc_hz() / 1000000;
144         else
145                 return usec / 1000000 * rte_get_tsc_hz();
146 }
147
148 uint64_t nsec_to_tsc(uint64_t nsec)
149 {
150         if (nsec < UINT64_MAX/rte_get_tsc_hz())
151                 return nsec * rte_get_tsc_hz() / 1000000000;
152         else
153                 return nsec / 1000000000 * rte_get_tsc_hz();
154 }
155
156 uint64_t tsc_to_msec(uint64_t tsc)
157 {
158         if (tsc < UINT64_MAX / 1000) {
159                 return tsc * 1000 / rte_get_tsc_hz();
160         } else {
161                 return tsc / (rte_get_tsc_hz() / 1000);
162         }
163 }
164
165 uint64_t tsc_to_usec(uint64_t tsc)
166 {
167         if (tsc < UINT64_MAX / 1000000) {
168                 return tsc * 1000000 / rte_get_tsc_hz();
169         } else {
170                 return tsc / (rte_get_tsc_hz() / 1000000);
171         }
172 }
173
174 uint64_t tsc_to_nsec(uint64_t tsc)
175 {
176         if (tsc < UINT64_MAX / 1000000000) {
177                 return tsc * 1000000000 / rte_get_tsc_hz();
178         } else {
179                 return tsc / (rte_get_tsc_hz() / 1000000000);
180         }
181 }
182
183 uint64_t tsc_to_sec(uint64_t tsc)
184 {
185         return tsc / rte_get_tsc_hz();
186 }
187
188 struct time_unit tsc_to_time_unit(uint64_t tsc)
189 {
190         struct time_unit ret;
191         uint64_t hz = rte_get_tsc_hz();
192
193         ret.sec = tsc/hz;
194         ret.nsec = (tsc - ret.sec*hz)*1000000000/hz;
195
196         return ret;
197 }
198
199 uint64_t time_unit_to_usec(struct time_unit *time_unit)
200 {
201         return time_unit->sec * 1000000 + time_unit->nsec/1000;
202 }
203
204 uint64_t time_unit_to_nsec(struct time_unit *time_unit)
205 {
206         return time_unit->sec * 1000000000 + time_unit->nsec;
207 }
208
209 int time_unit_cmp(struct time_unit *left, struct time_unit *right)
210 {
211         if (left->sec < right->sec)
212                 return -1;
213         if (left->sec > right->sec)
214                 return 1;
215
216         if (left->nsec < right->nsec)
217                 return -1;
218         if (left->nsec > right->nsec)
219                 return -1;
220         return 0;
221 }
222
223 uint64_t freq_to_tsc(uint64_t times_per_sec)
224 {
225         return rte_get_tsc_hz()/times_per_sec;
226 }
227
228 void tsc_to_tv(struct timeval *tv, const uint64_t tsc)
229 {
230         uint64_t hz = rte_get_tsc_hz();
231         uint64_t sec = tsc/hz;
232
233         tv->tv_sec = sec;
234         tv->tv_usec = ((tsc - sec * hz) * 1000000) / hz;
235 }
236
237 void tv_to_tsc(const struct timeval *tv, uint64_t *tsc)
238 {
239         uint64_t hz = rte_get_tsc_hz();
240         *tsc = tv->tv_sec * hz;
241         *tsc += tv->tv_usec * hz / 1000000;
242 }
243
244 struct timeval tv_diff(const struct timeval *cur, const struct timeval *next)
245 {
246         uint64_t sec, usec;
247
248         sec = next->tv_sec - cur->tv_sec;
249         if (next->tv_usec < cur->tv_usec) {
250                 usec = next->tv_usec + 1000000 - cur->tv_usec;
251                 sec -= 1;
252         }
253         else
254                 usec = next->tv_usec - cur->tv_usec;
255
256         struct timeval ret = {
257                 .tv_sec  = sec,
258                 .tv_usec = usec,
259         };
260
261         return ret;
262 }