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