Merge "Initial support for DPDK 18.05"
[samplevnf.git] / VNFs / DPPD-PROX / stats_latency.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 "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         uint8_t                lcore_id;
26         uint8_t                task_id;
27         struct lat_test        lat_test;
28         struct lat_test        tot_lat_test;
29         struct stats_latency   stats;
30         struct stats_latency   tot;
31 };
32
33 struct stats_latency_manager {
34         uint16_t n_latency;
35         struct stats_latency_manager_entry entries[0]; /* copy of stats when running update stats. */
36 };
37
38 static struct stats_latency_manager *slm;
39
40 void stats_latency_reset(void)
41 {
42         for (uint16_t i = 0; i < slm->n_latency; ++i)
43                 lat_test_reset(&slm->entries[i].tot_lat_test);
44 }
45
46 int stats_get_n_latency(void)
47 {
48         return slm->n_latency;
49 }
50
51 uint32_t stats_latency_get_core_id(uint32_t i)
52 {
53         return slm->entries[i].lcore_id;
54 }
55
56 uint32_t stats_latency_get_task_id(uint32_t i)
57 {
58         return slm->entries[i].task_id;
59 }
60
61 struct stats_latency *stats_latency_get(uint32_t i)
62 {
63         return &slm->entries[i].stats;
64 }
65
66 struct stats_latency *stats_latency_tot_get(uint32_t i)
67 {
68         return &slm->entries[i].tot;
69 }
70
71 static struct stats_latency_manager_entry *stats_latency_entry_find(uint8_t lcore_id, uint8_t task_id)
72 {
73         struct stats_latency_manager_entry *entry;
74
75         for (uint16_t i = 0; i < stats_get_n_latency(); ++i) {
76                 entry = &slm->entries[i];
77
78                 if (entry->lcore_id == lcore_id && entry->task_id == task_id) {
79                         return entry;
80                 }
81         }
82         return NULL;
83 }
84
85 struct stats_latency *stats_latency_tot_find(uint32_t lcore_id, uint32_t task_id)
86 {
87         struct stats_latency_manager_entry *entry = stats_latency_entry_find(lcore_id, task_id);
88
89         if (!entry)
90                 return NULL;
91         else
92                 return &entry->tot;
93 }
94
95 struct stats_latency *stats_latency_find(uint32_t lcore_id, uint32_t task_id)
96 {
97         struct stats_latency_manager_entry *entry = stats_latency_entry_find(lcore_id, task_id);
98
99         if (!entry)
100                 return NULL;
101         else
102                 return &entry->stats;
103 }
104
105 static int task_runs_observable_latency(struct task_args *targ)
106 {
107         /* TODO: make this work with multiple ports and with
108            rings. Currently, only showing lat tasks which have 1 RX
109            port. */
110         return !strcmp(targ->task_init->mode_str, "lat") &&
111                 (targ->nb_rxports == 1 || targ->nb_rxrings == 1);
112 }
113
114 static struct stats_latency_manager *alloc_stats_latency_manager(void)
115 {
116         const uint32_t socket_id = rte_lcore_to_socket_id(rte_lcore_id());
117         struct stats_latency_manager *ret;
118         struct lcore_cfg *lconf;
119         uint32_t n_latency = 0;
120         uint32_t lcore_id;
121         size_t mem_size;
122
123         lcore_id = -1;
124         while (prox_core_next(&lcore_id, 0) == 0) {
125                 lconf = &lcore_cfg[lcore_id];
126                 for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
127                         struct task_args *targ = &lconf->targs[task_id];
128                         if (task_runs_observable_latency(targ))
129                                 ++n_latency;
130                 }
131         }
132         mem_size = sizeof(*ret) + sizeof(ret->entries[0]) * n_latency;
133
134         ret = prox_zmalloc(mem_size, socket_id);
135         return ret;
136 }
137
138 static void stats_latency_add_task(struct lcore_cfg *lconf, struct task_args *targ)
139 {
140         struct stats_latency_manager_entry *new_entry = &slm->entries[slm->n_latency];
141
142         new_entry->task = (struct task_lat *)targ->tbase;
143         new_entry->lcore_id = lconf->id;
144         new_entry->task_id = targ->id;
145         slm->n_latency++;
146 }
147
148 void stats_latency_init(void)
149 {
150         struct lcore_cfg *lconf = NULL;
151         struct task_args *targ;
152
153         slm = alloc_stats_latency_manager();
154
155         while (core_targ_next(&lconf, &targ, 0) == 0) {
156                 if (task_runs_observable_latency(targ))
157                         stats_latency_add_task(lconf, targ);
158         }
159 }
160
161 #ifdef LATENCY_HISTOGRAM
162 void stats_core_lat_histogram(uint8_t lcore_id, uint8_t task_id, uint64_t **buckets)
163 {
164         struct stats_latency_manager_entry *lat_stats;
165         uint64_t tsc;
166
167         lat_stats = stats_latency_entry_find(lcore_id, task_id);
168
169         if (lat_stats)
170                 *buckets = lat_stats->lat_test.buckets;
171         else
172                 *buckets = NULL;
173 }
174 #endif
175
176 static void stats_latency_fetch_entry(struct stats_latency_manager_entry *entry)
177 {
178         struct stats_latency *cur = &entry->stats;
179         struct lat_test *lat_test_local = &entry->lat_test;
180         struct lat_test *lat_test_remote = task_lat_get_latency_meassurement(entry->task);
181
182         if (!lat_test_remote)
183                 return;
184
185         if (lat_test_remote->tot_all_pkts) {
186                 lat_test_copy(&entry->lat_test, lat_test_remote);
187                 lat_test_reset(lat_test_remote);
188                 lat_test_combine(&entry->tot_lat_test, &entry->lat_test);
189         }
190
191         task_lat_use_other_latency_meassurement(entry->task);
192 }
193
194 static void stats_latency_from_lat_test(struct stats_latency *dst, struct lat_test *src)
195 {
196         /* In case packets were received, but measurements were too
197            inaccurate */
198         if (src->tot_pkts) {
199                 dst->max = lat_test_get_max(src);
200                 dst->min = lat_test_get_min(src);
201                 dst->avg = lat_test_get_avg(src);
202                 dst->stddev = lat_test_get_stddev(src);
203         }
204         dst->accuracy_limit = lat_test_get_accuracy_limit(src);
205         dst->tot_packets = src->tot_pkts;
206         dst->tot_all_packets = src->tot_all_pkts;
207         dst->lost_packets = src->lost_packets;
208 }
209
210 static void stats_latency_update_entry(struct stats_latency_manager_entry *entry)
211 {
212         if (!entry->lat_test.tot_all_pkts)
213                 return;
214
215         stats_latency_from_lat_test(&entry->stats, &entry->lat_test);
216         stats_latency_from_lat_test(&entry->tot, &entry->tot_lat_test);
217 }
218
219 void stats_latency_update(void)
220 {
221         for (uint16_t i = 0; i < slm->n_latency; ++i)
222                 stats_latency_fetch_entry(&slm->entries[i]);
223         for (uint16_t i = 0; i < slm->n_latency; ++i)
224                 stats_latency_update_entry(&slm->entries[i]);
225 }