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

Reply via email to