summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--VNFs/DPPD-PROX/Makefile4
-rw-r--r--VNFs/DPPD-PROX/cmd_parser.c25
-rw-r--r--VNFs/DPPD-PROX/display.c8
-rw-r--r--VNFs/DPPD-PROX/display_irq.c160
-rw-r--r--VNFs/DPPD-PROX/display_irq.h23
-rw-r--r--VNFs/DPPD-PROX/handle_irq.c103
-rw-r--r--VNFs/DPPD-PROX/handle_irq.h30
-rw-r--r--VNFs/DPPD-PROX/prox_args.c5
-rw-r--r--VNFs/DPPD-PROX/prox_port_cfg.c8
-rw-r--r--VNFs/DPPD-PROX/stats.c9
-rw-r--r--VNFs/DPPD-PROX/stats_cons.h3
-rw-r--r--VNFs/DPPD-PROX/stats_irq.c144
-rw-r--r--VNFs/DPPD-PROX/stats_irq.h71
-rw-r--r--VNFs/DPPD-PROX/stats_parser.c23
-rw-r--r--VNFs/DPPD-PROX/task_init.h1
15 files changed, 556 insertions, 61 deletions
diff --git a/VNFs/DPPD-PROX/Makefile b/VNFs/DPPD-PROX/Makefile
index 906fc606..7109cb48 100644
--- a/VNFs/DPPD-PROX/Makefile
+++ b/VNFs/DPPD-PROX/Makefile
@@ -199,12 +199,12 @@ SRCS-y += prox_args.c prox_cfg.c prox_cksum.c prox_port_cfg.c
SRCS-y += cfgfile.c clock.c commands.c cqm.c msr.c defaults.c
SRCS-y += display.c display_latency.c display_mempools.c
-SRCS-y += display_ports.c display_rings.c display_priority.c display_pkt_len.c display_l4gen.c display_tasks.c
+SRCS-y += display_ports.c display_rings.c display_priority.c display_pkt_len.c display_l4gen.c display_tasks.c display_irq.c
SRCS-y += log.c hash_utils.c main.c parse_utils.c file_utils.c
SRCS-y += run.c input_conn.c input_curses.c
SRCS-y += rx_pkt.c lconf.c tx_pkt.c expire_cpe.c ip_subnet.c
SRCS-y += stats_port.c stats_mempool.c stats_ring.c stats_l4gen.c
-SRCS-y += stats_latency.c stats_global.c stats_core.c stats_task.c stats_prio.c
+SRCS-y += stats_latency.c stats_global.c stats_core.c stats_task.c stats_prio.c stats_irq.c
SRCS-y += cmd_parser.c input.c prox_shared.c prox_lua_types.c
SRCS-y += genl4_bundle.c heap.c genl4_stream_tcp.c genl4_stream_udp.c cdf.c
SRCS-y += stats.c stats_cons_log.c stats_cons_cli.c stats_parser.c hash_set.c prox_lua.c prox_malloc.c
diff --git a/VNFs/DPPD-PROX/cmd_parser.c b/VNFs/DPPD-PROX/cmd_parser.c
index 18a4f5fc..09ea9653 100644
--- a/VNFs/DPPD-PROX/cmd_parser.c
+++ b/VNFs/DPPD-PROX/cmd_parser.c
@@ -1664,6 +1664,28 @@ static int parse_cmd_lat_stats(const char *str, struct input *input)
return 0;
}
+static int parse_cmd_show_irq_buckets(const char *str, struct input *input)
+{
+ char buf[4096] = {0};
+ unsigned int i, c;
+ unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
+
+ if (parse_core_task(str, lcores, &task_id, &nb_cores))
+ return -1;
+
+ if (cores_task_are_valid(lcores, task_id, nb_cores)) {
+ for (c = 0; c < nb_cores; c++) {
+ lcore_id = lcores[c];
+ get_irq_buckets_by_core_task(buf, lcore_id, task_id);
+ plog_info("%s", buf);
+ if (input->reply)
+ input->reply(input, buf, strlen(buf));
+ buf[0] = 0;
+ }
+ }
+ return 0;
+}
+
static int parse_cmd_irq(const char *str, struct input *input)
{
unsigned int i, c;
@@ -1906,6 +1928,7 @@ static struct cmd_str cmd_strings[] = {
{"tot imissed tot", "", "Print total number of imissed since reset", parse_cmd_tot_imissed_tot},
{"lat stats", "<core id> <task id>", "Print min,max,avg latency as measured during last sampling interval", parse_cmd_lat_stats},
{"irq stats", "<core id> <task id>", "Print irq related infos", parse_cmd_irq},
+ {"show irq buckets", "<core id> <task id>", "Print irq buckets", parse_cmd_show_irq_buckets},
{"lat packets", "<core id> <task id>", "Print the latency for each of the last set of packets", parse_cmd_lat_packets},
{"accuracy limit", "<core id> <task id> <nsec>", "Only consider latency of packets that were measured with an error no more than <nsec>", parse_cmd_accuracy},
{"core stats", "<core id> <task id>", "Print rx/tx/drop for task <task id> running on core <core id>", parse_cmd_core_stats},
@@ -1928,7 +1951,7 @@ static struct cmd_str cmd_strings[] = {
{"port down", "<port id>", "Set the port down", parse_cmd_port_down},
{"port link state", "<port id>", "Get link state (up or down) for port", parse_cmd_port_link_state},
{"port xstats", "<port id>", "Get extra statistics for the port", parse_cmd_xstats},
- {"stats", "<stats_path>", "Get stats as sepcified by <stats_path>. A comma-separated list of <stats_path> can be supplied", parse_cmd_stats},
+ {"stats", "<stats_path>", "Get stats as specified by <stats_path>. A comma-separated list of <stats_path> can be supplied", parse_cmd_stats},
{"cgnat dump public hash", "<core id> <task id>", "Dump cgnat public hash table", parse_cmd_cgnat_public_hash},
{"cgnat dump private hash", "<core id> <task id>", "Dump cgnat private hash table", parse_cmd_cgnat_private_hash},
{"delay_us", "<core_id> <task_id> <delay_us>", "Set the delay in usec for the impair mode to <delay_us>", parse_cmd_delay_us},
diff --git a/VNFs/DPPD-PROX/display.c b/VNFs/DPPD-PROX/display.c
index 2a351a09..2c52d448 100644
--- a/VNFs/DPPD-PROX/display.c
+++ b/VNFs/DPPD-PROX/display.c
@@ -26,10 +26,13 @@
#include "display_mempools.h"
#include "display_ports.h"
#include "display_priority.h"
+#include "display_irq.h"
#include "display_rings.h"
#include "display_pkt_len.h"
#include "display_l4gen.h"
#include "display_tasks.h"
+#include "stats_irq.h"
+#include "stats_prio_task.h"
#include "cqm.h"
#include "msr.h"
@@ -292,7 +295,10 @@ static void display_init_screens(void)
display_add_screen(display_rings());
display_add_screen(display_l4gen());
display_add_screen(display_pkt_len());
- display_add_screen(display_priority());
+ if (stats_get_n_prio_tasks_tot())
+ display_add_screen(display_priority());
+ if (stats_get_n_irq_tasks())
+ display_add_screen(display_irq());
}
void display_init(void)
diff --git a/VNFs/DPPD-PROX/display_irq.c b/VNFs/DPPD-PROX/display_irq.c
new file mode 100644
index 00000000..5cf347d7
--- /dev/null
+++ b/VNFs/DPPD-PROX/display_irq.c
@@ -0,0 +1,160 @@
+/*
+// Copyright (c) 2010-2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "display_irq.h"
+#include "stats_irq.h"
+#include "display.h"
+#include "lconf.h"
+
+static struct display_page display_page_irq;
+static struct display_column *stats_irq[IRQ_BUCKETS_COUNT];
+static struct display_column *stats_max;
+static struct display_column *core_col;
+static struct display_column *name_col;
+
+static void display_irq_draw_frame(struct screen_state *state)
+{
+ uint32_t n_tasks = stats_get_n_irq_tasks();
+ struct lcore_cfg *lconf = NULL;
+ struct task_args *targ;
+ char name[32];
+ char *ptr;
+
+ display_page_init(&display_page_irq);
+
+ struct display_table *core_name = display_page_add_table(&display_page_irq);
+
+ display_table_init(core_name, "Core/task");
+ core_col = display_table_add_col(core_name);
+ name_col = display_table_add_col(core_name);
+ display_column_init(core_col, "Nb", 4);
+ display_column_init(name_col, "Name", 5);
+
+ struct display_table *stats = display_page_add_table(&display_page_irq);
+ if (state->toggle == 0) {
+ display_table_init(stats, "Statistics per second");
+
+ char title[64];
+ stats_max = display_table_add_col(stats);
+ snprintf(title, sizeof(title), " MAXIMUM(mic)");
+ display_column_init(stats_max, title, 11);
+
+ stats_irq[0] = display_table_add_col(stats);
+ if (irq_bucket_maxtime_micro[0] < 1000)
+ snprintf(title, sizeof(title), " %d-%ld mic", 0, irq_bucket_maxtime_micro[0]);
+ else
+ snprintf(title, sizeof(title), " %d-%ld ms", 0, irq_bucket_maxtime_micro[0] / 1000);
+ display_column_init(stats_irq[0], title, 9);
+ for (uint i = 1; i < IRQ_BUCKETS_COUNT - 1; ++i) {
+ stats_irq[i] = display_table_add_col(stats);
+ if (irq_bucket_maxtime_micro[i-1] < 1000)
+ snprintf(title, sizeof(title), " %ld-%ld mic", irq_bucket_maxtime_micro[i-1], irq_bucket_maxtime_micro[i]);
+ else
+ snprintf(title, sizeof(title), " %ld-%ld ms", irq_bucket_maxtime_micro[i-1] / 1000, irq_bucket_maxtime_micro[i] / 1000);
+ display_column_init(stats_irq[i], title, 9);
+ }
+ stats_irq[IRQ_BUCKETS_COUNT - 1] = display_table_add_col(stats);
+ if (irq_bucket_maxtime_micro[IRQ_BUCKETS_COUNT - 2] < 1000)
+ snprintf(title, sizeof(title), " > %ld mic ", irq_bucket_maxtime_micro[IRQ_BUCKETS_COUNT - 2]);
+ else
+ snprintf(title, sizeof(title), " > %ld ms ", irq_bucket_maxtime_micro[IRQ_BUCKETS_COUNT - 2] / 1000);
+ display_column_init(stats_irq[IRQ_BUCKETS_COUNT - 1], title, 9);
+ } else {
+ display_table_init(stats, "Total statistics");
+
+ char title[64];
+ stats_max = display_table_add_col(stats);
+ snprintf(title, sizeof(title), " MAXIMUM(mic)");
+ display_column_init(stats_max, title, 9);
+
+ stats_irq[0] = display_table_add_col(stats);
+ if (irq_bucket_maxtime_micro[0] < 1000)
+ snprintf(title, sizeof(title), " %d-%ld ", 0, irq_bucket_maxtime_micro[0]);
+ else
+ snprintf(title, sizeof(title), " %d-%ld ms", 0, irq_bucket_maxtime_micro[0] / 1000);
+ display_column_init(stats_irq[0], title, 9);
+ for (uint i = 1; i < IRQ_BUCKETS_COUNT - 1; ++i) {
+ stats_irq[i] = display_table_add_col(stats);
+ if (irq_bucket_maxtime_micro[i-1] < 1000)
+ snprintf(title, sizeof(title), " %ld-%ld ", irq_bucket_maxtime_micro[i-1], irq_bucket_maxtime_micro[i]);
+ else
+ snprintf(title, sizeof(title), " %ld-%ld ms", irq_bucket_maxtime_micro[i-1] / 1000, irq_bucket_maxtime_micro[i] / 1000);
+ display_column_init(stats_irq[i], title, 9);
+ }
+ stats_irq[IRQ_BUCKETS_COUNT - 1] = display_table_add_col(stats);
+ if (irq_bucket_maxtime_micro[IRQ_BUCKETS_COUNT - 2] < 1000)
+ snprintf(title, sizeof(title), " > %ld ", irq_bucket_maxtime_micro[IRQ_BUCKETS_COUNT - 2]);
+ else
+ snprintf(title, sizeof(title), " > %ld ", irq_bucket_maxtime_micro[IRQ_BUCKETS_COUNT - 2] / 1000);
+ display_column_init(stats_irq[IRQ_BUCKETS_COUNT - 1], title, 9);
+ }
+
+ display_page_draw_frame(&display_page_irq, n_tasks);
+
+ uint32_t count = 0;
+ lconf = NULL;
+ while (core_targ_next(&lconf, &targ, 0) == 0) {
+ if (strcmp(targ->task_init->mode_str, "irq") == 0) {
+ display_column_print_core_task(core_col, count, lconf, targ);
+ if (targ->id == 0)
+ display_column_print(name_col, count, "%s", lconf->name);
+ count++;
+ }
+ }
+}
+
+static void display_irq_draw_stats(struct screen_state *state)
+{
+ struct lcore_cfg *lconf = NULL;
+ struct task_args *targ;
+ const uint32_t n_stats_irq = stats_get_n_irq_tasks();
+
+ if (state->toggle == 0) {
+ for (uint32_t count = 0; count < n_stats_irq; ++count) {
+ struct irq_sample *last = get_irq_sample(count, 1);
+ struct irq_sample *prev = get_irq_sample(count, 0);
+
+ display_column_print(stats_max, count, "%9lu", (last->max_irq * 1000000L) / rte_get_tsc_hz());
+ for (uint i = 0; i < IRQ_BUCKETS_COUNT; ++i) {
+ display_column_print(stats_irq[i], count, "%9lu", last->irq[i] - prev->irq[i]);
+ }
+ }
+ } else {
+ for (uint32_t count = 0; count < n_stats_irq; ++count) {
+ display_column_print(stats_max, count, "%9lu", get_max_irq_stats(count));
+ for (uint i = 0; i < IRQ_BUCKETS_COUNT; ++i) {
+ display_column_print(stats_irq[i], count, "%9lu", get_irq_stats(count, i));
+ }
+ }
+ }
+}
+
+static int display_irq_get_height(void)
+{
+ return stats_get_n_irq_tasks();
+}
+
+static struct display_screen display_screen_irq = {
+ .draw_frame = display_irq_draw_frame,
+ .draw_stats = display_irq_draw_stats,
+ .get_height = display_irq_get_height,
+ .title = "irq",
+};
+
+struct display_screen *display_irq(void)
+{
+ return &display_screen_irq;
+}
diff --git a/VNFs/DPPD-PROX/display_irq.h b/VNFs/DPPD-PROX/display_irq.h
new file mode 100644
index 00000000..9d6865b5
--- /dev/null
+++ b/VNFs/DPPD-PROX/display_irq.h
@@ -0,0 +1,23 @@
+/*
+// Copyright (c) 2010-2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef DISPLAY_IRQ_H
+#define DISPLAY_IRQ_H
+
+struct display_screen;
+struct display_screen *display_irq(void);
+
+#endif /* DISPLAY_IRQ_H */
diff --git a/VNFs/DPPD-PROX/handle_irq.c b/VNFs/DPPD-PROX/handle_irq.c
index 86640c69..00c192f6 100644
--- a/VNFs/DPPD-PROX/handle_irq.c
+++ b/VNFs/DPPD-PROX/handle_irq.c
@@ -20,36 +20,13 @@
#include "task_base.h"
#include "task_init.h"
#include "handle_irq.h"
+#include "stats_irq.h"
#include "log.h"
#include "unistd.h"
#include "input.h"
-#define MAX_INDEX 65535 * 16
-
-struct irq_info {
- uint64_t tsc;
- uint64_t lat;
-};
-
-struct irq_bucket {
- uint64_t index;
- struct irq_info info[MAX_INDEX];
-};
-
-struct task_irq {
- struct task_base base;
- uint64_t start_tsc;
- uint64_t first_tsc;
- uint64_t tsc;
- uint64_t max_irq;
- uint8_t lcore_id;
- volatile uint16_t stats_use_lt; /* which lt to use, */
- volatile uint16_t task_use_lt; /* 0 or 1 depending on which of the 2 result records are used */
- struct irq_bucket buffer[2];
-};
-
#define MAX_INTERRUPT_LENGTH 500000 /* Maximum length of an interrupt is (1 / MAX_INTERRUPT_LENGTH) seconds */
-
+uint64_t irq_bucket_maxtime_micro[] = {1,5,10,50,100,500,1000,5000,10000,50000,100000,500000,UINT64_MAX};
/*
* This module is not handling any packets.
* It loops on rdtsc() and checks whether it has been interrupted
@@ -58,6 +35,18 @@ struct task_irq {
* as been properly configured.
*/
+static void update_irq_stats(struct task_irq *task, uint64_t irq)
+{
+ if (irq > task->stats.max_irq)
+ task->stats.max_irq = irq;
+ for (uint i = 0; i < IRQ_BUCKETS_COUNT; ++i) {
+ if (irq < irq_bucket_maxtime_cycles[i]) {
+ task->stats.irq[i]++;
+ break;
+ }
+ }
+}
+
void task_irq_show_stats(struct task_irq *task_irq, struct input *input)
{
struct irq_bucket *bucket = &task_irq->buffer[!task_irq->task_use_lt];
@@ -104,31 +93,33 @@ static void irq_stop(struct task_base *tbase)
int bucket_id;
int n_lat = 0;
- plog_info("Stopping core %u\n", lcore_id);
- sleep(2); // Make sure all cores are stopped before starting to write
- plog_info("Core ID; Interrupt (nanosec); Time (msec)\n");
- for (int j = 0; j < 2; j++) {
- // Start dumping the oldest bucket first
- if (task->buffer[0].info[0].tsc < task->buffer[1].info[0].tsc)
- bucket_id = j;
- else
- bucket_id = !j;
- struct irq_bucket *bucket = &task->buffer[bucket_id];
- for (i=0; i< bucket->index;i++) {
- if (bucket->info[i].lat != 0) {
- lat = bucket->info[i].lat * 1000000000 / rte_get_tsc_hz();
- if (max_lat < lat)
- max_lat = lat;
- n_lat++;
- tot_lat += lat;
- plog_info("%d; %ld; %ld\n", lcore_id, lat,
- (bucket->info[i].tsc - task->start_tsc) * 1000 / rte_get_tsc_hz());
+ if (task->irq_debug) {
+ plog_info("Stopping core %u\n", lcore_id);
+ sleep(2); // Make sure all cores are stopped before starting to write
+ plog_info("Core ID; Interrupt (nanosec); Time (msec)\n");
+ for (int j = 0; j < 2; j++) {
+ // Start dumping the oldest bucket first
+ if (task->buffer[0].info[0].tsc < task->buffer[1].info[0].tsc)
+ bucket_id = j;
+ else
+ bucket_id = !j;
+ struct irq_bucket *bucket = &task->buffer[bucket_id];
+ for (i=0; i< bucket->index;i++) {
+ if (bucket->info[i].lat != 0) {
+ lat = bucket->info[i].lat * 1000000000 / rte_get_tsc_hz();
+ if (max_lat < lat)
+ max_lat = lat;
+ n_lat++;
+ tot_lat += lat;
+ plog_info("%d; %ld; %ld\n", lcore_id, lat,
+ (bucket->info[i].tsc - task->start_tsc) * 1000 / rte_get_tsc_hz());
+ }
}
}
+ if (n_lat)
+ tot_lat = tot_lat / n_lat;
+ plog_info("Core %u stopped. max lat is %ld and average is %ld\n", lcore_id, max_lat, tot_lat);
}
- if (n_lat)
- tot_lat = tot_lat / n_lat;
- plog_info("Core %u stopped. max lat is %ld and average is %ld\n", lcore_id, max_lat, tot_lat);
}
static inline int handle_irq_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
@@ -142,9 +133,12 @@ static inline int handle_irq_bulk(struct task_base *tbase, struct rte_mbuf **mbu
struct irq_bucket *bucket = &task->buffer[task->task_use_lt];
tsc1 = rte_rdtsc();
- if ((tsc1 > task->first_tsc) && (task->tsc != 0) && ((tsc1 - task->tsc) > task->max_irq) && (bucket->index < MAX_INDEX)) {
- bucket->info[bucket->index].tsc = tsc1;
- bucket->info[bucket->index++].lat = tsc1 - task->tsc;
+ if ((tsc1 > task->first_tsc) && (task->tsc != 0)) {
+ update_irq_stats(task, tsc1 - task->tsc);
+ if (((tsc1 - task->tsc) > task->max_irq) && (bucket->index < MAX_INDEX)) {
+ bucket->info[bucket->index].tsc = tsc1;
+ bucket->info[bucket->index++].lat = tsc1 - task->tsc;
+ }
}
task->tsc = tsc1;
return 0;
@@ -154,12 +148,17 @@ static void init_task_irq(struct task_base *tbase,
__attribute__((unused)) struct task_args *targ)
{
struct task_irq *task = (struct task_irq *)tbase;
- // max_irq expressed in cycles
- task->max_irq = rte_get_tsc_hz() / MAX_INTERRUPT_LENGTH;
task->start_tsc = rte_rdtsc();
task->first_tsc = task->start_tsc + 2 * rte_get_tsc_hz();
task->lcore_id = targ->lconf->id;
+ task->irq_debug = targ->irq_debug;
+ // max_irq expressed in cycles
+ task->max_irq = rte_get_tsc_hz() / MAX_INTERRUPT_LENGTH;
plog_info("\tusing irq mode with max irq set to %ld cycles\n", task->max_irq);
+
+ for (uint bucket_id = 0; bucket_id < IRQ_BUCKETS_COUNT - 1; bucket_id++)
+ irq_bucket_maxtime_cycles[bucket_id] = rte_get_tsc_hz() * irq_bucket_maxtime_micro[bucket_id] / 1000000;
+ irq_bucket_maxtime_cycles[IRQ_BUCKETS_COUNT - 1] = UINT64_MAX;
}
static struct task_init task_init_irq = {
diff --git a/VNFs/DPPD-PROX/handle_irq.h b/VNFs/DPPD-PROX/handle_irq.h
index 784bf0d6..2399c8d0 100644
--- a/VNFs/DPPD-PROX/handle_irq.h
+++ b/VNFs/DPPD-PROX/handle_irq.h
@@ -17,7 +17,35 @@
#ifndef _HANDLE_IRQ_H_
#define _HANDLE_IRQ_H_
-struct task_irq;
+#include "task_base.h"
+#include "stats_irq.h"
+
+#define MAX_INDEX 65535 * 16
+
+struct irq_info {
+ uint64_t tsc;
+ uint64_t lat;
+};
+
+struct irq_bucket {
+ uint64_t index;
+ struct irq_info info[MAX_INDEX];
+};
+
+struct task_irq {
+ struct task_base base;
+ uint64_t start_tsc;
+ uint64_t first_tsc;
+ uint64_t tsc;
+ uint64_t max_irq;
+ uint8_t lcore_id;
+ uint8_t irq_debug;
+ volatile uint16_t stats_use_lt; /* which lt to use, */
+ volatile uint16_t task_use_lt; /* 0 or 1 depending on which of the 2 result records are used */
+ struct irq_bucket buffer[2];
+ struct irq_rt_stats stats;
+};
+
struct input;
void task_irq_show_stats(struct task_irq *task_irq, struct input *input);
diff --git a/VNFs/DPPD-PROX/prox_args.c b/VNFs/DPPD-PROX/prox_args.c
index fb053802..08f27e9e 100644
--- a/VNFs/DPPD-PROX/prox_args.c
+++ b/VNFs/DPPD-PROX/prox_args.c
@@ -1520,6 +1520,11 @@ static int get_core_cfg(unsigned sindex, char *str, void *data)
return 0;
}
+ if (STR_EQ(str, "irq debug")) {
+ parse_int(&targ->irq_debug, pkey);
+ return 0;
+ }
+
set_errf("Option '%s' is not known", str);
/* fail on unknown keys */
return -1;
diff --git a/VNFs/DPPD-PROX/prox_port_cfg.c b/VNFs/DPPD-PROX/prox_port_cfg.c
index bf8dbda2..c4787b1e 100644
--- a/VNFs/DPPD-PROX/prox_port_cfg.c
+++ b/VNFs/DPPD-PROX/prox_port_cfg.c
@@ -39,6 +39,7 @@
#include "toeplitz.h"
#include "defines.h"
#include "prox_cksum.h"
+#include "stats_irq.h"
struct prox_port_cfg prox_port_cfg[PROX_MAX_PORTS];
rte_atomic32_t lsc;
@@ -54,7 +55,7 @@ int prox_nb_active_ports(void)
int prox_last_port_active(void)
{
- int ret = 0;
+ int ret = -1;
for (uint32_t i = 0; i < PROX_MAX_PORTS; ++i) {
if (prox_port_cfg[i].active) {
ret = i;
@@ -125,7 +126,8 @@ void prox_pktmbuf_reinit(void *arg, void *start, __attribute__((unused)) void *e
/* initialize rte devices and check the number of available ports */
void init_rte_dev(int use_dummy_devices)
{
- uint8_t nb_ports, port_id_max, port_id_last;
+ uint8_t nb_ports, port_id_max;
+ int port_id_last;
struct rte_eth_dev_info dev_info;
nb_ports = rte_eth_dev_count();
@@ -150,7 +152,7 @@ void init_rte_dev(int use_dummy_devices)
PROX_PANIC(use_dummy_devices, "Can't use dummy devices\n");
#endif
}
- else {
+ else if (prox_last_port_active() != -1) {
PROX_PANIC(nb_ports == 0, "\tError: DPDK could not find any port\n");
plog_info("\tDPDK has found %u ports\n", nb_ports);
}
diff --git a/VNFs/DPPD-PROX/stats.c b/VNFs/DPPD-PROX/stats.c
index 2418826f..656b8d37 100644
--- a/VNFs/DPPD-PROX/stats.c
+++ b/VNFs/DPPD-PROX/stats.c
@@ -29,6 +29,7 @@
#include "stats_task.h"
#include "stats_prio_task.h"
#include "stats_latency.h"
+#include "stats_irq.h"
/* Stores all readed values from the cores, displaying is done afterwards because
displaying introduces overhead. If displaying was done right after the values
@@ -41,6 +42,7 @@ void stats_reset(void)
stats_prio_task_reset();
stats_port_reset();
stats_latency_reset();
+ stats_irq_reset();
stats_global_reset();
}
@@ -49,6 +51,7 @@ void stats_init(unsigned avg_start, unsigned duration)
stats_lcore_init();
stats_task_init();
stats_prio_task_init();
+ stats_irq_init();
stats_port_init();
stats_mempool_init();
stats_latency_init();
@@ -86,6 +89,9 @@ void stats_update(uint16_t flag_cons)
if (flag_cons & STATS_CONS_F_RINGS)
stats_ring_update();
+ if (flag_cons & STATS_CONS_F_IRQ)
+ stats_irq_update();
+
if (flag_cons & STATS_CONS_F_LCORE)
stats_lcore_post_proc();
@@ -97,4 +103,7 @@ void stats_update(uint16_t flag_cons)
if (flag_cons & STATS_CONS_F_GLOBAL)
stats_global_post_proc();
+
+ if (flag_cons & STATS_CONS_F_IRQ)
+ stats_irq_post_proc();
}
diff --git a/VNFs/DPPD-PROX/stats_cons.h b/VNFs/DPPD-PROX/stats_cons.h
index ba51f49f..453ee518 100644
--- a/VNFs/DPPD-PROX/stats_cons.h
+++ b/VNFs/DPPD-PROX/stats_cons.h
@@ -26,7 +26,8 @@
#define STATS_CONS_F_L4GEN 0x40
#define STATS_CONS_F_GLOBAL 0x80
#define STATS_CONS_F_PRIO_TASKS 0x100
-#define STATS_CONS_F_ALL 0x1ff
+#define STATS_CONS_F_IRQ 0x200
+#define STATS_CONS_F_ALL 0x3ff
struct stats_cons {
void (*init)(void);
diff --git a/VNFs/DPPD-PROX/stats_irq.c b/VNFs/DPPD-PROX/stats_irq.c
new file mode 100644
index 00000000..cd1b78d7
--- /dev/null
+++ b/VNFs/DPPD-PROX/stats_irq.c
@@ -0,0 +1,144 @@
+/*
+// Copyright (c) 2010-2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <stddef.h>
+
+#include "handle_irq.h"
+#include "stats_irq.h"
+#include "prox_cfg.h"
+#include "prox_globals.h"
+#include "lconf.h"
+
+static struct irq_task_stats irq_task_stats_set[RTE_MAX_LCORE * MAX_TASKS_PER_CORE];
+static uint8_t nb_irq_tasks;
+
+int stats_get_n_irq_tasks(void)
+{
+ return nb_irq_tasks;
+}
+
+struct irq_sample *get_irq_sample(uint32_t task_id, int l)
+{
+ return &irq_task_stats_set[task_id].sample[last_stat == l];
+}
+
+struct irq_sample *get_irq_sample_by_core_task(uint32_t lcore_id, uint32_t irq_task_id, int l)
+{
+ for (uint8_t task_id = 0; task_id < nb_irq_tasks; ++task_id) {
+ if ((irq_task_stats_set[task_id].lcore_id == lcore_id) && (irq_task_stats_set[task_id].task_id == irq_task_id))
+ return &irq_task_stats_set[task_id].sample[last_stat == l];
+ }
+ return NULL;
+}
+
+void stats_irq_reset(void)
+{
+ struct irq_task_stats *cur_task_stats;
+
+ for (uint8_t task_id = 0; task_id < nb_irq_tasks; ++task_id) {
+ cur_task_stats = &irq_task_stats_set[task_id];
+ cur_task_stats->max_irq = 0;
+ for (uint i = 0; i < IRQ_BUCKETS_COUNT; ++i) {
+ cur_task_stats->irq[i] = 0;
+ }
+ }
+}
+
+void stats_irq_post_proc(void)
+{
+ for (uint8_t task_id = 0; task_id < nb_irq_tasks; ++task_id) {
+ struct irq_task_stats *cur_task_stats = &irq_task_stats_set[task_id];
+ struct irq_rt_stats *stats = cur_task_stats->stats;
+ const struct irq_sample *last = &cur_task_stats->sample[last_stat];
+ const struct irq_sample *prev = &cur_task_stats->sample[!last_stat];
+
+ if (cur_task_stats->max_irq < last->max_irq)
+ cur_task_stats->max_irq = last->max_irq;
+ for (uint i = 0; i < IRQ_BUCKETS_COUNT; ++i) {
+ cur_task_stats->irq[i] += last->irq[i] - prev->irq[i];
+ }
+ stats->max_irq = 0;
+ }
+}
+
+void stats_irq_update(void)
+{
+ for (uint8_t task_id = 0; task_id < nb_irq_tasks; ++task_id) {
+ struct irq_task_stats *cur_task_stats = &irq_task_stats_set[task_id];
+ struct irq_rt_stats *stats = cur_task_stats->stats;
+ struct irq_sample *sample = &cur_task_stats->sample[last_stat];
+
+ sample->max_irq = stats->max_irq;
+ for (uint i = 0; i < IRQ_BUCKETS_COUNT; ++i) {
+ sample->irq[i] = stats->irq[i];
+ }
+ }
+}
+
+void stats_irq_init(void)
+{
+ struct lcore_cfg *lconf;
+ uint32_t lcore_id;
+
+ lcore_id = -1;
+ while(prox_core_next(&lcore_id, 0) == 0) {
+ lconf = &lcore_cfg[lcore_id];
+ for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
+ struct task_args *targ = &lconf->targs[task_id];
+ if (strcmp(targ->task_init->mode_str, "irq") == 0) {
+ struct irq_rt_stats *stats = &((struct task_irq *)(lconf->tasks_all[task_id]))->stats;
+ irq_task_stats_set[nb_irq_tasks].stats = stats;
+ irq_task_stats_set[nb_irq_tasks].lcore_id = lcore_id;
+ irq_task_stats_set[nb_irq_tasks++].task_id = task_id;
+ }
+ }
+ }
+}
+
+uint64_t get_max_irq_stats_by_core_task(uint8_t lcore_id, uint8_t irq_task_id)
+{
+ for (uint8_t task_id = 0; task_id < nb_irq_tasks; ++task_id) {
+ if ((irq_task_stats_set[task_id].lcore_id == lcore_id) && (irq_task_stats_set[task_id].task_id == irq_task_id))
+ return (irq_task_stats_set[task_id].max_irq * 1000000) / rte_get_tsc_hz();
+ }
+ return -1;
+}
+
+uint64_t get_irq_stats_by_core_task(uint8_t lcore_id, uint8_t irq_task_id, int id)
+{
+ for (uint8_t task_id = 0; task_id < nb_irq_tasks; ++task_id) {
+ if ((irq_task_stats_set[task_id].lcore_id == lcore_id) && (irq_task_stats_set[task_id].task_id == irq_task_id))
+ return irq_task_stats_set[task_id].irq[id];
+ }
+ return -1;
+}
+
+uint64_t get_max_irq_stats(uint8_t task_id)
+{
+ return (irq_task_stats_set[task_id].max_irq * 1000000L) / rte_get_tsc_hz();
+}
+
+uint64_t get_irq_stats(uint8_t task_id, int bucket_id)
+{
+ return irq_task_stats_set[task_id].irq[bucket_id];
+}
+void get_irq_buckets_by_core_task(char *buf, uint8_t lcore_id, uint8_t irq_task_id)
+{
+ for (int i = 0; i < IRQ_BUCKETS_COUNT; i++) {
+ sprintf(buf+strlen(buf), "%ld; ", irq_bucket_maxtime_micro[i]);
+ }
+ sprintf(buf+strlen(buf), "\n");
+}
diff --git a/VNFs/DPPD-PROX/stats_irq.h b/VNFs/DPPD-PROX/stats_irq.h
new file mode 100644
index 00000000..71ff80f7
--- /dev/null
+++ b/VNFs/DPPD-PROX/stats_irq.h
@@ -0,0 +1,71 @@
+/*
+// Copyright (c) 2010-2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef _STATS_IRQ_H_
+#define _STATS_IRQ_H_
+
+#include <inttypes.h>
+
+#include "clock.h"
+
+#define IRQ_BUCKETS_COUNT 13
+
+extern int last_stat;
+
+// irq_rt_stats is updated real time by handle_irq. It contains total stats, from beginning
+// It cannot be reset to 0, as the reset would be done by another core
+struct irq_rt_stats {
+ uint64_t max_irq;
+ uint64_t irq[IRQ_BUCKETS_COUNT];
+};
+
+// irq_sample is updated by irq_update - as sampling of irq_rt_stats
+// There is usually one sample per second; two samples in total
+struct irq_sample {
+ uint64_t tsc;
+ uint64_t max_irq;
+ uint64_t irq[IRQ_BUCKETS_COUNT];
+};
+
+// Those are the total stats; there can be reset
+// They are obtained by adding samples
+struct irq_task_stats {
+ uint8_t lcore_id;
+ uint8_t task_id;
+ uint64_t max_irq;
+ uint64_t irq[IRQ_BUCKETS_COUNT];
+ struct irq_sample sample[2];
+ struct irq_rt_stats *stats;
+};
+
+uint64_t irq_bucket_maxtime_cycles[IRQ_BUCKETS_COUNT];
+extern uint64_t irq_bucket_maxtime_micro[];
+
+void stats_irq_reset(void);
+void stats_irq_post_proc(void);
+void stats_irq_update(void);
+void stats_irq_init(void);
+int stats_get_n_irq_tasks(void);
+
+struct irq_sample *get_irq_sample(uint32_t task_id, int last);
+struct irq_sample *get_irq_sample_by_core_task(uint32_t lcore_id, uint32_t task_id, int last);
+uint64_t get_max_irq_stats(uint8_t task_id);
+uint64_t get_irq_stats(uint8_t task_id, int bucket_id);
+uint64_t get_max_irq_stats_by_core_task(uint8_t lcore_id, uint8_t task_id);
+uint64_t get_irq_stats_by_core_task(uint8_t lcore_id, uint8_t task_id, int bucket_id);
+void get_irq_buckets_by_core_task(char *buf, uint8_t lcore_id, uint8_t irq_task_id);
+
+#endif /* _STATS_IRQ_H_ */
diff --git a/VNFs/DPPD-PROX/stats_parser.c b/VNFs/DPPD-PROX/stats_parser.c
index aa9d6741..37e1781b 100644
--- a/VNFs/DPPD-PROX/stats_parser.c
+++ b/VNFs/DPPD-PROX/stats_parser.c
@@ -30,6 +30,7 @@
#include "stats_latency.h"
#include "stats_global.h"
#include "stats_prio_task.h"
+#include "stats_irq.h"
struct stats_path_str {
const char *str;
@@ -108,6 +109,26 @@ static uint64_t sp_task_rx_prio(int argc, const char *argv[])
return stats_get_prio_task_stats_sample_by_core_task(c, t, 1)->rx_prio[atoi(argv[2])];
}
+static uint64_t sp_task_max_irq(int argc, const char *argv[])
+{
+ struct task_stats_sample *last;
+ uint32_t c, t;
+
+ if (args_to_core_task(argv[0], argv[1], &c, &t))
+ return -1;
+ return get_max_irq_stats_by_core_task(c, t);
+}
+
+static uint64_t sp_task_irq(int argc, const char *argv[])
+{
+ struct task_stats_sample *last;
+ uint32_t c, t;
+
+ if (args_to_core_task(argv[0], argv[1], &c, &t))
+ return -1;
+ return get_irq_stats_by_core_task(c, t, atoi(argv[2]));
+}
+
static uint64_t sp_task_drop_discard(int argc, const char *argv[])
{
struct task_stats_sample *last;
@@ -767,6 +788,8 @@ struct stats_path_str stats_paths[] = {
{"task.core(#).task(#).tsc", sp_task_tsc},
{"task.core(#).task(#).drop.tx_fail_prio(#)", sp_task_drop_tx_fail_prio},
{"task.core(#).task(#).rx_prio(#)", sp_task_rx_prio},
+ {"task.core(#).task(#).max_irq", sp_task_max_irq},
+ {"task.core(#).task(#).irq(#)", sp_task_irq},
{"port(#).no_mbufs", sp_port_no_mbufs},
{"port(#).ierrors", sp_port_ierrors},
diff --git a/VNFs/DPPD-PROX/task_init.h b/VNFs/DPPD-PROX/task_init.h
index 745a7425..c5a17796 100644
--- a/VNFs/DPPD-PROX/task_init.h
+++ b/VNFs/DPPD-PROX/task_init.h
@@ -229,6 +229,7 @@ struct task_args {
struct rte_ring **ctrl_rx_rings;
struct rte_ring **ctrl_tx_rings;
int n_ctrl_rings;
+ uint irq_debug;
struct task_base *tmaster;
char sub_mode_str[PROX_MODE_LEN];
};