diff options
author | Xavier Simonart <xavier.simonart@intel.com> | 2018-01-14 18:13:09 +0100 |
---|---|---|
committer | Xavier Simonart <xavier.simonart@intel.com> | 2018-01-16 16:53:26 +0100 |
commit | ab933e9fd74d5a4e20eeb30e3fab3977e98b8743 (patch) | |
tree | 81bd77c978e4308cf51f78391397be7be6998af3 /VNFs | |
parent | deab1ee8197298bd7cf30d259a28206841d59383 (diff) |
Integrate irq mode into PROX (support display and command line)
irq mode can be used to show how a core is interrupted by other tasks.
This mode does not handle packets. It only loops reading tsc.
When the difference between two consecutive calls to rdtsc() is high
then it means the core was interrupted.
This task implementes the display, so that we can see a histogram of
interrupts as well as the maximum, per core.
Command line is also supported, through "show irq buckets" (too show
the intervals of each buckets, in micrcoseconds), and the stats
command line (showing the number of items in each buckets and the max)..
Change-Id: I153cc3deaa7b86ae2776ea44e46ef9ecfd116992
Signed-off-by: Xavier Simonart <xavier.simonart@intel.com>
Diffstat (limited to 'VNFs')
-rw-r--r-- | VNFs/DPPD-PROX/Makefile | 4 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/cmd_parser.c | 25 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/display.c | 8 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/display_irq.c | 160 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/display_irq.h | 23 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/handle_irq.c | 103 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/handle_irq.h | 30 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/prox_args.c | 5 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/prox_port_cfg.c | 8 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/stats.c | 9 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/stats_cons.h | 3 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/stats_irq.c | 144 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/stats_irq.h | 71 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/stats_parser.c | 23 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/task_init.h | 1 |
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]; }; |