> On Feb 25, 2015, at 8:43 AM, Daniele Di Proietto <diproiet...@vmware.com> 
> wrote:
> 
> 

(snip)

> 
> +enum pmd_info_type {
> +    PMD_INFO_SHOW_STATS,  /* show how cpu cycles are spent */
> +    PMD_INFO_CLEAR_STATS  /* set the cycles count to 0 */
> +};
> +
> +static void
> +dpif_netdev_pmd_info(struct unixctl_conn *conn, int argc, const char *argv[],
> +                     void *aux)
> +{
> +    struct ds reply = DS_EMPTY_INITIALIZER;
> +    struct dp_netdev_pmd_thread *pmd;
> +    struct dp_netdev *dp = NULL;
> +    enum pmd_info_type type = (enum pmd_info_type) aux;
> +
> +    ovs_mutex_lock(&dp_netdev_mutex);
> +
> +    if (argc == 2) {
> +        dp = shash_find_data(&dp_netdevs, argv[1]);
> +    } else if (shash_count(&dp_netdevs) == 1) {
> +        /* There's only one datapath */
> +        dp = shash_random_node(&dp_netdevs)->data;
> +    }
> +
> +    if (!dp) {
> +        ovs_mutex_unlock(&dp_netdev_mutex);
> +        unixctl_command_reply_error(conn,
> +                                    "please specify an existing datapath");
> +        return;
> +    }
> +
> +    CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
> +        struct dp_netdev_pmd_stats s;
> +        struct dp_netdev_pmd_cycles t;
> +        unsigned long long total_packets = 0;
> +        uint64_t total_cycles = 0;
> +        int i;
> +
> +        if (type == PMD_INFO_CLEAR_STATS) {
> +            /* We cannot write 'stats' and 'cycles' (because they're written
> +             * by other threads) and we shouldn't change 'stats' (because
> +             * ther're used to count datapath stats, which must not be 
> cleared
> +             * here).
> +             * Insted, we save the current values and subtract them from the

“instead"

> +             * values to be displayed in the future */
> +            pmd->cycles_zero = pmd->cycles;
> +            pmd->stats_zero = pmd->stats;

It seems to me that this access should be protected with a similar mechanism we 
use in cmaps, as any concurrent write by the pmd thread may result the “zero” 
versions to be inconsistent, a mixture of the old and new. Or is it the case 
that this does not matter? I guess that the cycles and stats need not be 
consistent with each other, though.

> +            continue;
> +        }
> +        t = pmd->cycles;
> +        s = pmd->stats;
> +
> +        for (i = 0; i < ARRAY_SIZE(t.n); i++) {
> +            t.n[i] -= pmd->cycles_zero.n[i];
> +            total_cycles += t.n[i];
> +        }
> +        for (i = 0; i < ARRAY_SIZE(s.n); i++) {
> +            s.n[i] -= pmd->stats_zero.n[i];
> +            if (i != DP_STAT_LOST) {
> +                total_packets += s.n[i];
> +            }
> +        }
> +

Similar concern up here.

> +        ds_put_cstr(&reply, (pmd->core_id == NON_PMD_CORE_ID)
> +                            ?"main thread":"pmd thread");
> +
> +        if(pmd->numa_id != OVS_NUMA_UNSPEC) {
> +            ds_put_format(&reply, " numa_id %d", pmd->numa_id);
> +        }
> +        if(pmd->core_id != OVS_CORE_UNSPEC) {
> +            ds_put_format(&reply, " core_id %d", pmd->core_id);
> +        }
> +        ds_put_cstr(&reply, ":\n");
> +
> +        ds_put_format(&reply,
> +                      "\temc hits:%llu\n"
> +                      "\tmasked hits:%llu\n"
> +                      "\tmiss:%llu\n"
> +                      "\tlost:%llu\n",
> +                      s.n[DP_STAT_EXACT_HIT],
> +                      s.n[DP_STAT_MASKED_HIT],
> +                      s.n[DP_STAT_MISS],
> +                      s.n[DP_STAT_LOST]);
> +
> +        if (total_cycles == 0) {
> +            ds_put_cstr(&reply, "\tcycles counters not supported\n");
> +            continue;
> +        }
> +
> +        ds_put_format(&reply,
> +                      "\tpolling cycles:%"PRIu64" (%.02f%%)\n"
> +                      "\tprocessing cycles:%"PRIu64" (%.02f%%)\n"
> +                      "\tother cycles:%"PRIu64" (%.02f%%)\n",
> +                      t.n[PMD_CYCLES_POLLING],
> +                      t.n[PMD_CYCLES_POLLING]/(double)total_cycles*100,
> +                      t.n[PMD_CYCLES_PROCESSING],
> +                      t.n[PMD_CYCLES_PROCESSING]/(double)total_cycles*100,
> +                      t.n[PMD_CYCLES_OTHER],
> +                      t.n[PMD_CYCLES_OTHER]/(double)total_cycles*100);
> +
> +        if (total_packets == 0) {
> +            ds_put_cstr(&reply, "\tno packets processed yet\n");
> +            continue;
> +        }
> +        ds_put_format(&reply,
> +                      "\tavg cycles per packet: %.02f (%"PRIu64"/%llu)\n",
> +                      total_cycles/(double)total_packets,
> +                      total_cycles, total_packets);
> +
> +        ds_put_format(&reply,
> +                      "\tavg processing cycles per packet: %.02f 
> (%"PRIu64"/%llu)\n",
> +                      t.n[PMD_CYCLES_PROCESSING]/(double)total_packets,
> +                      t.n[PMD_CYCLES_PROCESSING], total_packets);
> +    }
> +
> +    ovs_mutex_unlock(&dp_netdev_mutex);
> +
> +    unixctl_command_reply(conn, ds_cstr(&reply));
> +    ds_destroy(&reply);
> +}
> +
> +static int
> +dpif_netdev_init(void)
> +{
> +    unixctl_command_register("dpif-netdev/pmd-stats-show", "[dp]",
> +                             0, 1, dpif_netdev_pmd_info,
> +                             (void *)PMD_INFO_SHOW_STATS);
> +    unixctl_command_register("dpif-netdev/pmd-stats-clear", "[dp]",
> +                             0, 1, dpif_netdev_pmd_info,
> +                             (void *)PMD_INFO_CLEAR_STATS);
> +    return 0;
> +}
> +
> static int
> dpif_netdev_enumerate(struct sset *all_dps,
>                       const struct dpif_class *dpif_class)
> @@ -2260,7 +2399,7 @@ pmd_cycles_counter_diff(struct dp_netdev_pmd_thread 
> *pmd)
> {
>     uint64_t old_cycles = pmd->last_cycles,
> #ifdef DPDK_NETDEV
> -             new_cycles = rte_get_tsc_cycles();
> +             new_cycles = rte_get_timer_cycles();
> #else
>              new_cycles = 0;
> #endif
> @@ -3332,7 +3471,7 @@ dp_netdev_execute_actions(struct dp_netdev_pmd_thread 
> *pmd,
> 
> const struct dpif_class dpif_netdev_class = {
>     "netdev",
> -    NULL,                       /* init */
> +    dpif_netdev_init,
>     dpif_netdev_enumerate,
>     dpif_netdev_port_open_type,
>     dpif_netdev_open,
> diff --git a/vswitchd/ovs-vswitchd.8.in b/vswitchd/ovs-vswitchd.8.in
> index 7f165ea..26b257b 100644
> --- a/vswitchd/ovs-vswitchd.8.in
> +++ b/vswitchd/ovs-vswitchd.8.in
> @@ -239,6 +239,24 @@ type).
> ..
> .so lib/dpctl.man
> .
> +.SS "DPIF-NETDEV COMMANDS"
> +These commands are used to expose internal information (mostly statistics)
> +about the ``dpif-netdev'' userspace datapath. If there is only one datapath
> +(as is often the case, unless \fBdpctl/\fR commands are used), the \fIdp\fR
> +argument can be omitted.
> +.IP "\fBdpif-netdev/pmd-stats-show\fR [\fIdp\fR]"
> +Shows performance statistics for each pmd thread of the datapath \fIdp\fR.
> +The special thread ``main'' sums up the statistics of every other thread.
> +The sum of ``emc hits'', ``masked hits'' and ``miss'' is the number of
> +packets received by the datapath. Cycles are counted using the TSC or similar
> +facilities (when available on the platform). To reset these counters use
> +\fBdpif-netdev/pmd-stats-clear\fR. The duration of one cycle depends on the
> +measuring infrastructure.
> +.IP "\fBdpif-netdev/pmd-stats-clear\fR [\fIdp\fR]"
> +Resets to zero the per pmd thread performance numbers shown by the
> +\fBdpif-netdev/pmd-stats-show\fR command. It will NOT reset datapath or
> +bridge statistics, only the values shown by the above command.
> +.
> .so ofproto/ofproto-dpif-unixctl.man
> .so ofproto/ofproto-unixctl.man
> .so lib/vlog-unixctl.man
> -- 
> 2.1.4
> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to