Fix command parser
[samplevnf.git] / VNFs / DPPD-PROX / handle_irq.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 <rte_cycles.h>
18
19 #include "lconf.h"
20 #include "task_base.h"
21 #include "task_init.h"
22 #include "handle_irq.h"
23 #include "log.h"
24 #include "unistd.h"
25 #include "input.h"
26
27 #define MAX_INDEX       65535 * 16
28
29 struct irq_info {
30         uint64_t tsc;
31         uint64_t lat;
32 };
33
34 struct irq_bucket {
35         uint64_t index;
36         struct irq_info info[MAX_INDEX];
37 };
38
39 struct task_irq {
40         struct task_base base;
41         uint64_t start_tsc;
42         uint64_t first_tsc;
43         uint64_t tsc;
44         uint64_t max_irq;
45         uint8_t  lcore_id;
46         volatile uint16_t stats_use_lt; /* which lt to use, */
47         volatile uint16_t task_use_lt; /* 0 or 1 depending on which of the 2 result records are used */
48         struct irq_bucket buffer[2];
49 };
50
51 #define MAX_INTERRUPT_LENGTH    500000  /* Maximum length of an interrupt is (1 / MAX_INTERRUPT_LENGTH) seconds */
52
53 /*
54  *      This module is not handling any packets.
55  *      It loops on rdtsc() and checks whether it has been interrupted
56  *               for more than (1 / MAX_INTERRUPT_LENGTH) sec.
57  *      This is a debugging only task, useful to check if the system h
58  *              as been properly configured.
59 */
60
61 void task_irq_show_stats(struct task_irq *task_irq, struct input *input)
62 {
63         struct irq_bucket *bucket = &task_irq->buffer[!task_irq->task_use_lt];
64         if (input->reply) {
65                 char buf[8192] = {0};
66                 if (bucket->index == 0) {
67                         sprintf(buf, "\n");
68                         input->reply(input, buf, strlen(buf));
69                         buf[0] = 0;
70                 }
71                 for (uint64_t i = 0; i < bucket->index; i++) {
72                         sprintf(buf + strlen(buf), "%d; %"PRIu64"""; %ld; %ld; %ld; %ld ;",
73                                 task_irq->lcore_id,
74                                 i,
75                                 bucket->info[i].lat,
76                                 bucket->info[i].lat * 1000000 / rte_get_tsc_hz(),
77                                 bucket->info[i].tsc - task_irq->start_tsc,
78                                 (bucket->info[i].tsc - task_irq->start_tsc) * 1000 / rte_get_tsc_hz());
79                         sprintf(buf+strlen(buf), "\n");
80                         input->reply(input, buf, strlen(buf));
81                         buf[0] = 0;
82                 }
83         } else {
84                 for (uint64_t i = 0; i < bucket->index; i++)
85                         if (bucket->info[i].lat)
86                                 plog_info("[%d]; Interrupt %"PRIu64": %ld cycles (%ld micro-sec) at %ld cycles (%ld msec)\n",
87                                           task_irq->lcore_id,
88                                           i,
89                                           bucket->info[i].lat,
90                                           bucket->info[i].lat * 1000000 / rte_get_tsc_hz(),
91                                           bucket->info[i].tsc - task_irq->start_tsc,
92                                           (bucket->info[i].tsc - task_irq->start_tsc) * 1000 / rte_get_tsc_hz());
93         }
94         task_irq->stats_use_lt = !task_irq->task_use_lt;
95         bucket->index = 0;
96 }
97
98 static void irq_stop(struct task_base *tbase)
99 {
100         struct task_irq *task = (struct task_irq *)tbase;
101         uint32_t i;
102         uint32_t lcore_id = rte_lcore_id();
103         uint64_t lat, max_lat = 0, tot_lat = 0;
104         int bucket_id;
105         int n_lat = 0;
106
107         plog_info("Stopping core %u\n", lcore_id);
108         sleep(2);       // Make sure all cores are stopped before starting to write
109         plog_info("Core ID; Interrupt (nanosec); Time (msec)\n");
110         for (int j = 0; j < 2; j++) {
111                 // Start dumping the oldest bucket first
112                 if (task->buffer[0].info[0].tsc < task->buffer[1].info[0].tsc)
113                         bucket_id = j;
114                 else
115                         bucket_id = !j;
116                 struct irq_bucket *bucket = &task->buffer[bucket_id];
117                 for (i=0; i< bucket->index;i++) {
118                         if (bucket->info[i].lat != 0) {
119                                 lat = bucket->info[i].lat * 1000000000 / rte_get_tsc_hz();
120                                 if (max_lat < lat)
121                                         max_lat = lat;
122                                 n_lat++;
123                                 tot_lat += lat;
124                                 plog_info("%d; %ld; %ld\n", lcore_id, lat,
125                                           (bucket->info[i].tsc - task->start_tsc) * 1000 / rte_get_tsc_hz());
126                         }
127                 }
128         }
129         if (n_lat)
130                 tot_lat = tot_lat / n_lat;
131         plog_info("Core %u stopped. max lat is %ld and average is %ld\n", lcore_id, max_lat, tot_lat);
132 }
133
134 static inline int handle_irq_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
135 {
136         struct task_irq *task = (struct task_irq *)tbase;
137         uint64_t tsc1;
138         uint64_t index;
139
140         if (task->stats_use_lt != task->task_use_lt)
141                 task->task_use_lt = task->stats_use_lt;
142         struct irq_bucket *bucket = &task->buffer[task->task_use_lt];
143
144         tsc1 = rte_rdtsc();
145         if ((tsc1 > task->first_tsc) && (task->tsc != 0) && ((tsc1 - task->tsc) > task->max_irq) && (bucket->index < MAX_INDEX)) {
146                 bucket->info[bucket->index].tsc = tsc1;
147                 bucket->info[bucket->index++].lat = tsc1 - task->tsc;
148         }
149         task->tsc = tsc1;
150         return 0;
151 }
152
153 static void init_task_irq(struct task_base *tbase,
154                           __attribute__((unused)) struct task_args *targ)
155 {
156         struct task_irq *task = (struct task_irq *)tbase;
157         // max_irq expressed in cycles
158         task->max_irq = rte_get_tsc_hz() / MAX_INTERRUPT_LENGTH;
159         task->start_tsc = rte_rdtsc();
160         task->first_tsc = task->start_tsc + 2 * rte_get_tsc_hz();
161         task->lcore_id = targ->lconf->id;
162         plog_info("\tusing irq mode with max irq set to %ld cycles\n", task->max_irq);
163 }
164
165 static struct task_init task_init_irq = {
166         .mode_str = "irq",
167         .init = init_task_irq,
168         .handle = handle_irq_bulk,
169         .stop = irq_stop,
170         .flag_features = TASK_FEATURE_NO_RX,
171         .size = sizeof(struct task_irq)
172 };
173
174 static struct task_init task_init_none;
175
176 __attribute__((constructor)) static void reg_task_irq(void)
177 {
178         reg_task(&task_init_irq);
179 }