Multiple changes for June release
[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         /* Note that multiple ports or rings are only supported
108            if they all receive packets configured in the same way
109            e.g. same timestamp pos. */
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         new_entry->tot_lat_test.min_lat = -1;
146         slm->n_latency++;
147 }
148
149 void stats_latency_init(void)
150 {
151         struct lcore_cfg *lconf = NULL;
152         struct task_args *targ;
153
154         slm = alloc_stats_latency_manager();
155
156         while (core_targ_next(&lconf, &targ, 0) == 0) {
157                 if (task_runs_observable_latency(targ))
158                         stats_latency_add_task(lconf, targ);
159         }
160 }
161
162 #ifdef LATENCY_HISTOGRAM
163 void stats_core_lat_histogram(uint8_t lcore_id, uint8_t task_id, uint64_t **buckets)
164 {
165         struct stats_latency_manager_entry *lat_stats;
166         uint64_t tsc;
167
168         lat_stats = stats_latency_entry_find(lcore_id, task_id);
169
170         if (lat_stats)
171                 *buckets = lat_stats->lat_test.buckets;
172         else
173                 *buckets = NULL;
174 }
175 #endif
176
177 static void stats_latency_fetch_entry(struct stats_latency_manager_entry *entry)
178 {
179         struct stats_latency *cur = &entry->stats;
180         struct lat_test *lat_test_local = &entry->lat_test;
181         struct lat_test *lat_test_remote = task_lat_get_latency_meassurement(entry->task);
182
183         if (!lat_test_remote)
184                 return;
185
186         if (lat_test_remote->tot_all_pkts) {
187                 lat_test_copy(&entry->lat_test, lat_test_remote);
188                 lat_test_reset(lat_test_remote);
189                 lat_test_combine(&entry->tot_lat_test, &entry->lat_test);
190         }
191
192         task_lat_use_other_latency_meassurement(entry->task);
193 }
194
195 static void stats_latency_from_lat_test(struct stats_latency *dst, struct lat_test *src)
196 {
197         /* In case packets were received, but measurements were too
198            inaccurate */
199         if (src->tot_pkts) {
200                 dst->max = lat_test_get_max(src);
201                 dst->min = lat_test_get_min(src);
202                 dst->avg = lat_test_get_avg(src);
203                 dst->stddev = lat_test_get_stddev(src);
204         }
205         dst->accuracy_limit = lat_test_get_accuracy_limit(src);
206         dst->tot_packets = src->tot_pkts;
207         dst->tot_all_packets = src->tot_all_pkts;
208         dst->lost_packets = src->lost_packets;
209 }
210
211 static void stats_latency_update_entry(struct stats_latency_manager_entry *entry)
212 {
213         if (!entry->lat_test.tot_all_pkts)
214                 return;
215
216         stats_latency_from_lat_test(&entry->stats, &entry->lat_test);
217         stats_latency_from_lat_test(&entry->tot, &entry->tot_lat_test);
218 }
219
220 void stats_latency_update(void)
221 {
222         for (uint16_t i = 0; i < slm->n_latency; ++i)
223                 stats_latency_fetch_entry(&slm->entries[i]);
224         for (uint16_t i = 0; i < slm->n_latency; ++i)
225                 stats_latency_update_entry(&slm->entries[i]);
226 }