diff options
Diffstat (limited to 'VNFs/DPPD-PROX')
-rw-r--r-- | VNFs/DPPD-PROX/Makefile | 4 | ||||
-rw-r--r-- | VNFs/DPPD-PROX/cmd_parser.c | 33 | ||||
-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_gen.c | 19 | ||||
-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/handle_lat.c | 32 | ||||
-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 |
17 files changed, 604 insertions, 72 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..f88ee942 100644 --- a/VNFs/DPPD-PROX/cmd_parser.c +++ b/VNFs/DPPD-PROX/cmd_parser.c @@ -545,8 +545,8 @@ static int parse_cmd_speed(const char *str, struct input *input) if ((!task_is_mode_and_submode(lcore_id, task_id, "gen", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "gen", "l3"))) { plog_err("Core %u task %u is not generating packets\n", lcore_id, task_id); } - else if (speed > 400.0f || speed < 0.0f) { - plog_err("Speed out of range (must be betweeen 0%% and 100%%)\n"); + else if (speed > 1000.0f || speed < 0.0f) { // Up to 100 Gbps + plog_err("Speed out of range (must be betweeen 0%% and 1000%%)\n"); } else { struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id]; @@ -579,8 +579,8 @@ static int parse_cmd_speed_byte(const char *str, struct input *input) if ((!task_is_mode_and_submode(lcore_id, task_id, "gen", "")) && (!task_is_mode_and_submode(lcore_id, task_id, "gen", "l3"))) { plog_err("Core %u task %u is not generating packets\n", lcore_id, task_id); } - else if (bps > 1250000000) { - plog_err("Speed out of range (must be <= 1250000000)\n"); + else if (bps > 12500000000) { // Up to 100Gbps + plog_err("Speed out of range (must be <= 12500000000)\n"); } else { struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id]; @@ -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_gen.c b/VNFs/DPPD-PROX/handle_gen.c index c48b4c13..0f70ee6b 100644 --- a/VNFs/DPPD-PROX/handle_gen.c +++ b/VNFs/DPPD-PROX/handle_gen.c @@ -122,6 +122,7 @@ struct task_gen { struct ether_addr src_mac; uint8_t flags; uint8_t cksum_offload; + struct prox_port_cfg *port; } __rte_cache_aligned; static inline uint8_t ipv4_get_hdr_len(struct ipv4_hdr *ip) @@ -1144,6 +1145,12 @@ static void start(struct task_base *tbase) if (tbase->l3.tmaster) { register_all_ip_to_ctrl_plane(task); } + if (task->port) { + // task->port->link->speed reports the link speed in Mbps e.g. 40k for a 40 Gbps NIC + // task->link_speed reported link speed in Bytes per sec. + task->link_speed = task->port->link_speed * 125000L; + plog_info("\tGenerating at %ld Mbps\n", 8 * task->link_speed / 1000000); + } /* TODO Handle the case when two tasks transmit to the same port and one of them is stopped. In that case ARP (requests or replies) @@ -1190,9 +1197,16 @@ static void init_task_gen(struct task_base *tbase, struct task_args *targ) task->sig = targ->sig; task->new_rate_bps = targ->rate_bps; + /* + * For tokens, use 10 Gbps as base rate + * Scripts can then use speed command, with speed=100 as 10 Gbps and speed=400 as 40 Gbps + * Script can query prox "port info" command to find out the port link speed to know + * at which rate to start. Note that virtio running on OVS returns 10 Gbps, so a script has + * probably also to check the driver (as returned by the same "port info" command. + */ struct token_time_cfg tt_cfg = token_time_cfg_create(1250000000, rte_get_tsc_hz(), -1); - token_time_init(&task->token_time, &tt_cfg); + init_task_gen_seeds(task); task->min_bulk_size = targ->min_bulk_size; @@ -1211,8 +1225,6 @@ static void init_task_gen(struct task_base *tbase, struct task_args *targ) task->generator_id = targ->generator_id; task->link_speed = UINT64_MAX; - if (targ->nb_txrings == 0 && targ->nb_txports == 1) - task->link_speed = 1250000000; if (!strcmp(targ->pcap_file, "")) { plog_info("\tUsing inline definition of a packet\n"); @@ -1237,6 +1249,7 @@ static void init_task_gen(struct task_base *tbase, struct task_args *targ) struct prox_port_cfg *port = find_reachable_port(targ); if (port) { task->cksum_offload = port->capabilities.tx_offload_cksum; + task->port = port; } } 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/handle_lat.c b/VNFs/DPPD-PROX/handle_lat.c index 95ebcc73..b50f9504 100644 --- a/VNFs/DPPD-PROX/handle_lat.c +++ b/VNFs/DPPD-PROX/handle_lat.c @@ -32,6 +32,7 @@ #include "quit.h" #include "eld.h" #include "prox_shared.h" +#include "prox_port_cfg.h" #define DEFAULT_BUCKET_SIZE 10 @@ -105,8 +106,10 @@ struct task_lat { uint32_t generator_count; struct early_loss_detect *eld; struct rx_pkt_meta_data *rx_pkt_meta; + uint64_t link_speed; FILE *fp_rx; FILE *fp_tx; + struct prox_port_cfg *port; }; static uint32_t abs_diff(uint32_t a, uint32_t b) @@ -375,9 +378,9 @@ static uint32_t task_lat_early_loss_detect(struct task_lat *task, struct unique_ return early_loss_detect_add(eld, packet_index); } -static uint64_t tsc_extrapolate_backward(uint64_t tsc_from, uint64_t bytes, uint64_t tsc_minimum) +static uint64_t tsc_extrapolate_backward(uint64_t link_speed, uint64_t tsc_from, uint64_t bytes, uint64_t tsc_minimum) { - uint64_t tsc = tsc_from - rte_get_tsc_hz()*bytes/1250000000; + uint64_t tsc = tsc_from - (rte_get_tsc_hz()*bytes)/link_speed; if (likely(tsc > tsc_minimum)) return tsc; else @@ -495,7 +498,7 @@ static int handle_lat_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uin bytes_total_in_bulk += mbuf_wire_size(mbufs[flipped]); } - pkt_rx_time = tsc_extrapolate_backward(rx_tsc, task->rx_pkt_meta[0].bytes_after_in_bulk, task->last_pkts_tsc) >> LATENCY_ACCURACY; + pkt_rx_time = tsc_extrapolate_backward(task->link_speed, rx_tsc, task->rx_pkt_meta[0].bytes_after_in_bulk, task->last_pkts_tsc) >> LATENCY_ACCURACY; if ((uint32_t)((task->begin >> LATENCY_ACCURACY)) > pkt_rx_time) { // Extrapolation went up to BEFORE begin => packets were stuck in the NIC but we were not seeing them rx_time_err = pkt_rx_time - (uint32_t)(task->last_pkts_tsc >> LATENCY_ACCURACY); @@ -510,7 +513,7 @@ static int handle_lat_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uin struct rx_pkt_meta_data *rx_pkt_meta = &task->rx_pkt_meta[j]; uint8_t *hdr = rx_pkt_meta->hdr; - pkt_rx_time = tsc_extrapolate_backward(rx_tsc, rx_pkt_meta->bytes_after_in_bulk, task->last_pkts_tsc) >> LATENCY_ACCURACY; + pkt_rx_time = tsc_extrapolate_backward(task->link_speed, rx_tsc, rx_pkt_meta->bytes_after_in_bulk, task->last_pkts_tsc) >> LATENCY_ACCURACY; pkt_tx_time = rx_pkt_meta->pkt_tx_time; if (task->unique_id_pos) { @@ -604,6 +607,18 @@ void task_lat_set_accuracy_limit(struct task_lat *task, uint32_t accuracy_limit_ task->limit = nsec_to_tsc(accuracy_limit_nsec); } +static void lat_start(struct task_base *tbase) +{ + struct task_lat *task = (struct task_lat *)tbase; + + if (task->port) { + // task->port->link->speed reports the link speed in Mbps e.g. 40k for a 40 Gbps NIC + // task->link_speed reported link speed in Bytes per sec. + task->link_speed = task->port->link_speed * 125000L; + plog_info("\tReceiving at %ld Mbps\n", 8 * task->link_speed / 1000000); + } +} + static void init_task_lat(struct task_base *tbase, struct task_args *targ) { struct task_lat *task = (struct task_lat *)tbase; @@ -636,12 +651,21 @@ static void init_task_lat(struct task_base *tbase, struct task_args *targ) task_lat_set_accuracy_limit(task, targ->accuracy_limit_nsec); task->rx_pkt_meta = prox_zmalloc(MAX_RX_PKT_ALL * sizeof(*task->rx_pkt_meta), socket_id); PROX_PANIC(task->rx_pkt_meta == NULL, "unable to allocate memory to store RX packet meta data"); + + task->link_speed = UINT64_MAX; + if (targ->nb_rxports) { + // task->port structure is only used while starting handle_lat to get the link_speed. + // link_speed can not be quiried at init as the port has not been initialized yet. + struct prox_port_cfg *port = &prox_port_cfg[targ->rx_port_queue[0].port]; + task->port = port; + } } static struct task_init task_init_lat = { .mode_str = "lat", .init = init_task_lat, .handle = handle_lat_bulk, + .start = lat_start, .stop = lat_stop, .flag_features = TASK_FEATURE_TSC_RX | TASK_FEATURE_RX_ALL | TASK_FEATURE_ZERO_RX | TASK_FEATURE_NEVER_DISCARDS, .size = sizeof(struct task_lat) 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]; }; |