Added support for reporting packet (mis)order.
[samplevnf.git] / VNFs / DPPD-PROX / stats_latency.c
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 #include "prox_malloc.h"
18 #include "stats_latency.h"
19 #include "handle_lat.h"
20 #include "prox_cfg.h"
21 #include "prox_args.h"
22
23 struct stats_latency_manager_entry {
24         struct task_lat        *task;
25         uint32_t                bucket_size;
26         uint8_t                lcore_id;
27         uint8_t                task_id;
28         struct lat_test        lat_test;
29         struct lat_test        tot_lat_test;
30         struct stats_latency   stats;
31         struct stats_latency   tot;
32 };
33
34 struct stats_latency_manager {
35         uint16_t n_latency;
36         uint32_t bucket_size;
37         struct stats_latency_manager_entry entries[0]; /* copy of stats when running update stats. */
38 };
39
40 static struct stats_latency_manager *slm;
41
42 void stats_latency_reset(void)
43 {
44         for (uint16_t i = 0; i < slm->n_latency; ++i)
45                 lat_test_reset(&slm->entries[i].tot_lat_test);
46 }
47
48 int stats_get_n_latency(void)
49 {
50         return slm->n_latency;
51 }
52
53 int stats_get_latency_bucket_size(void)
54 {
55         return slm->bucket_size;
56 }
57
58 uint32_t stats_latency_get_core_id(uint32_t i)
59 {
60         return slm->entries[i].lcore_id;
61 }
62
63 uint32_t stats_latency_get_task_id(uint32_t i)
64 {
65         return slm->entries[i].task_id;
66 }
67
68 struct stats_latency *stats_latency_get(uint32_t i)
69 {
70         return &slm->entries[i].stats;
71 }
72
73 uint64_t *stats_latency_get_bucket(uint32_t i)
74 {
75         return slm->entries[i].lat_test.buckets;
76 }
77
78 uint64_t *stats_latency_get_tot_bucket(uint32_t i)
79 {
80         return slm->entries[i].tot_lat_test.buckets;
81 }
82
83 struct stats_latency *stats_latency_tot_get(uint32_t i)
84 {
85         return &slm->entries[i].tot;
86 }
87
88 static struct stats_latency_manager_entry *stats_latency_entry_find(uint8_t lcore_id, uint8_t task_id)
89 {
90         struct stats_latency_manager_entry *entry;
91
92         for (uint16_t i = 0; i < stats_get_n_latency(); ++i) {
93                 entry = &slm->entries[i];
94
95                 if (entry->lcore_id == lcore_id && entry->task_id == task_id) {
96                         return entry;
97                 }
98         }
99         return NULL;
100 }
101
102 struct stats_latency *stats_latency_tot_find(uint32_t lcore_id, uint32_t task_id)
103 {
104         struct stats_latency_manager_entry *entry = stats_latency_entry_find(lcore_id, task_id);
105
106         if (!entry)
107                 return NULL;
108         else
109                 return &entry->tot;
110 }
111
112 struct stats_latency *stats_latency_find(uint32_t lcore_id, uint32_t task_id)
113 {
114         struct stats_latency_manager_entry *entry = stats_latency_entry_find(lcore_id, task_id);
115
116         if (!entry)
117                 return NULL;
118         else
119                 return &entry->stats;
120 }
121
122 static int task_runs_observable_latency(struct task_args *targ)
123 {
124         /* Note that multiple ports or rings are only supported
125            if they all receive packets configured in the same way
126            e.g. same timestamp pos. */
127         return !strcmp(targ->task_init->mode_str, "lat") &&
128                 (targ->nb_rxports >= 1 || targ->nb_rxrings >= 1);
129 }
130
131 static struct stats_latency_manager *alloc_stats_latency_manager(void)
132 {
133         const uint32_t socket_id = rte_lcore_to_socket_id(rte_lcore_id());
134         struct stats_latency_manager *ret;
135         struct lcore_cfg *lconf;
136         uint32_t n_latency = 0;
137         uint32_t lcore_id;
138         size_t mem_size;
139
140         lcore_id = -1;
141         while (prox_core_next(&lcore_id, 0) == 0) {
142                 lconf = &lcore_cfg[lcore_id];
143                 for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
144                         struct task_args *targ = &lconf->targs[task_id];
145                         if (task_runs_observable_latency(targ))
146                                 ++n_latency;
147                 }
148         }
149         mem_size = sizeof(*ret) + sizeof(ret->entries[0]) * n_latency;
150
151         ret = prox_zmalloc(mem_size, socket_id);
152         return ret;
153 }
154
155 static void stats_latency_add_task(struct lcore_cfg *lconf, struct task_args *targ)
156 {
157         struct stats_latency_manager_entry *new_entry = &slm->entries[slm->n_latency];
158
159         new_entry->task = (struct task_lat *)targ->tbase;
160         new_entry->bucket_size = task_lat_get_latency_bucket_size(new_entry->task);
161         new_entry->lcore_id = lconf->id;
162         new_entry->task_id = targ->id;
163         new_entry->tot_lat_test.min_lat = -1;
164         if (slm->bucket_size == 0)
165                 slm->bucket_size = new_entry->bucket_size;
166         else if (slm->bucket_size != new_entry->bucket_size)
167                 plog_err("Latency bucket size does not support different bucket sizes per task - using bucket size from first task (%d)\n", slm->bucket_size);
168         slm->n_latency++;
169 }
170
171 void stats_latency_init(void)
172 {
173         struct lcore_cfg *lconf = NULL;
174         struct task_args *targ;
175
176         slm = alloc_stats_latency_manager();
177
178         while (core_targ_next(&lconf, &targ, 0) == 0) {
179                 if (task_runs_observable_latency(targ))
180                         stats_latency_add_task(lconf, targ);
181         }
182 }
183
184 #ifdef LATENCY_HISTOGRAM
185 void stats_core_lat_histogram(uint8_t lcore_id, uint8_t task_id, uint64_t **buckets)
186 {
187         struct stats_latency_manager_entry *lat_stats;
188         uint64_t tsc;
189
190         lat_stats = stats_latency_entry_find(lcore_id, task_id);
191
192         if (lat_stats)
193                 *buckets = lat_stats->lat_test.buckets;
194         else
195                 *buckets = NULL;
196 }
197 #endif
198
199 static void stats_latency_fetch_entry(struct stats_latency_manager_entry *entry)
200 {
201         struct stats_latency *cur = &entry->stats;
202         struct lat_test *lat_test_local = &entry->lat_test;
203         struct lat_test *lat_test_remote = task_lat_get_latency_meassurement(entry->task);
204
205         if (!lat_test_remote)
206                 return;
207
208         if (lat_test_remote->tot_all_pkts) {
209                 lat_test_copy(&entry->lat_test, lat_test_remote);
210                 lat_test_reset(lat_test_remote);
211                 lat_test_combine(&entry->tot_lat_test, &entry->lat_test);
212         }
213
214         task_lat_use_other_latency_meassurement(entry->task);
215 }
216
217 static void stats_latency_from_lat_test(struct stats_latency *dst, struct lat_test *src)
218 {
219         /* In case packets were received, but measurements were too
220            inaccurate */
221         if (src->tot_pkts) {
222                 dst->max = lat_test_get_max(src);
223                 dst->min = lat_test_get_min(src);
224                 dst->avg = lat_test_get_avg(src);
225                 dst->stddev = lat_test_get_stddev(src);
226         }
227         dst->accuracy_limit = lat_test_get_accuracy_limit(src);
228         dst->tot_packets = src->tot_pkts;
229         dst->tot_all_packets = src->tot_all_pkts;
230         dst->lost_packets = src->lost_packets;
231         dst->mis_ordered = src->mis_ordered;
232         dst->extent = src->extent;
233         dst->duplicate = src->duplicate;
234 }
235
236 static void stats_latency_update_entry(struct stats_latency_manager_entry *entry)
237 {
238         if (!entry->lat_test.tot_all_pkts)
239                 return;
240
241         stats_latency_from_lat_test(&entry->stats, &entry->lat_test);
242         stats_latency_from_lat_test(&entry->tot, &entry->tot_lat_test);
243 }
244
245 void stats_latency_update(void)
246 {
247         for (uint16_t i = 0; i < slm->n_latency; ++i)
248                 stats_latency_fetch_entry(&slm->entries[i]);
249         for (uint16_t i = 0; i < slm->n_latency; ++i)
250                 stats_latency_update_entry(&slm->entries[i]);
251 }