Merge "docs: Update install and release docs for DPDK migration support"
[samplevnf.git] / VNFs / DPPD-PROX / handle_lat.h
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 #ifndef _HANDLE_LAT_H_
18 #define _HANDLE_LAT_H_
19
20 #include <stdio.h>
21 #include <math.h>
22 #include <string.h>
23
24 #include "task_base.h"
25 #include "clock.h"
26
27 #define MAX_PACKETS_FOR_LATENCY 64
28 #define LATENCY_ACCURACY        1
29
30 struct lat_test {
31         uint64_t tot_all_pkts;
32         uint64_t tot_pkts;
33         uint64_t max_lat;
34         uint64_t min_lat;
35         uint64_t tot_lat;
36         unsigned __int128 var_lat; /* variance */
37         uint64_t accuracy_limit_tsc;
38
39         uint64_t max_lat_error;
40         uint64_t min_lat_error;
41         uint64_t tot_lat_error;
42         unsigned __int128 var_lat_error;
43
44         uint64_t buckets[128];
45         uint64_t bucket_size;
46         uint64_t lost_packets;
47 };
48
49 static struct time_unit lat_test_get_accuracy_limit(struct lat_test *lat_test)
50 {
51         return tsc_to_time_unit(lat_test->accuracy_limit_tsc);
52 }
53
54 static struct time_unit_err lat_test_get_avg(struct lat_test *lat_test)
55 {
56         uint64_t tsc;
57         uint64_t tsc_error;
58
59         tsc = lat_test->tot_lat/lat_test->tot_pkts;
60         tsc_error = lat_test->tot_lat_error/lat_test->tot_pkts;
61
62         struct time_unit_err ret = {
63                 .time = tsc_to_time_unit(tsc),
64                 .error = tsc_to_time_unit(tsc_error),
65         };
66
67         return ret;
68 }
69
70 static struct time_unit_err lat_test_get_min(struct lat_test *lat_test)
71 {
72         struct time_unit_err ret = {
73                 .time = tsc_to_time_unit(lat_test->min_lat),
74                 .error = tsc_to_time_unit(lat_test->min_lat_error),
75         };
76
77         return ret;
78 }
79
80 static struct time_unit_err lat_test_get_max(struct lat_test *lat_test)
81 {
82         struct time_unit_err ret = {
83                 .time = tsc_to_time_unit(lat_test->max_lat),
84                 .error = tsc_to_time_unit(lat_test->max_lat_error),
85         };
86
87         return ret;
88 }
89
90 static struct time_unit_err lat_test_get_stddev(struct lat_test *lat_test)
91 {
92         unsigned __int128 avg_tsc = lat_test->tot_lat/lat_test->tot_pkts;
93         unsigned __int128 avg_tsc_squared = avg_tsc * avg_tsc;
94         unsigned __int128 avg_squares_tsc = lat_test->var_lat/lat_test->tot_pkts;
95
96         /* The assumption is that variance fits into 64 bits, meaning
97            that standard deviation fits into 32 bits. In other words,
98            the assumption is that the standard deviation is not more
99            than approximately 1 second. */
100         uint64_t var_tsc = avg_squares_tsc - avg_tsc_squared;
101         uint64_t stddev_tsc = sqrt(var_tsc);
102
103         unsigned __int128 avg_tsc_error = lat_test->tot_lat_error / lat_test->tot_pkts;
104         unsigned __int128 avg_tsc_squared_error = 2 * avg_tsc * avg_tsc_error + avg_tsc_error * avg_tsc_error;
105         unsigned __int128 avg_squares_tsc_error = lat_test->var_lat_error / lat_test->tot_pkts;
106
107         uint64_t var_tsc_error = avg_squares_tsc_error + avg_tsc_squared_error;
108
109         /* sqrt(a+-b) = sqrt(a) +- (-sqrt(a) + sqrt(a + b)) */
110
111         uint64_t stddev_tsc_error = - stddev_tsc + sqrt(var_tsc + var_tsc_error);
112
113         struct time_unit_err ret = {
114                 .time = tsc_to_time_unit(stddev_tsc),
115                 .error = tsc_to_time_unit(stddev_tsc_error),
116         };
117
118         return ret;
119 }
120
121 static void _lat_test_histogram_combine(struct lat_test *dst, struct lat_test *src)
122 {
123         for (size_t i = 0; i < sizeof(dst->buckets)/sizeof(dst->buckets[0]); ++i)
124                 dst->buckets[i] += src->buckets[i];
125 }
126
127 static void lat_test_combine(struct lat_test *dst, struct lat_test *src)
128 {
129         dst->tot_all_pkts += src->tot_all_pkts;
130
131         dst->tot_pkts += src->tot_pkts;
132
133         dst->tot_lat += src->tot_lat;
134         dst->tot_lat_error += src->tot_lat_error;
135
136         /* (a +- b)^2 = a^2 +- (2ab + b^2) */
137         dst->var_lat += src->var_lat;
138         dst->var_lat_error += src->var_lat_error;
139
140         if (src->max_lat > dst->max_lat) {
141                 dst->max_lat = src->max_lat;
142                 dst->max_lat_error = src->max_lat_error;
143         }
144         if (src->min_lat < dst->min_lat) {
145                 dst->min_lat = src->min_lat;
146                 dst->min_lat_error = src->min_lat_error;
147         }
148
149         if (src->accuracy_limit_tsc > dst->accuracy_limit_tsc)
150                 dst->accuracy_limit_tsc = src->accuracy_limit_tsc;
151         dst->lost_packets += src->lost_packets;
152
153 #ifdef LATENCY_HISTOGRAM
154         _lat_test_histogram_combine(dst, src);
155 #endif
156 }
157
158 static void lat_test_reset(struct lat_test *lat_test)
159 {
160         lat_test->tot_all_pkts = 0;
161         lat_test->tot_pkts = 0;
162         lat_test->max_lat = 0;
163         lat_test->min_lat = -1;
164         lat_test->tot_lat = 0;
165         lat_test->var_lat = 0;
166         lat_test->max_lat_error = 0;
167         lat_test->min_lat_error = 0;
168         lat_test->tot_lat_error = 0;
169         lat_test->var_lat_error = 0;
170         lat_test->accuracy_limit_tsc = 0;
171
172         lat_test->lost_packets = 0;
173
174         memset(lat_test->buckets, 0, sizeof(lat_test->buckets));
175 }
176
177 static void lat_test_copy(struct lat_test *dst, struct lat_test *src)
178 {
179         if (src->tot_all_pkts)
180                 memcpy(dst, src, sizeof(struct lat_test));
181 }
182
183 struct task_lat;
184
185 struct lat_test *task_lat_get_latency_meassurement(struct task_lat *task);
186 void task_lat_use_other_latency_meassurement(struct task_lat *task);
187 void task_lat_set_accuracy_limit(struct task_lat *task, uint32_t accuracy_limit_nsec);
188
189 #endif /* _HANDLE_LAT_H_ */