Fix potential core dump when closing ports at exit
[samplevnf.git] / VNFs / DPPD-PROX / handle_lat.h
1 /*
2 // Copyright (c) 2010-2019 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 LATENCY_ACCURACY        1
28 // If ACCURACY_WINDOW is too small, the accuracy for packet N can be received by lat BEFORE
29 // packet N is received (re-ordering) resulting in accuracy being unused
30 // 8192 packets is equivalent to 550 micro-seconds at 10Gbps for 64 bytes packets
31 #define ACCURACY_WINDOW         8192
32 #define LAT_BUCKET_COUNT        128
33
34 #define LAT_BUCKET_COUNT        128
35
36 #define LAT_BUCKET_COUNT        128
37
38 struct lat_test {
39         uint64_t tot_all_pkts;
40         uint64_t tot_pkts;
41         uint64_t max_lat;
42         uint64_t min_lat;
43         uint64_t tot_lat;
44         unsigned __int128 var_lat; /* variance */
45         uint64_t accuracy_limit_tsc;
46
47         uint64_t max_lat_error;
48         uint64_t min_lat_error;
49         uint64_t tot_lat_error;
50         unsigned __int128 var_lat_error;
51
52         uint64_t buckets[LAT_BUCKET_COUNT];
53         uint64_t bucket_size;
54         uint64_t lost_packets;
55 };
56
57 static struct time_unit lat_test_get_accuracy_limit(struct lat_test *lat_test)
58 {
59         return tsc_to_time_unit(lat_test->accuracy_limit_tsc);
60 }
61
62 static struct time_unit_err lat_test_get_avg(struct lat_test *lat_test)
63 {
64         uint64_t tsc;
65         uint64_t tsc_error;
66
67         tsc = lat_test->tot_lat/lat_test->tot_pkts;
68         tsc_error = lat_test->tot_lat_error/lat_test->tot_pkts;
69
70         struct time_unit_err ret = {
71                 .time = tsc_to_time_unit(tsc),
72                 .error = tsc_to_time_unit(tsc_error),
73         };
74
75         return ret;
76 }
77
78 static struct time_unit_err lat_test_get_min(struct lat_test *lat_test)
79 {
80         struct time_unit_err ret = {
81                 .time = tsc_to_time_unit(lat_test->min_lat),
82                 .error = tsc_to_time_unit(lat_test->min_lat_error),
83         };
84
85         return ret;
86 }
87
88 static struct time_unit_err lat_test_get_max(struct lat_test *lat_test)
89 {
90         struct time_unit_err ret = {
91                 .time = tsc_to_time_unit(lat_test->max_lat),
92                 .error = tsc_to_time_unit(lat_test->max_lat_error),
93         };
94
95         return ret;
96 }
97
98 static struct time_unit_err lat_test_get_stddev(struct lat_test *lat_test)
99 {
100         unsigned __int128 avg_tsc = lat_test->tot_lat/lat_test->tot_pkts;
101         unsigned __int128 avg_tsc_squared = avg_tsc * avg_tsc;
102         unsigned __int128 avg_squares_tsc = lat_test->var_lat/lat_test->tot_pkts;
103
104         /* The assumption is that variance fits into 64 bits, meaning
105            that standard deviation fits into 32 bits. In other words,
106            the assumption is that the standard deviation is not more
107            than approximately 1 second. */
108         uint64_t var_tsc = avg_squares_tsc - avg_tsc_squared;
109         uint64_t stddev_tsc = sqrt(var_tsc);
110
111         unsigned __int128 avg_tsc_error = lat_test->tot_lat_error / lat_test->tot_pkts;
112         unsigned __int128 avg_tsc_squared_error = 2 * avg_tsc * avg_tsc_error + avg_tsc_error * avg_tsc_error;
113         unsigned __int128 avg_squares_tsc_error = lat_test->var_lat_error / lat_test->tot_pkts;
114
115         uint64_t var_tsc_error = avg_squares_tsc_error + avg_tsc_squared_error;
116
117         /* sqrt(a+-b) = sqrt(a) +- (-sqrt(a) + sqrt(a + b)) */
118
119         uint64_t stddev_tsc_error = - stddev_tsc + sqrt(var_tsc + var_tsc_error);
120
121         struct time_unit_err ret = {
122                 .time = tsc_to_time_unit(stddev_tsc),
123                 .error = tsc_to_time_unit(stddev_tsc_error),
124         };
125
126         return ret;
127 }
128
129 static void _lat_test_histogram_combine(struct lat_test *dst, struct lat_test *src)
130 {
131         for (size_t i = 0; i < sizeof(dst->buckets)/sizeof(dst->buckets[0]); ++i)
132                 dst->buckets[i] += src->buckets[i];
133 }
134
135 static void lat_test_combine(struct lat_test *dst, struct lat_test *src)
136 {
137         dst->tot_all_pkts += src->tot_all_pkts;
138
139         dst->tot_pkts += src->tot_pkts;
140
141         dst->tot_lat += src->tot_lat;
142         dst->tot_lat_error += src->tot_lat_error;
143
144         /* (a +- b)^2 = a^2 +- (2ab + b^2) */
145         dst->var_lat += src->var_lat;
146         dst->var_lat_error += src->var_lat_error;
147
148         if (src->max_lat > dst->max_lat) {
149                 dst->max_lat = src->max_lat;
150                 dst->max_lat_error = src->max_lat_error;
151         }
152         if (src->min_lat < dst->min_lat) {
153                 dst->min_lat = src->min_lat;
154                 dst->min_lat_error = src->min_lat_error;
155         }
156
157         if (src->accuracy_limit_tsc > dst->accuracy_limit_tsc)
158                 dst->accuracy_limit_tsc = src->accuracy_limit_tsc;
159         dst->lost_packets += src->lost_packets;
160
161 #ifdef LATENCY_HISTOGRAM
162         _lat_test_histogram_combine(dst, src);
163 #endif
164 }
165
166 static void lat_test_reset(struct lat_test *lat_test)
167 {
168         lat_test->tot_all_pkts = 0;
169         lat_test->tot_pkts = 0;
170         lat_test->max_lat = 0;
171         lat_test->min_lat = -1;
172         lat_test->tot_lat = 0;
173         lat_test->var_lat = 0;
174         lat_test->max_lat_error = 0;
175         lat_test->min_lat_error = 0;
176         lat_test->tot_lat_error = 0;
177         lat_test->var_lat_error = 0;
178         lat_test->accuracy_limit_tsc = 0;
179
180         lat_test->lost_packets = 0;
181
182         memset(lat_test->buckets, 0, sizeof(lat_test->buckets));
183 }
184
185 static void lat_test_copy(struct lat_test *dst, struct lat_test *src)
186 {
187         if (src->tot_all_pkts)
188                 memcpy(dst, src, sizeof(struct lat_test));
189 }
190
191 struct task_lat;
192
193 struct lat_test *task_lat_get_latency_meassurement(struct task_lat *task);
194 uint32_t task_lat_get_latency_bucket_size(struct task_lat *task);
195 void task_lat_use_other_latency_meassurement(struct task_lat *task);
196 void task_lat_set_accuracy_limit(struct task_lat *task, uint32_t accuracy_limit_nsec);
197
198 #endif /* _HANDLE_LAT_H_ */