- Latency Distribution (i.e. histograms) has been added when latency is enabled.
- Histograms are now compiled by default.
- A bug has also been fixed, which was causing strange behavior in the histograms
(due to bucket size being overwritten).
- The default bucket size has been changed to "11" which means that the size of each bucket
is now (1 cycle << 11) = 2048 cycles = 1 microsecond at 2GHz. It was (1 << (10 - 1)).
As there are 128 latency buckets, it is not possible to show all of them on the display.
Hence the latency buckets are displayed based on on the assumption that the minimum latency is usually relatively
stable and that the maximum latency change more often.
- The first empty buckets are not shown (i.e. buckets empty for all tasks)
- If more than 15 buckets are non empty, then the buckets are combined, so that a maximum of
15 (bigger) buckets are shown
- If less than 15 buckets are non empty, the following (empty) buckets are shown
(this avoid seeing every x seconds some columns being added and removed).
Change-Id: I27fe6ac0e513a5558e42ff2e74255c55ba79516d
Signed-off-by: Xavier Simonart <xavier.simonart@intel.com>
##
-## Copyright (c) 2010-2017 Intel Corporation
+## Copyright (c) 2010-2019 Intel Corporation
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
#CFLAGS += -DASSERT
#CFLAGS += -DENABLE_EXTRA_USER_STATISTICS
CFLAGS += -DLATENCY_PER_PACKET
-CFLAGS += -DLATENCY_DETAILS
+CFLAGS += -DLATENCY_HISTOGRAM
CFLAGS += -DGRE_TP
CFLAGS += -std=gnu99
CFLAGS += -D_GNU_SOURCE # for PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
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.c display_latency.c display_latency_distr.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 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
/*
-// Copyright (c) 2010-2017 Intel Corporation
+// Copyright (c) 2010-2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
plog_info("Bucket [%zu]: %"PRIu64"\n", i, buckets[i]);
}
#else
- plog_info("LATENCY_DETAILS disabled\n");
+ plog_info("LATENCY_HISTOGRAM disabled\n");
#endif
}
/*
-// Copyright (c) 2010-2017 Intel Corporation
+// Copyright (c) 2010-2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
#include "display_ports.h"
#include "display_priority.h"
#include "display_irq.h"
+#include "display_latency_distr.h"
#include "display_rings.h"
#include "display_pkt_len.h"
#include "display_l4gen.h"
display_add_screen(display_ports());
display_add_screen(display_mempools());
display_add_screen(display_latency());
+#ifdef LATENCY_HISTOGRAM
+ display_add_screen(display_latency_distr());
+#endif
display_add_screen(display_rings());
display_add_screen(display_l4gen());
display_add_screen(display_pkt_len());
stats_display_layout(1);
}
+void display_renew(void)
+{
+ stats_display_layout(0);
+}
+
void display_stats(void)
{
display_lock();
/*
-// Copyright (c) 2010-2017 Intel Corporation
+// Copyright (c) 2010-2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
#ifndef _DISPLAY_H_
#define _DISPLAY_H_
+#define PROX_MAX_COLS 32
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
};
struct display_table {
- struct display_column cols[16];
+ struct display_column cols[PROX_MAX_COLS];
char title[32];
int n_cols;
int offset;
void display_end(void);
void display_stats(void);
void display_refresh(void);
+void display_renew(void);
void display_print(const char *str);
void display_cmd(const char *cmd, int cmd_len, int cursor_pos);
void display_screen(unsigned screen_id);
--- /dev/null
+/*
+// Copyright (c) 2019 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 <math.h>
+#include "handle_lat.h"
+#include "display_latency_distr.h"
+#include "stats_latency.h"
+#include "display.h"
+#include "lconf.h"
+
+static struct display_page display_page_latency_distr;
+static struct display_column *stats_latency_distr[LAT_BUCKET_COUNT];
+static struct display_column *stats_max;
+static struct display_column *core_col;
+static struct display_column *name_col;
+static uint32_t global_min_bucket_id = 0, global_max_bucket_id = LAT_BUCKET_COUNT - 1;
+static const uint16_t global_nb_buckets_displayed = 15;
+static uint32_t group_size = 9; //LAT_BUCKET_COUNT / global_nb_buckets_displayed;
+
+#define UNIT_INT(i) (((i) * bucket_unit_nsec)/1000)
+#define UNIT_FRACT(i) ((((i) * bucket_unit_nsec) % 1000) / 100)
+
+static void display_latency_distr_draw_frame(struct screen_state *state)
+{
+ uint32_t n_tasks = stats_get_n_latency();
+ struct lcore_cfg *lconf = NULL;
+ struct task_args *targ;
+ char name[32];
+ char *ptr;
+
+ display_page_init(&display_page_latency_distr);
+
+ struct display_table *core_name = display_page_add_table(&display_page_latency_distr);
+
+ 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);
+
+ uint32_t bucket_size = stats_get_latency_bucket_size();
+ struct display_table *stats = display_page_add_table(&display_page_latency_distr);
+ uint32_t bucket_unit_nsec = 1000000000 / (rte_get_tsc_hz() >> bucket_size);
+ if (state->toggle == 0) {
+ display_table_init(stats, "Statistics per second");
+ } 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, 11);
+ plog_info("Bucket unit is %d nsec, bucket size is %d, freq is %ld\n", bucket_unit_nsec, bucket_size, rte_get_tsc_hz());
+
+ uint32_t i = global_min_bucket_id, first = i, k = 0;
+ while ((i < LAT_BUCKET_COUNT) && (i <= global_max_bucket_id)) {
+ stats_latency_distr[k] = display_table_add_col(stats);
+ if (i < LAT_BUCKET_COUNT - group_size) {
+ snprintf(title, sizeof(title), "%d.%01d-%d.%01d", UNIT_INT(i), UNIT_FRACT(i), UNIT_INT(i + group_size), UNIT_FRACT(i + group_size));
+ } else {
+ snprintf(title, sizeof(title), "> %d.%01d", UNIT_INT(i), UNIT_FRACT(i));
+ }
+ display_column_init(stats_latency_distr[k++], title, 9);
+ i += group_size;
+ }
+ display_page_draw_frame(&display_page_latency_distr, n_tasks);
+
+ uint32_t count = 0;
+ lconf = NULL;
+ while (core_targ_next(&lconf, &targ, 0) == 0) {
+ if (strcmp(targ->task_init->mode_str, "lat") == 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_latency_distr_draw_stats(struct screen_state *state)
+{
+ const uint32_t n_latency = stats_get_n_latency();
+ uint64_t *bucket;
+ uint32_t bucket_id = 0, min_bucket_id = LAT_BUCKET_COUNT - 1, max_bucket_id = 0;
+ struct time_unit tu;
+
+ for (uint32_t count = 0; count < n_latency; ++count) {
+ if (state->toggle == 0)
+ tu = stats_latency_get(count)->max.time;
+ else
+ tu = stats_latency_tot_get(count)->max.time;
+ display_column_print(stats_max, count, "%9lu.%03lu", tu.sec * 1000000 + tu.nsec / 1000, tu.nsec % 1000);
+ }
+
+ // Calculate min_bucket_id: id of 1st bucket with data for any tasks
+ // Calculate max_bucket_id: id of last bucket with data for any tasks
+ for (uint i = 0; i < LAT_BUCKET_COUNT; ++i) {
+ for (uint32_t count = 0; count < n_latency; ++count) {
+ if (state->toggle == 0)
+ bucket = stats_latency_get_bucket(count);
+ else
+ bucket = stats_latency_get_tot_bucket(count);
+ if (bucket[i] != 0) {
+ min_bucket_id = i;
+ break;
+ }
+ }
+ if (min_bucket_id != LAT_BUCKET_COUNT - 1)
+ break;
+ }
+
+ for (uint i = LAT_BUCKET_COUNT; i > 0; i--) {
+ for (uint32_t count = 0; count < n_latency; ++count) {
+ if (state->toggle == 0)
+ bucket = stats_latency_get_bucket(count);
+ else
+ bucket = stats_latency_get_tot_bucket(count);
+ if (bucket[i - 1] != 0) {
+ max_bucket_id = i - 1;
+ break;
+ }
+ }
+ if (max_bucket_id)
+ break;
+ }
+
+ if (max_bucket_id - min_bucket_id + 1 < global_nb_buckets_displayed) {
+ max_bucket_id = global_nb_buckets_displayed + min_bucket_id - 1;
+ }
+
+ if ((global_min_bucket_id != min_bucket_id) || (global_max_bucket_id != max_bucket_id)) {
+ global_min_bucket_id = min_bucket_id;
+ global_max_bucket_id = max_bucket_id;
+ // Calculate how many buckets must be grouped together
+ if (max_bucket_id - min_bucket_id + 1 > global_nb_buckets_displayed)
+ group_size = ceil(1.0 * (max_bucket_id - min_bucket_id + 1) / global_nb_buckets_displayed);
+ else
+ group_size = 1;
+ display_latency_distr_draw_frame(state);
+ display_renew();
+ plog_info("min_bucket_id = %d, max_bucket_id = %d\n", min_bucket_id, max_bucket_id);
+ }
+
+ for (uint32_t count = 0; count < n_latency; ++count) {
+ if (state->toggle == 0)
+ bucket = stats_latency_get_bucket(count);
+ else
+ bucket = stats_latency_get_tot_bucket(count);
+ uint32_t i = min_bucket_id, k = 0;
+ uint64_t nb = 0;
+ while ((i < LAT_BUCKET_COUNT) && (i <= global_max_bucket_id)){
+ for (uint32_t j = 0; j <= group_size; j++)
+ if (i + j < LAT_BUCKET_COUNT)
+ nb += bucket[i+j];
+ display_column_print(stats_latency_distr[k++], count, "%9lu", nb);
+ if ((nb == 16) || (nb == 48))
+ for (uint32_t j = 0; j <= group_size; j++)
+ plog_info("id %d: %ld\n", i+j, bucket[i+j]);
+ nb = 0;
+ i += group_size;
+ }
+ }
+}
+
+static int display_latency_distr_get_height(void)
+{
+ return stats_get_n_latency();
+}
+
+static struct display_screen display_screen_latency_distr = {
+ .draw_frame = display_latency_distr_draw_frame,
+ .draw_stats = display_latency_distr_draw_stats,
+ .get_height = display_latency_distr_get_height,
+ .title = "latency_distr",
+};
+
+struct display_screen *display_latency_distr(void)
+{
+ return &display_screen_latency_distr;
+}
--- /dev/null
+/*
+// Copyright (c) 2019 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_LATENCY_DISTR_H
+#define DISPLAY_LATENCY_DISTR_H
+
+struct display_screen;
+struct display_screen *display_latency_distr(void);
+
+#endif /* DISPLAY_LATENCY_DISTR_H */
/*
-// Copyright (c) 2010-2017 Intel Corporation
+// Copyright (c) 2010-2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
#include "prox_shared.h"
#include "prox_port_cfg.h"
-#define DEFAULT_BUCKET_SIZE 10
+#define DEFAULT_BUCKET_SIZE 11
#define ACCURACY_BUFFER_SIZE (2 * ACCURACY_WINDOW)
struct lat_info {
uint32_t packet_id;
uint8_t generator_id;
uint64_t pkt_rx_time;
- uint64_t pkt_tx_time;
+ uint64_t pkt_tx_time; // Time written into packets by gen. Unit is TSC >> LATENCY_ACCURACY
uint64_t rx_time_err;
};
return rx_time - tx_time;
}
+uint32_t task_lat_get_latency_bucket_size(struct task_lat *task)
+{
+ return task->lat_test->bucket_size;
+}
+
struct lat_test *task_lat_get_latency_meassurement(struct task_lat *task)
{
if (task->use_lt == task->using_lt)
uint64_t bucket_id = (lat_tsc >> lat_test->bucket_size);
size_t bucket_count = sizeof(lat_test->buckets)/sizeof(lat_test->buckets[0]);
- bucket_id = bucket_id < bucket_count? bucket_id : bucket_count;
+ bucket_id = bucket_id < bucket_count? bucket_id : (bucket_count - 1);
lat_test->buckets[bucket_id]++;
}
task->lt[0].min_lat = -1;
task->lt[1].min_lat = -1;
- task->lt[0].bucket_size = targ->bucket_size - LATENCY_ACCURACY;
- task->lt[1].bucket_size = targ->bucket_size - LATENCY_ACCURACY;
+ task->lt[0].bucket_size = targ->bucket_size;
+ task->lt[1].bucket_size = targ->bucket_size;
if (task->unique_id_pos) {
task_lat_init_eld(task, socket_id);
task_lat_reset_eld(task);
/*
-// Copyright (c) 2010-2017 Intel Corporation
+// Copyright (c) 2010-2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// 8192 packets is equivalent to 550 micro-seconds at 10Gbps for 64 bytes packets
#define ACCURACY_WINDOW 8192
+#define LAT_BUCKET_COUNT 128
+
struct lat_test {
uint64_t tot_all_pkts;
uint64_t tot_pkts;
uint64_t tot_lat_error;
unsigned __int128 var_lat_error;
- uint64_t buckets[128];
+ uint64_t buckets[LAT_BUCKET_COUNT];
uint64_t bucket_size;
uint64_t lost_packets;
};
struct task_lat;
struct lat_test *task_lat_get_latency_meassurement(struct task_lat *task);
+uint32_t task_lat_get_latency_bucket_size(struct task_lat *task);
void task_lat_use_other_latency_meassurement(struct task_lat *task);
void task_lat_set_accuracy_limit(struct task_lat *task, uint32_t accuracy_limit_nsec);
/*
-// Copyright (c) 2010-2017 Intel Corporation
+// Copyright (c) 2010-2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
struct stats_latency_manager_entry {
struct task_lat *task;
+ uint32_t bucket_size;
uint8_t lcore_id;
uint8_t task_id;
struct lat_test lat_test;
struct stats_latency_manager {
uint16_t n_latency;
+ uint32_t bucket_size;
struct stats_latency_manager_entry entries[0]; /* copy of stats when running update stats. */
};
return slm->n_latency;
}
+int stats_get_latency_bucket_size(void)
+{
+ return slm->bucket_size;
+}
+
uint32_t stats_latency_get_core_id(uint32_t i)
{
return slm->entries[i].lcore_id;
return &slm->entries[i].stats;
}
+uint64_t *stats_latency_get_bucket(uint32_t i)
+{
+ return slm->entries[i].lat_test.buckets;
+}
+
+uint64_t *stats_latency_get_tot_bucket(uint32_t i)
+{
+ return slm->entries[i].tot_lat_test.buckets;
+}
+
struct stats_latency *stats_latency_tot_get(uint32_t i)
{
return &slm->entries[i].tot;
struct stats_latency_manager_entry *new_entry = &slm->entries[slm->n_latency];
new_entry->task = (struct task_lat *)targ->tbase;
+ new_entry->bucket_size = task_lat_get_latency_bucket_size(new_entry->task);
new_entry->lcore_id = lconf->id;
new_entry->task_id = targ->id;
new_entry->tot_lat_test.min_lat = -1;
+ if (slm->bucket_size == 0)
+ slm->bucket_size = new_entry->bucket_size;
+ else if (slm->bucket_size != new_entry->bucket_size)
+ plog_err("Latency bucket size does not support different bucket sizes per task - using bucket size from first task (%d)\n", slm->bucket_size);
slm->n_latency++;
}
/*
-// Copyright (c) 2010-2017 Intel Corporation
+// Copyright (c) 2010-2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
uint32_t stats_latency_get_core_id(uint32_t i);
uint32_t stats_latency_get_task_id(uint32_t i);
struct stats_latency *stats_latency_get(uint32_t i);
+uint64_t *stats_latency_get_bucket(uint32_t i);
+uint64_t *stats_latency_get_tot_bucket(uint32_t i);
struct stats_latency *stats_latency_find(uint32_t lcore_id, uint32_t task_id);
struct stats_latency *stats_latency_tot_get(uint32_t i);
void stats_latency_reset(void);
int stats_get_n_latency(void);
+int stats_get_latency_bucket_size(void);
#ifdef LATENCY_HISTOGRAM
void stats_core_lat_histogram(uint8_t lcore_id, uint8_t task_id, uint64_t **buckets);