mirror of
https://github.com/openvswitch/ovs
synced 2025-09-02 23:35:27 +00:00
dpif-netdev: Refactor cycle counting
Simplify the historically grown TSC cycle counting in PMD threads. Cycles are currently counted for the following purposes: 1. Measure PMD ustilization PMD utilization is defined as ratio of cycles spent in busy iterations (at least one packet received or sent) over the total number of cycles. This is already done in pmd_perf_start_iteration() and pmd_perf_end_iteration() based on a TSC timestamp saved in current iteration at start_iteration() and the actual TSC at end_iteration(). No dependency on intermediate cycle accounting. 2. Measure the processing load per RX queue This comprises cycles spend on polling and processing packets received from the rx queue and the cycles spent on delayed sending of these packets to tx queues (with time-based batching). The previous scheme using cycles_count_start(), cycles_count_intermediate() and cycles-count_end() originally introduced to simplify cycle counting and saving calls to rte_get_tsc_cycles() was rather obscuring things. Replace by a nestable cycle_timer with with start and stop functions to embrace a code segment to be timed. The timed code may contain arbitrary nested cycle_timers. The duration of nested timers is excluded from the outer timer. The caller must ensure that each call to cycle_timer_start() is followed by a call to cycle_timer_end(). Failure to do so will lead to assertion failure or a memory leak. The new cycle_timer is used to measure the processing cycles per rx queue. This is not yet strictly necessary but will be made use of in a subsequent commit. All cycle count functions and data are relocated to module dpif-netdev-perf. Signed-off-by: Jan Scheurich <jan.scheurich@ericsson.com> Acked-by: Ilya Maximets <i.maximets@samsung.com> Acked-by: Billy O'Mahony <billy.o.mahony@intel.com> Signed-off: Ian Stokes <ian.stokes@intel.com>
This commit is contained in:
committed by
Ian Stokes
parent
82a48ead4e
commit
a19896abe5
@@ -23,6 +23,11 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef DPDK_NETDEV
|
||||
#include <rte_config.h>
|
||||
#include <rte_cycles.h>
|
||||
#endif
|
||||
|
||||
#include "openvswitch/vlog.h"
|
||||
#include "ovs-atomic.h"
|
||||
#include "timeval.h"
|
||||
@@ -59,10 +64,6 @@ enum pmd_stat_type {
|
||||
* recirculation. */
|
||||
PMD_STAT_SENT_PKTS, /* Packets that have been sent. */
|
||||
PMD_STAT_SENT_BATCHES, /* Number of batches sent. */
|
||||
PMD_CYCLES_POLL_IDLE, /* Cycles spent unsuccessful polling. */
|
||||
PMD_CYCLES_POLL_BUSY, /* Cycles spent successfully polling and
|
||||
* processing polled packets. */
|
||||
PMD_CYCLES_OVERHEAD, /* Cycles spent for other tasks. */
|
||||
PMD_CYCLES_ITER_IDLE, /* Cycles spent in idle iterations. */
|
||||
PMD_CYCLES_ITER_BUSY, /* Cycles spent in busy iterations. */
|
||||
PMD_N_STATS
|
||||
@@ -85,11 +86,95 @@ struct pmd_counters {
|
||||
|
||||
struct pmd_perf_stats {
|
||||
/* Start of the current PMD iteration in TSC cycles.*/
|
||||
uint64_t start_it_tsc;
|
||||
/* Latest TSC time stamp taken in PMD. */
|
||||
uint64_t last_tsc;
|
||||
/* If non-NULL, outermost cycle timer currently running in PMD. */
|
||||
struct cycle_timer *cur_timer;
|
||||
/* Set of PMD counters with their zero offsets. */
|
||||
struct pmd_counters counters;
|
||||
};
|
||||
|
||||
/* Support for accurate timing of PMD execution on TSC clock cycle level.
|
||||
* These functions are intended to be invoked in the context of pmd threads. */
|
||||
|
||||
/* Read the TSC cycle register and cache it. Any function not requiring clock
|
||||
* cycle accuracy should read the cached value using cycles_counter_get() to
|
||||
* avoid the overhead of reading the TSC register. */
|
||||
|
||||
static inline uint64_t
|
||||
cycles_counter_update(struct pmd_perf_stats *s)
|
||||
{
|
||||
#ifdef DPDK_NETDEV
|
||||
return s->last_tsc = rte_get_tsc_cycles();
|
||||
#else
|
||||
return s->last_tsc = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
cycles_counter_get(struct pmd_perf_stats *s)
|
||||
{
|
||||
return s->last_tsc;
|
||||
}
|
||||
|
||||
/* A nestable timer for measuring execution time in TSC cycles.
|
||||
*
|
||||
* Usage:
|
||||
* struct cycle_timer timer;
|
||||
*
|
||||
* cycle_timer_start(pmd, &timer);
|
||||
* <Timed execution>
|
||||
* uint64_t cycles = cycle_timer_stop(pmd, &timer);
|
||||
*
|
||||
* The caller must guarantee that a call to cycle_timer_start() is always
|
||||
* paired with a call to cycle_stimer_stop().
|
||||
*
|
||||
* Is is possible to have nested cycles timers within the timed code. The
|
||||
* execution time measured by the nested timers is excluded from the time
|
||||
* measured by the embracing timer.
|
||||
*/
|
||||
|
||||
struct cycle_timer {
|
||||
uint64_t start;
|
||||
uint64_t suspended;
|
||||
struct cycle_timer *interrupted;
|
||||
};
|
||||
|
||||
static inline void
|
||||
cycle_timer_start(struct pmd_perf_stats *s,
|
||||
struct cycle_timer *timer)
|
||||
{
|
||||
struct cycle_timer *cur_timer = s->cur_timer;
|
||||
uint64_t now = cycles_counter_update(s);
|
||||
|
||||
if (cur_timer) {
|
||||
cur_timer->suspended = now;
|
||||
}
|
||||
timer->interrupted = cur_timer;
|
||||
timer->start = now;
|
||||
timer->suspended = 0;
|
||||
s->cur_timer = timer;
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
cycle_timer_stop(struct pmd_perf_stats *s,
|
||||
struct cycle_timer *timer)
|
||||
{
|
||||
/* Assert that this is the current cycle timer. */
|
||||
ovs_assert(s->cur_timer == timer);
|
||||
uint64_t now = cycles_counter_update(s);
|
||||
struct cycle_timer *intr_timer = timer->interrupted;
|
||||
|
||||
if (intr_timer) {
|
||||
/* Adjust the start offset by the suspended cycles. */
|
||||
intr_timer->start += now - intr_timer->suspended;
|
||||
}
|
||||
/* Restore suspended timer, if any. */
|
||||
s->cur_timer = intr_timer;
|
||||
return now - timer->start;
|
||||
}
|
||||
|
||||
void pmd_perf_stats_init(struct pmd_perf_stats *s);
|
||||
void pmd_perf_stats_clear(struct pmd_perf_stats *s);
|
||||
void pmd_perf_read_counters(struct pmd_perf_stats *s,
|
||||
@@ -115,16 +200,23 @@ pmd_perf_update_counter(struct pmd_perf_stats *s,
|
||||
}
|
||||
|
||||
static inline void
|
||||
pmd_perf_start_iteration(struct pmd_perf_stats *s, uint64_t now_tsc)
|
||||
pmd_perf_start_iteration(struct pmd_perf_stats *s)
|
||||
{
|
||||
s->last_tsc = now_tsc;
|
||||
if (OVS_LIKELY(s->last_tsc)) {
|
||||
/* We assume here that last_tsc was updated immediately prior at
|
||||
* the end of the previous iteration, or just before the first
|
||||
* iteration. */
|
||||
s->start_it_tsc = s->last_tsc;
|
||||
} else {
|
||||
/* In case last_tsc has never been set before. */
|
||||
s->start_it_tsc = cycles_counter_update(s);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
pmd_perf_end_iteration(struct pmd_perf_stats *s, uint64_t now_tsc,
|
||||
int rx_packets)
|
||||
pmd_perf_end_iteration(struct pmd_perf_stats *s, int rx_packets)
|
||||
{
|
||||
uint64_t cycles = now_tsc - s->last_tsc;
|
||||
uint64_t cycles = cycles_counter_update(s) - s->start_it_tsc;
|
||||
|
||||
if (rx_packets > 0) {
|
||||
pmd_perf_update_counter(s, PMD_CYCLES_ITER_BUSY, cycles);
|
||||
|
Reference in New Issue
Block a user