The histogram type is currently used to measure dpif-netdev performance statistics. Simplify access by putting it into a standalone module.
Signed-off-by: Gaetan Rivet <[email protected]> --- lib/automake.mk | 2 + lib/dpif-netdev-perf.c | 73 +------------------------------- lib/dpif-netdev-perf.h | 35 +--------------- lib/histogram.c | 94 ++++++++++++++++++++++++++++++++++++++++++ lib/histogram.h | 64 ++++++++++++++++++++++++++++ tests/test-histogram.c | 16 +++---- 6 files changed, 172 insertions(+), 112 deletions(-) create mode 100644 lib/histogram.c create mode 100644 lib/histogram.h diff --git a/lib/automake.mk b/lib/automake.mk index 78d6e65164..ecc8a64e20 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -148,6 +148,8 @@ lib_libopenvswitch_la_SOURCES = \ lib/dpif.h \ lib/heap.c \ lib/heap.h \ + lib/histogram.c \ + lib/histogram.h \ lib/dynamic-string.c \ lib/entropy.c \ lib/entropy.h \ diff --git a/lib/dpif-netdev-perf.c b/lib/dpif-netdev-perf.c index 0d029ff00e..17e3195b17 100644 --- a/lib/dpif-netdev-perf.c +++ b/lib/dpif-netdev-perf.c @@ -19,6 +19,7 @@ #include "dpdk.h" #include "dpif-netdev-perf.h" +#include "histogram.h" #include "openvswitch/dynamic-string.h" #include "openvswitch/vlog.h" #include "ovs-numa.h" @@ -100,76 +101,6 @@ pmd_perf_estimate_tsc_frequency(void) VLOG_INFO("Estimated TSC frequency: %"PRIu64" KHz", tsc_hz / 1000); } -/* Histogram functions. */ - -void -histogram_walls_set_lin(struct histogram *hist, uint32_t min, uint32_t max) -{ - uint32_t i, inc; - - ovs_assert(min < max); - inc = (max - min) / (NUM_BINS - 2); - for (i = 0; i < NUM_BINS-1; i++) { - hist->wall[i] = min + (i * inc); - } - if (max != UINT32_MAX) { - hist->wall[NUM_BINS - 2] = max; - } - hist->wall[NUM_BINS-1] = UINT32_MAX; -} - -void -histogram_walls_set_log(struct histogram *hist, uint32_t min, uint32_t max) -{ - uint32_t i, start, bins, wall; - double log_min, log_max; - - ovs_assert(min < max); - if (min > 0) { - log_min = log(min); - log_max = log(max); - start = 0; - bins = NUM_BINS - 1; - } else { - hist->wall[0] = 0; - log_min = log(1); - log_max = log(max); - start = 1; - bins = NUM_BINS - 2; - } - wall = start; - for (i = 0; i < bins; i++) { - /* Make sure each wall is monotonically increasing. */ - wall = MAX(wall, exp(log_min + (i * (log_max - log_min)) / (bins-1))); - hist->wall[start + i] = wall++; - } - if (hist->wall[NUM_BINS - 2] < max && max != UINT32_MAX) { - hist->wall[NUM_BINS-2] = max; - } - hist->wall[NUM_BINS-1] = UINT32_MAX; -} - -uint64_t -histogram_samples(const struct histogram *hist) -{ - uint64_t samples = 0; - - for (int i = 0; i < NUM_BINS; i++) { - samples += hist->bin[i]; - } - return samples; -} - -static void -histogram_clear(struct histogram *hist) -{ - int i; - - for (i = 0; i < NUM_BINS; i++) { - hist->bin[i] = 0; - } -} - static void history_init(struct history *h) { @@ -317,7 +248,7 @@ pmd_perf_format_histograms(struct ds *str, struct pmd_perf_stats *s) " %-21s %-21s %-21s %-21s %-21s %-21s %-21s\n", "cycles/it", "packets/it", "cycles/pkt", "pkts/batch", "max vhost qlen", "upcalls/it", "cycles/upcall"); - for (i = 0; i < NUM_BINS-1; i++) { + for (i = 0; i < HISTOGRAM_N_BINS - 1; i++) { ds_put_format(str, " %-9d %-11"PRIu64" %-9d %-11"PRIu64" %-9d %-11"PRIu64 " %-9d %-11"PRIu64" %-9d %-11"PRIu64" %-9d %-11"PRIu64 diff --git a/lib/dpif-netdev-perf.h b/lib/dpif-netdev-perf.h index 9bfc474293..89978b219e 100644 --- a/lib/dpif-netdev-perf.h +++ b/lib/dpif-netdev-perf.h @@ -29,6 +29,7 @@ #include <rte_cycles.h> #endif +#include "histogram.h" #include "openvswitch/vlog.h" #include "ovs-atomic.h" #include "timeval.h" @@ -41,7 +42,7 @@ extern "C" { /* This module encapsulates data structures and functions to maintain basic PMD * performance metrics such as packet counters, execution cycles as well as - * histograms and time series recording for more detailed PMD metrics. + * time series recording for more detailed PMD metrics. * * It provides a clean API for dpif-netdev to initialize, update and read and * reset these metrics. @@ -97,19 +98,6 @@ struct pmd_counters { uint64_t zero[PMD_N_STATS]; /* Value at last _clear(). */ }; -/* Data structure to collect statistical distribution of an integer measurement - * type in form of a histogram. The wall[] array contains the inclusive - * upper boundaries of the bins, while the bin[] array contains the actual - * counters per bin. The histogram walls are typically set automatically - * using the functions provided below.*/ - -#define NUM_BINS 32 /* Number of histogram bins. */ - -struct histogram { - uint32_t wall[NUM_BINS]; - uint64_t bin[NUM_BINS]; -}; - /* Data structure to record details PMD execution metrics per iteration for * a history period of up to HISTORY_LEN iterations in circular buffer. * Also used to record up to HISTORY_LEN millisecond averages/totals of these @@ -333,25 +321,6 @@ pmd_perf_update_counter(struct pmd_perf_stats *s, /* Functions to manipulate a sample history. */ -static inline void -histogram_add_sample(struct histogram *hist, uint32_t val) -{ - /* TODO: Can do better with binary search? */ - for (int i = 0; i < NUM_BINS-1; i++) { - if (val <= hist->wall[i]) { - hist->bin[i]++; - return; - } - } - hist->bin[NUM_BINS-1]++; -} - -void histogram_walls_set_lin(struct histogram *hist, - uint32_t min, uint32_t max); -void histogram_walls_set_log(struct histogram *hist, - uint32_t min, uint32_t max); -uint64_t histogram_samples(const struct histogram *hist); - /* This function is used to advance the given history index by positive * offset in the circular history buffer. */ static inline uint32_t diff --git a/lib/histogram.c b/lib/histogram.c new file mode 100644 index 0000000000..85bb3661c3 --- /dev/null +++ b/lib/histogram.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2017 Ericsson AB. + * Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * 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 <config.h> + +#include <stdint.h> +#include <math.h> + +#include "histogram.h" +#include "openvswitch/util.h" +#include "util.h" + +void +histogram_walls_set_lin(struct histogram *hist, uint32_t min, uint32_t max) +{ + uint32_t i, inc; + + ovs_assert(min < max); + inc = (max - min) / (HISTOGRAM_N_BINS - 2); + for (i = 0; i < HISTOGRAM_N_BINS - 1; i++) { + hist->wall[i] = min + (i * inc); + } + if (max != UINT32_MAX) { + hist->wall[HISTOGRAM_N_BINS - 2] = max; + } + hist->wall[HISTOGRAM_N_BINS - 1] = UINT32_MAX; +} + +void +histogram_walls_set_log(struct histogram *hist, uint32_t min, uint32_t max) +{ + uint32_t i, start, bins, wall; + double log_min, log_max; + + ovs_assert(min < max); + if (min > 0) { + log_min = log(min); + log_max = log(max); + start = 0; + bins = HISTOGRAM_N_BINS - 1; + } else { + hist->wall[0] = 0; + log_min = log(1); + log_max = log(max); + start = 1; + bins = HISTOGRAM_N_BINS - 2; + } + wall = start; + for (i = 0; i < bins; i++) { + /* Make sure each wall is monotonically increasing. */ + wall = MAX(wall, + exp(log_min + (i * (log_max - log_min)) / (bins - 1))); + hist->wall[start + i] = wall++; + } + if (hist->wall[HISTOGRAM_N_BINS - 2] < max && max != UINT32_MAX) { + hist->wall[HISTOGRAM_N_BINS - 2] = max; + } + hist->wall[HISTOGRAM_N_BINS - 1] = UINT32_MAX; +} + +uint64_t +histogram_samples(const struct histogram *hist) +{ + uint64_t samples = 0; + + for (int i = 0; i < HISTOGRAM_N_BINS; i++) { + samples += hist->bin[i]; + } + return samples; +} + +void +histogram_clear(struct histogram *hist) +{ + int i; + + for (i = 0; i < HISTOGRAM_N_BINS; i++) { + hist->bin[i] = 0; + } +} diff --git a/lib/histogram.h b/lib/histogram.h new file mode 100644 index 0000000000..8c2a9ea5c7 --- /dev/null +++ b/lib/histogram.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 Ericsson AB. + * Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * 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 HISTOGRAM_H +#define HISTOGRAM_H 1 + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Data structure to collect statistical distribution of an integer measurement + * type in form of a histogram. The wall[] array contains the inclusive + * upper boundaries of the bins, while the bin[] array contains the actual + * counters per bin. The histogram walls are typically set automatically + * using the functions provided below.*/ + +#define HISTOGRAM_N_BINS 32 /* Number of histogram bins. */ + +struct histogram { + uint32_t wall[HISTOGRAM_N_BINS]; + uint64_t bin[HISTOGRAM_N_BINS]; +}; + +static inline void +histogram_add_sample(struct histogram *hist, uint32_t val) +{ + /* TODO: Can do better with binary search? */ + for (int i = 0; i < HISTOGRAM_N_BINS - 1; i++) { + if (val <= hist->wall[i]) { + hist->bin[i]++; + return; + } + } + hist->bin[HISTOGRAM_N_BINS - 1]++; +} + +void histogram_walls_set_lin(struct histogram *hist, + uint32_t min, uint32_t max); +void histogram_walls_set_log(struct histogram *hist, + uint32_t min, uint32_t max); +uint64_t histogram_samples(const struct histogram *hist); +void histogram_clear(struct histogram *hist); + +#ifdef __cplusplus +} +#endif + +#endif /* HISTOGRAM_H */ diff --git a/tests/test-histogram.c b/tests/test-histogram.c index d43f8d7012..c22ca44b84 100644 --- a/tests/test-histogram.c +++ b/tests/test-histogram.c @@ -18,7 +18,7 @@ #include <stdint.h> -#include "dpif-netdev-perf.h" +#include "histogram.h" #include "openvswitch/util.h" #include "ovstest.h" #include "random.h" @@ -59,7 +59,7 @@ test_histogram_check(struct histogram *hist, }; bool min_found = false, max_found = false; - for (size_t i = 0; i < NUM_BINS; i++) { + for (size_t i = 0; i < HISTOGRAM_N_BINS; i++) { if (ops[EQ](hist->wall[i], min)) { min_found = true; } @@ -69,7 +69,7 @@ test_histogram_check(struct histogram *hist, } ovs_assert(min_found); ovs_assert(max_found); - for (size_t i = 0; i < NUM_BINS - 1; i++) { + for (size_t i = 0; i < HISTOGRAM_N_BINS - 1; i++) { if (ops[LT](hist->wall[i], min)) { ovs_abort(0, "A bucket is under the requested minimum. " "For [%"PRIu32",%"PRIu32"]: " @@ -126,14 +126,14 @@ test_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) { LIN | LOG, 1, UINT32_MAX }, { LIN | LOG, 0, UINT32_MAX - 1 }, { LIN | LOG, 1, UINT32_MAX - 1 }, - { LIN , UINT32_MAX - (NUM_BINS - 1), UINT32_MAX }, - { LIN , UINT32_MAX - (NUM_BINS - 1), UINT32_MAX - 1 }, + { LIN , UINT32_MAX - (HISTOGRAM_N_BINS - 1), UINT32_MAX }, + { LIN , UINT32_MAX - (HISTOGRAM_N_BINS - 1), UINT32_MAX - 1 }, /* Congruent case with inc=1. */ - { LIN , 5, 5 + NUM_BINS }, + { LIN , 5, 5 + HISTOGRAM_N_BINS }, /* Non-congruent case with inc<1. */ - { LIN , 5, 5 + (NUM_BINS - 1) }, + { LIN , 5, 5 + (HISTOGRAM_N_BINS - 1) }, /* Non-congruent case with inc<1. */ - { LIN , 5, 5 + (NUM_BINS - 2) }, + { LIN , 5, 5 + (HISTOGRAM_N_BINS - 2) }, { LIN | LOG, 0x88888888, 0x99999999 }, { LIN | LOG, 2203470768, 2441348688 }, { LIN | LOG, 1732474832, 2432533624 }, -- 2.34.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
