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>
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
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;
{"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},
{"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},
#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"
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)
--- /dev/null
+/*
+// 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;
+}
--- /dev/null
+/*
+// 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 */
#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
* 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];
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)
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;
__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 = {
#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);
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;
#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;
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;
/* 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();
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);
}
#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
stats_prio_task_reset();
stats_port_reset();
stats_latency_reset();
+ stats_irq_reset();
stats_global_reset();
}
stats_lcore_init();
stats_task_init();
stats_prio_task_init();
+ stats_irq_init();
stats_port_init();
stats_mempool_init();
stats_latency_init();
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();
if (flag_cons & STATS_CONS_F_GLOBAL)
stats_global_post_proc();
+
+ if (flag_cons & STATS_CONS_F_IRQ)
+ stats_irq_post_proc();
}
#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);
--- /dev/null
+/*
+// 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");
+}
--- /dev/null
+/*
+// 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_ */
#include "stats_latency.h"
#include "stats_global.h"
#include "stats_prio_task.h"
+#include "stats_irq.h"
struct stats_path_str {
const char *str;
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;
{"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},
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];
};