Added support for reporting packet (mis)order.
[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         uint64_t mis_ordered;
56         uint64_t extent;
57         uint64_t duplicate;
58 };
59
60 static struct time_unit lat_test_get_accuracy_limit(struct lat_test *lat_test)
61 {
62         return tsc_to_time_unit(lat_test->accuracy_limit_tsc);
63 }
64
65 static struct time_unit_err lat_test_get_avg(struct lat_test *lat_test)
66 {
67         uint64_t tsc;
68         uint64_t tsc_error;
69
70         tsc = lat_test->tot_lat/lat_test->tot_pkts;
71         tsc_error = lat_test->tot_lat_error/lat_test->tot_pkts;
72
73         struct time_unit_err ret = {
74                 .time = tsc_to_time_unit(tsc),
75                 .error = tsc_to_time_unit(tsc_error),
76         };
77
78         return ret;
79 }
80
81 static struct time_unit_err lat_test_get_min(struct lat_test *lat_test)
82 {
83         struct time_unit_err ret = {
84                 .time = tsc_to_time_unit(lat_test->min_lat),
85                 .error = tsc_to_time_unit(lat_test->min_lat_error),
86         };
87
88         return ret;
89 }
90
91 static struct time_unit_err lat_test_get_max(struct lat_test *lat_test)
92 {
93         struct time_unit_err ret = {
94                 .time = tsc_to_time_unit(lat_test->max_lat),
95                 .error = tsc_to_time_unit(lat_test->max_lat_error),
96         };
97
98         return ret;
99 }
100
101 static struct time_unit_err lat_test_get_stddev(struct lat_test *lat_test)
102 {
103         unsigned __int128 avg_tsc = lat_test->tot_lat/lat_test->tot_pkts;
104         unsigned __int128 avg_tsc_squared = avg_tsc * avg_tsc;
105         unsigned __int128 avg_squares_tsc = lat_test->var_lat/lat_test->tot_pkts;
106
107         /* The assumption is that variance fits into 64 bits, meaning
108            that standard deviation fits into 32 bits. In other words,
109            the assumption is that the standard deviation is not more
110            than approximately 1 second. */
111         uint64_t var_tsc = avg_squares_tsc - avg_tsc_squared;
112         uint64_t stddev_tsc = sqrt(var_tsc);
113
114         unsigned __int128 avg_tsc_error = lat_test->tot_lat_error / lat_test->tot_pkts;
115         unsigned __int128 avg_tsc_squared_error = 2 * avg_tsc * avg_tsc_error + avg_tsc_error * avg_tsc_error;
116         unsigned __int128 avg_squares_tsc_error = lat_test->var_lat_error / lat_test->tot_pkts;
117
118         uint64_t var_tsc_error = avg_squares_tsc_error + avg_tsc_squared_error;
119
120         /* sqrt(a+-b) = sqrt(a) +- (-sqrt(a) + sqrt(a + b)) */
121
122         uint64_t stddev_tsc_error = - stddev_tsc + sqrt(var_tsc + var_tsc_error);
123
124         struct time_unit_err ret = {
125                 .time = tsc_to_time_unit(stddev_tsc),
126                 .error = tsc_to_time_unit(stddev_tsc_error),
127         };
128
129         return ret;
130 }
131
132 static void _lat_test_histogram_combine(struct lat_test *dst, struct lat_test *src)
133 {
134         for (size_t i = 0; i < sizeof(dst->buckets)/sizeof(dst->buckets[0]); ++i)
135                 dst->buckets[i] += src->buckets[i];
136 }
137
138 static void lat_test_combine(struct lat_test *dst, struct lat_test *src)
139 {
140         dst->tot_all_pkts += src->tot_all_pkts;
141
142         dst->tot_pkts += src->tot_pkts;
143
144         dst->tot_lat += src->tot_lat;
145         dst->tot_lat_error += src->tot_lat_error;
146
147         /* (a +- b)^2 = a^2 +- (2ab + b^2) */
148         dst->var_lat += src->var_lat;
149         dst->var_lat_error += src->var_lat_error;
150
151         if (src->max_lat > dst->max_lat) {
152                 dst->max_lat = src->max_lat;
153                 dst->max_lat_error = src->max_lat_error;
154         }
155         if (src->min_lat < dst->min_lat) {
156                 dst->min_lat = src->min_lat;
157                 dst->min_lat_error = src->min_lat_error;
158         }
159
160         if (src->accuracy_limit_tsc > dst->accuracy_limit_tsc)
161                 dst->accuracy_limit_tsc = src->accuracy_limit_tsc;
162         dst->lost_packets += src->lost_packets;
163         dst->mis_ordered += src->mis_ordered;
164         dst->extent += src->extent;
165         dst->duplicate += src->duplicate;
166
167 #ifdef LATENCY_HISTOGRAM
168         _lat_test_histogram_combine(dst, src);
169 #endif
170 }
171
172 static void lat_test_reset(struct lat_test *lat_test)
173 {
174         lat_test->tot_all_pkts = 0;
175         lat_test->tot_pkts = 0;
176         lat_test->max_lat = 0;
177         lat_test->min_lat = -1;
178         lat_test->tot_lat = 0;
179         lat_test->var_lat = 0;
180         lat_test->max_lat_error = 0;
181         lat_test->min_lat_error = 0;
182         lat_test->tot_lat_error = 0;
183         lat_test->var_lat_error = 0;
184         lat_test->accuracy_limit_tsc = 0;
185
186         lat_test->lost_packets = 0;
187         lat_test->mis_ordered = 0;
188         lat_test->extent = 0;
189         lat_test->duplicate = 0;
190
191         memset(lat_test->buckets, 0, sizeof(lat_test->buckets));
192 }
193
194 static void lat_test_copy(struct lat_test *dst, struct lat_test *src)
195 {
196         if (src->tot_all_pkts)
197                 memcpy(dst, src, sizeof(struct lat_test));
198 }
199
200 struct task_lat;
201
202 struct lat_test *task_lat_get_latency_meassurement(struct task_lat *task);
203 uint32_t task_lat_get_latency_bucket_size(struct task_lat *task);
204 void task_lat_use_other_latency_meassurement(struct task_lat *task);
205 void task_lat_set_accuracy_limit(struct task_lat *task, uint32_t accuracy_limit_nsec);
206
207 #endif /* _HANDLE_LAT_H_ */