> > I have prepared a slightly more advanced version that allows arbitrary
> > nesting of cycles measurements where the nested measurements
> are excluded from the outer measurement: Here's the outline. I am including
> this in the next version of my umbrella series. This version
> isn't tested yet:
> >
> > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> > index 4761d3b..e487828 100644
> > --- a/lib/dpif-netdev.c
> > +++ b/lib/dpif-netdev.c
> > @@ -516,6 +516,8 @@ struct tx_port {
> > struct dp_netdev_rxq *output_pkts_rxqs[NETDEV_MAX_BURST];
> > };
> >
> > +struct cycle_timer;
> > +
> > /* A set of properties for the current processing loop that is not directly
> > * associated with the pmd thread itself, but with the packets being
> > * processed or the short-term system configuration (for example, time).
> > @@ -527,6 +529,7 @@ struct dp_netdev_pmd_thread_ctx {
> > uint64_t last_cycles;
> > /* RX queue from which last packet was received. */
> > struct dp_netdev_rxq *last_rxq;
> > + struct cycle_timer *cur_timer;
> > };
> >
> > /* PMD: Poll modes drivers. PMD accesses devices via polling to eliminate
> > @@ -632,6 +635,71 @@ struct dpif_netdev {
> > uint64_t last_port_seq;
> > };
> >
> > +/* 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 in the pmd context. Any
> > function
> > + * not requiring clock cycle accuracy should read the cached value from the
> > + * context. */
> > +static inline uint64_t
> > +cycles_counter(struct dp_netdev_pmd_thread *pmd)
> > +{
> > +#ifdef DPDK_NETDEV
> > + return pmd->ctx.last_cycles = rte_get_tsc_cycles();
> > +#else
> > + return pmd->ctx.last_cycles = 0;
> > +#endif
> > +}
> > +
> > +/* 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 *offset;
> > + struct cycle_timer *interrupted;
> > +};
> > +
> > +static void
> > +cycle_timer_start(struct dp_netdev_pmd_thread *pmd,
> > + struct cycle_timer *timer)
> > +{
> > + /* Suspend current timer, if any. */
> > + timer->interrupted = pmd->ctx.cur_timer;
> > + timer->offset = cycles_counter(pmd);
> > + pmd->ctx.cur_timer = timer;
> > +}
> > +
> > +static uint64_t
> > +cycle_timer_stop(struct dp_netdev_pmd_thread *pmd,
> > + struct cycle_timer *timer)
> > +{
> > + /* Assert that this is the current cycle timer. */
> > + ovs_assert(pmd->ctx.cur_timer == timer);
> > + uint64_t cycles = cycles_counter(pmd) - timer->offset;
> > + if (timer->interrupted) {
> > + /* Adjust the start offset by the used cycles. */
> > + timer->interrupted->offset += cycles;
>
> I think, this will not work for nesting more than 2 timers, because
> you will adjust only by the time of the one level deeper timer.
> You probably need one more field in the timer structure to accumulate
> sleep time while unwinding the timer's stack and not modify original
> offsets like:
>
> uint64_t cycles = cycles_counter(pmd) - timer->offset;
> if (timer->interrupted) {
> timer->interrupted->interrupted_time += cycles;
> }
> pmd->ctx.cur_timer = timer->interrupted;
> return cycles - timer->interrupted_time;
>
Good spot. I will fix this in my #2 patch.
Thanks, Jan
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev