Hello Michal,

Most systems that run Open vSwitch can also run hsflowd to export a wide
range of standard host performance statistics:
http://sflow.org/sflow_host.txt
http://sflow.org/sflow_host_ip.txt

That's a large superset of the "struct processor" export you are filling in
here.

This "struct processor" was originally aimed at providing some visibility
into the CPU/memory status of closed-platform physical switches,  but it
has really been superseded in places where sflow_host is available.   Newer
physical switches tend to run Linux,  and usually run hsflowd (Cumulus
Linux,  Dell OS10, ...).

The hsflowd daemon integrates with OVS  (just add "ovs{}" to
/etc/hsflowd.conf and it will configure OVS sFlow):
http://sflow.net/host-sflow-linux-config.php

So I'm wondering if this patch is worthwhile?
But perhaps I missed something.  Is there a use-case where it's unlikely
that hsflowd can be layered on top?

Neil



------
Neil McKee
InMon Corp.
http://www.inmon.com

On Mon, Nov 21, 2016 at 5:34 AM, mweglicx <michalx.wegli...@intel.com>
wrote:

> Exports PROCESSOR structure with sFLOW counters.
> Refactors vswitchd/system-stats.* functionality to support
> complex system counters which are enabled on request, and basic stats
> enabled by default.
> Adjust unit tests with very basic sanity check for PROCESSOR counters.
>
> Signed-off-by: Michal Weglicki <michalx.wegli...@intel.com>
> ---
>  lib/sflow.h                  |  12 ++
>  lib/sflow_receiver.c         |   8 ++
>  ofproto/ofproto-dpif-sflow.c |  17 ++-
>  tests/ofproto-dpif.at        |  28 +++-
>  tests/test-sflow.c           |  15 +++
>  vswitchd/bridge.c            |   1 +
>  vswitchd/system-stats.c      | 308 ++++++++++++++++++++++++++++++
> ++++++-------
>  vswitchd/system-stats.h      |  16 +++
>  8 files changed, 352 insertions(+), 53 deletions(-)
>
> diff --git a/lib/sflow.h b/lib/sflow.h
> index 95bedd9..53ba4e0 100644
> --- a/lib/sflow.h
> +++ b/lib/sflow.h
> @@ -502,6 +502,16 @@ typedef struct _SFLVlan_counters {
>      u_int32_t discards;
>  } SFLVlan_counters;
>
> +#define SFL_CTR_PROCESSOR_XDR_SIZE 28
> +
> +typedef struct _SFLProcessor_counters {
> +    int32_t cpu_util_5s;      /* 5 second average CPU utilization */
> +    int32_t cpu_util_1m;      /* 1 minute average CPU utilization */
> +    int32_t cpu_util_5m;      /* 5 minute average CPU utilization */
> +    u_int64_t total_memory;     /* total memory (in bytes) */
> +    u_int64_t free_memory;      /* free memory (in bytes) */
> +} SFLProcessor_counters;
> +
>  /* OpenFlow port */
>  typedef struct {
>      u_int64_t datapath_id;
> @@ -587,6 +597,7 @@ enum SFLCounters_type_tag {
>      SFLCOUNTERS_VG           = 4,
>      SFLCOUNTERS_VLAN         = 5,
>      SFLCOUNTERS_LACP         = 7,
> +    SFLCOUNTERS_PROCESSOR    = 1001,
>      SFLCOUNTERS_OPENFLOWPORT = 1004,
>      SFLCOUNTERS_PORTNAME     = 1005,
>      SFLCOUNTERS_APP_RESOURCES = 2203,
> @@ -604,6 +615,7 @@ typedef union _SFLCounters_type {
>      SFLPortName portName;
>      SFLAPPResources_counters appResources;
>      SFLOVSDP_counters ovsdp;
> +    SFLProcessor_counters processor;
>  } SFLCounters_type;
>
>  typedef struct _SFLCounters_sample_element {
> diff --git a/lib/sflow_receiver.c b/lib/sflow_receiver.c
> index cde1359..23468f1 100644
> --- a/lib/sflow_receiver.c
> +++ b/lib/sflow_receiver.c
> @@ -655,6 +655,7 @@ static int computeCountersSampleSize(SFLReceiver
> *receiver, SFL_COUNTERS_SAMPLE_
>         case SFLCOUNTERS_PORTNAME: elemSiz = stringEncodingLength(&elem->
> counterBlock.portName.portName); break;
>         case SFLCOUNTERS_APP_RESOURCES: elemSiz =
> SFL_CTR_APP_RESOURCES_XDR_SIZE; break;
>         case SFLCOUNTERS_OVSDP: elemSiz = SFL_CTR_OVSDP_XDR_SIZE; break;
> +    case SFLCOUNTERS_PROCESSOR: elemSiz = SFL_CTR_PROCESSOR_XDR_SIZE;
> break;
>         default:
>             sflError(receiver, "unexpected counters_tag");
>             return -1;
> @@ -795,6 +796,13 @@ int sfl_receiver_writeCountersSample(SFLReceiver
> *receiver, SFL_COUNTERS_SAMPLE_
>                 putNet32(receiver, elem->counterBlock.ovsdp.n_flows);
>                 putNet32(receiver, elem->counterBlock.ovsdp.n_masks);
>                 break;
> +           case SFLCOUNTERS_PROCESSOR:
> +               putNet32(receiver, elem->counterBlock.processor.
> cpu_util_5s);
> +               putNet32(receiver, elem->counterBlock.processor.
> cpu_util_1m);
> +               putNet32(receiver, elem->counterBlock.processor.
> cpu_util_5m);
> +               putNet64(receiver, elem->counterBlock.processor.
> total_memory);
> +               putNet64(receiver, elem->counterBlock.processor.
> free_memory);
> +               break;
>             default:
>                 sflError(receiver, "unexpected counters_tag");
>                 return -1;
> diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
> index 37992b4..84bbe18 100644
> --- a/ofproto/ofproto-dpif-sflow.c
> +++ b/ofproto/ofproto-dpif-sflow.c
> @@ -43,6 +43,7 @@
>  #include "lib/unaligned.h"
>  #include "ofproto-provider.h"
>  #include "lacp.h"
> +#include "vswitchd/system-stats.h"
>
>  VLOG_DEFINE_THIS_MODULE(sflow);
>
> @@ -297,7 +298,7 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
>      OVS_REQUIRES(mutex)
>  {
>      struct dpif_sflow *ds = ds_;
> -    SFLCounters_sample_element elem, lacp_elem, of_elem, name_elem;
> +    SFLCounters_sample_element elem, lacp_elem, of_elem, name_elem,
> proc_elem;
>      enum netdev_features current;
>      struct dpif_sflow_port *dsp;
>      SFLIf_counters *counters;
> @@ -305,6 +306,7 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
>      enum netdev_flags flags;
>      struct lacp_slave_stats lacp_stats;
>      const char *ifName;
> +    struct system_stats_basic *stats_basic;
>
>      dsp = dpif_sflow_find_port(ds, u32_to_odp(poller->bridgePort));
>      if (!dsp) {
> @@ -407,6 +409,19 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
>        (OVS_FORCE uint32_t)dsp->ofport->ofp_port;
>      SFLADD_ELEMENT(cs, &of_elem);
>
> +    memset(&proc_elem, 0, sizeof proc_elem);
> +    proc_elem.tag = SFLCOUNTERS_PROCESSOR;
> +    stats_basic = system_stats_run_basic();
> +    if (stats_basic) {
> +        proc_elem.counterBlock.processor.cpu_util_5s =
> stats_basic->cpu_util_5s;
> +        proc_elem.counterBlock.processor.cpu_util_1m =
> stats_basic->cpu_util_1m;
> +        proc_elem.counterBlock.processor.cpu_util_5m =
> stats_basic->cpu_util_5m;
> +        proc_elem.counterBlock.processor.total_memory =
> stats_basic->total_memory;
> +        proc_elem.counterBlock.processor.free_memory =
> stats_basic->free_memory;
> +        SFLADD_ELEMENT(cs, &proc_elem);
> +        free(stats_basic);
> +    }
> +
>      sfl_poller_writeCountersSample(poller, cs);
>  }
>
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index ec7bd60..c8ee532 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -5430,8 +5430,8 @@ HEADER
>         hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-67-00-00-00-
> 00-00-0A-80-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-01-
> FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-02
>  ])
>
> -  AT_CHECK_UNQUOTED([[sort sflow.log | $EGREP 
> 'IFCOUNTERS|ERROR|PORTNAME|OPENFLOWPORT'
> | head -18 | sed 's/ /\
> -       /g']], [0], [dnl
> +  AT_CHECK_UNQUOTED([[sort sflow.log | $EGREP
> 'PROCESSORCOUNTERS|IFCOUNTERS|ERROR|PORTNAME|OPENFLOWPORT' | head -24 |
> sed 's/ /\
> +       /g' | sed '/total_memory/d' | sed '/free_memory/d']], [0], [dnl
>  IFCOUNTERS
>         dgramSeqNo=1
>         ds=127.0.0.1>0:1002
> @@ -5600,6 +5600,30 @@ PORTNAME
>         portName=p2
>  PORTNAME
>         portName=p2
> +PROCESSORCOUNTERS
> +       5s_cpu=4294967295
> +       1m_cpu=4294967295
> +       5m_cpu=4294967295
> +PROCESSORCOUNTERS
> +       5s_cpu=4294967295
> +       1m_cpu=4294967295
> +       5m_cpu=4294967295
> +PROCESSORCOUNTERS
> +       5s_cpu=4294967295
> +       1m_cpu=4294967295
> +       5m_cpu=4294967295
> +PROCESSORCOUNTERS
> +       5s_cpu=4294967295
> +       1m_cpu=4294967295
> +       5m_cpu=4294967295
> +PROCESSORCOUNTERS
> +       5s_cpu=4294967295
> +       1m_cpu=4294967295
> +       5m_cpu=4294967295
> +PROCESSORCOUNTERS
> +       5s_cpu=4294967295
> +       1m_cpu=4294967295
> +       5m_cpu=4294967295
>  ])])
>
>  AT_SETUP([ofproto-dpif - basic truncate action])
> diff --git a/tests/test-sflow.c b/tests/test-sflow.c
> index 60870df..8d41531 100644
> --- a/tests/test-sflow.c
> +++ b/tests/test-sflow.c
> @@ -55,6 +55,7 @@ static unixctl_cb_func test_sflow_exit;
>  /* Structure element tag numbers. */
>  #define SFLOW_TAG_CTR_IFCOUNTERS 1
>  #define SFLOW_TAG_CTR_LACPCOUNTERS 7
> +#define SFLOW_TAG_CTR_PROCESSORCOUNTERS 1001
>  #define SFLOW_TAG_CTR_OPENFLOWPORT 1004
>  #define SFLOW_TAG_CTR_PORTNAME 1005
>  #define SFLOW_TAG_PKT_HEADER 1
> @@ -116,6 +117,7 @@ struct sflow_xdr {
>         uint32_t TUNNEL_VNI_IN;
>         uint32_t MPLS;
>          uint32_t IFCOUNTERS;
> +        uint32_t PROCESSORCOUNTERS;
>         uint32_t LACPCOUNTERS;
>         uint32_t OPENFLOWPORT;
>         uint32_t PORTNAME;
> @@ -297,6 +299,16 @@ process_counter_sample(struct sflow_xdr *x)
>         printf(" portName=%s", portName);
>         printf("\n");
>      }
> +    if (x->offset.PROCESSORCOUNTERS) {
> +        sflowxdr_setc(x, x->offset.PROCESSORCOUNTERS);
> +        printf("PROCESSORCOUNTERS");
> +        printf(" 5s_cpu=%"PRIu32, sflowxdr_next(x));
> +        printf(" 1m_cpu=%"PRIu32, sflowxdr_next(x));
> +        printf(" 5m_cpu=%"PRIu32, sflowxdr_next(x));
> +        printf(" total_memory=%"PRIu64, sflowxdr_next_int64(x));
> +        printf(" free_memory=%"PRIu64, sflowxdr_next_int64(x));
> +        printf("\n");
> +    }
>  }
>
>  static char
> @@ -513,6 +525,9 @@ process_datagram(struct sflow_xdr *x)
>                  case SFLOW_TAG_CTR_IFCOUNTERS:
>                      sflowxdr_mark_unique(x, &x->offset.IFCOUNTERS);
>                      break;
> +                case SFLOW_TAG_CTR_PROCESSORCOUNTERS:
> +                    sflowxdr_mark_unique(x, &x->offset.PROCESSORCOUNTERS);
> +                    break;
>                  case SFLOW_TAG_CTR_LACPCOUNTERS:
>                      sflowxdr_mark_unique(x, &x->offset.LACPCOUNTERS);
>                      break;
> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
> index d78c48e..50934e6 100644
> --- a/vswitchd/bridge.c
> +++ b/vswitchd/bridge.c
> @@ -645,6 +645,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch
> *ovs_cfg)
>          shash_destroy(&br->wanted_ports);
>      }
>
> +    system_stats_init();
>      reconfigure_system_stats(ovs_cfg);
>
>      /* Complete the configuration. */
> diff --git a/vswitchd/system-stats.c b/vswitchd/system-stats.c
> index 49e5419..e779b0c 100644
> --- a/vswitchd/system-stats.c
> +++ b/vswitchd/system-stats.c
> @@ -23,7 +23,6 @@
>  #if HAVE_MNTENT_H
>  #include <mntent.h>
>  #endif
> -#include <stdint.h>
>  #include <stdio.h>
>  #include <stdlib.h>
>  #if HAVE_SYS_STATVFS_H
> @@ -58,6 +57,116 @@ VLOG_DEFINE_THIS_MODULE(system_stats);
>  #define LINUX 0
>  #endif
>
> +struct system_stats_cpu_snapshot {
> +    long double proc_stats[4];
> +    int64_t time_stamp_ms;
> +    uint64_t period_ms;
> +};
> +
> +#define SYSTEM_STATS_INTERVAL (5 * 1000) /* In milliseconds. */
> +#define CPU_SNAPSHOTS 3
> +#define CPU_COUNTERS 4
> +#define SYSTEM_STATS_CPU_5S_ID 0
> +#define SYSTEM_STATS_CPU_1M_ID 1
> +#define SYSTEM_STATS_CPU_5M_ID 2
> +
> +static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
> +static struct ovs_mutex mutex_basic = OVS_MUTEX_INITIALIZER;
> +static struct latch latch OVS_GUARDED_BY(mutex);
> +static bool enabled_complex;
> +bool stats_init = false;
> +static bool started OVS_GUARDED_BY(mutex);
> +static struct smap *system_stats OVS_GUARDED_BY(mutex);
> +struct system_stats_basic stats_basic OVS_GUARDED_BY(mutex_basic);
> +static struct system_stats_cpu_snapshot cpu_snapshots[CPU_SNAPSHOTS];
> +
> +OVS_NO_RETURN static void *system_stats_thread_func(void *);
> +static void discard_stats(void);
> +
> +/* Function gets current statistics snapshot from memory. It assumes
> + * that four element array will be passed as argument. */
> +static void
> +get_cpu_snapshot_from_system(long double *cpu_array, uint8_t array_size,
> +                             int64_t *time_stamp)
> +{
> +    if (LINUX) {
> +        FILE *fp;
> +        struct timeval now;
> +
> +        xgettimeofday(&now);
> +
> +        *time_stamp = timeval_to_msec(&now);
> +
> +        /* Sanity array check */
> +        if (array_size != CPU_COUNTERS) {
> +            for (uint8_t i = 0 ; i < array_size; i++) {
> +                cpu_array[i] = -1;
> +            }
> +        }else{
> +            fp = fopen("/proc/stat","r");
> +            fscanf(fp,"%*s %Lf %Lf %Lf %Lf",&cpu_array[0],&cpu_array[1],
> +                          &cpu_array[2],&cpu_array[3]);
> +            fclose(fp);
> +        }
> +    }
> +}
> +/* Function initializes statistics snapshot with default values */
> +static void
> +cpu_snapshots_init(void)
> +{
> +
> +    long double cpu_values[CPU_COUNTERS] = {0, 0, 0, 0};
> +    int64_t time_stamp_ms = 0;
> +
> +    get_cpu_snapshot_from_system(cpu_values, CPU_COUNTERS,
> +                                 &time_stamp_ms);
> +
> +    /* 5 seconds snapshot */
> +    cpu_snapshots[0].period_ms = 5000;
> +    /* 1 minute snapshot */
> +    cpu_snapshots[1].period_ms = 60000;
> +    /* 5 minutes snapshot */
> +    cpu_snapshots[2].period_ms = 5 * 60000;
> +
> +    for (uint8_t snap_id = 0 ; snap_id < CPU_SNAPSHOTS ; snap_id++) {
> +        for (uint8_t c_id = 0 ; c_id < CPU_COUNTERS ; c_id++) {
> +            cpu_snapshots[snap_id].proc_stats[c_id] = cpu_values[c_id];
> +        }
> +        cpu_snapshots[snap_id].time_stamp_ms = time_stamp_ms;
> +    }
> +}
> +
> +/* Simple initialize function */
> +static void
> +system_stats_basic_init(struct system_stats_basic* stats)
> +{
> +    stats->cpu_util_5s = -1;
> +    stats->cpu_util_1m = -1;
> +    stats->cpu_util_5m = -1;
> +
> +    stats->free_memory = 0;
> +    stats->total_memory = 0;
> +}
> +
> +/* Conditional copy function */
> +static void
> +system_stats_basic_copy(struct system_stats_basic* stats_in,
> +                        struct system_stats_basic* stats_out)
> +{
> +    if (stats_in->cpu_util_5s != -1) {
> +        stats_out->cpu_util_5s = stats_in->cpu_util_5s;
> +    }
> +    if (stats_in->cpu_util_1m != -1) {
> +        stats_out->cpu_util_1m = stats_in->cpu_util_1m;
> +    }
> +    if (stats_in->cpu_util_5m != -1) {
> +        stats_out->cpu_util_5m = stats_in->cpu_util_5m;
> +    }
> +    stats_out->total_memory = stats_in->total_memory;
> +    stats_out->free_memory = stats_in->free_memory;
> +}
> +
> +
>  static void
>  get_cpu_cores(struct smap *stats)
>  {
> @@ -67,6 +176,54 @@ get_cpu_cores(struct smap *stats)
>      }
>  }
>
> +/* Function gets current basic system statistics if available */
> +static void
> +update_cpu_utilization(struct system_stats_basic *stats)
> +{
> +    if (LINUX) {
> +        long double cpu_val[CPU_COUNTERS] = {0, 0, 0, 0};
> +        long double util_value;
> +        long double work_current, total_current, work_previous,
> +                    total_previous;
> +        int64_t time_stamp_ms = 0;
> +
> +        get_cpu_snapshot_from_system(cpu_val, CPU_COUNTERS,
> +                                     &time_stamp_ms);
> +
> +        for (uint8_t snap_id = 0 ; snap_id < CPU_SNAPSHOTS; snap_id++) {
> +            uint64_t period = time_stamp_ms -
> +                              cpu_snapshots[snap_id].time_stamp_ms;
> +            if (period >= cpu_snapshots[snap_id].period_ms) {
> +                /* Data from requested period is gathered. */
> +                work_current = cpu_val[0] + cpu_val[1] +
> +                               cpu_val[2];
> +                total_current = cpu_val[0] + cpu_val[1] +
> +                                cpu_val[2] + cpu_val[3];
> +                work_previous = cpu_snapshots[snap_id].proc_stats[0] +
> +                                    cpu_snapshots[snap_id].proc_stats[1]
> +
> +                                    cpu_snapshots[snap_id].proc_stats[2];
> +                total_previous = cpu_snapshots[snap_id].proc_stats[0] +
> +                                     cpu_snapshots[snap_id].proc_stats[1]
> +
> +                                     cpu_snapshots[snap_id].proc_stats[2]
> +
> +                                     cpu_snapshots[snap_id].proc_
> stats[3];
> +                util_value = ((work_current - work_previous) /
> +                                  (total_current - total_previous)) *
> 10000;
> +                if (SYSTEM_STATS_CPU_5S_ID == snap_id) {
> +                    stats->cpu_util_5s = util_value;
> +                } else if (SYSTEM_STATS_CPU_1M_ID == snap_id){
> +                    stats->cpu_util_1m = util_value;
> +                } else {
> +                    stats->cpu_util_5m = util_value;
> +                }
> +                cpu_snapshots[snap_id].time_stamp_ms = time_stamp_ms;
> +                for (uint8_t c_id = 0 ; c_id < CPU_COUNTERS ; c_id++) {
> +                    cpu_snapshots[snap_id].proc_stats[c_id] =
> cpu_val[c_id];
> +                }
> +            }
> +        }
> +    }
> +}
> +
>  static void
>  get_load_average(struct smap *stats OVS_UNUSED)
>  {
> @@ -103,7 +260,8 @@ get_page_size(void)
>  }
>
>  static void
> -get_memory_stats(struct smap *stats)
> +get_memory_stats(struct smap *stats,
> +                 struct system_stats_basic * stats_basic_out)
>  {
>      if (!LINUX) {
>          unsigned int pagesize = get_page_size();
> @@ -133,7 +291,11 @@ get_memory_stats(struct smap *stats)
>          mem_total = memory_status.dwTotalPhys;
>          mem_used = memory_status.dwTotalPhys - memory_status.dwAvailPhys;
>  #endif
> -        smap_add_format(stats, "memory", "%d,%d", mem_total, mem_used);
> +        if (NULL != stats) {
> +            smap_add_format(stats, "memory", "%d,%d", mem_total,
> mem_used);
> +        }
> +        stats_basic_out->total_memory = mem_total;
> +        stats_basic_out->free_memory = mem_total - mem_used;
>      } else {
>          static const char file_name[] = "/proc/meminfo";
>          int mem_used, mem_cache, swap_used;
> @@ -178,8 +340,13 @@ get_memory_stats(struct smap *stats)
>          mem_used = mem_total - mem_free;
>          mem_cache = buffers + cached;
>          swap_used = swap_total - swap_free;
> -        smap_add_format(stats, "memory", "%d,%d,%d,%d,%d",
> -                        mem_total, mem_used, mem_cache, swap_total,
> swap_used);
> +        if (NULL != stats) {
> +            smap_add_format(stats, "memory", "%d,%d,%d,%d,%d",
> +                            mem_total, mem_used, mem_cache,
> +                            swap_total, swap_used);
> +        }
> +        stats_basic_out->total_memory = mem_total;
> +        stats_basic_out->free_memory = mem_free;
>      }
>  }
>
> @@ -522,36 +689,45 @@ get_filesys_stats(struct smap *stats OVS_UNUSED)
>      ds_destroy(&s);
>  #endif  /* HAVE_GETMNTENT_R && HAVE_STATVFS */
>  }
> -
> -#define SYSTEM_STATS_INTERVAL (5 * 1000) /* In milliseconds. */
>
> -static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
> -static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
> -static struct latch latch OVS_GUARDED_BY(mutex);
> -static bool enabled;
> -static bool started OVS_GUARDED_BY(mutex);
> -static struct smap *system_stats OVS_GUARDED_BY(mutex);
> +/* Initializes system statistics with basic functionality. */
> +void
> +system_stats_init(void)
> +{
>
> -OVS_NO_RETURN static void *system_stats_thread_func(void *);
> -static void discard_stats(void);
> +    /* Make sure that stats are initialized just once. */
> +    if (!stats_init) {
> +        stats_init = true;
> +        cpu_snapshots_init();
>
> -/* Enables or disables system stats collection, according to 'enable'. */
> +        ovs_mutex_lock(&mutex_basic);
> +        system_stats_basic_init(&stats_basic);
> +        ovs_mutex_unlock(&mutex_basic);
> +
> +        ovs_mutex_lock(&mutex);
> +        if (!started) {
> +            ovs_thread_create("system_stats",
> +                              system_stats_thread_func, NULL);
> +            latch_init(&latch);
> +            started = true;
> +        }
> +        discard_stats();
> +        enabled_complex = false;
> +        ovs_mutex_unlock(&mutex);
> +    }
> +}
> +
> +/* Enables or disables system complex stats collection,
> + * according to 'enable'. */
>  void
>  system_stats_enable(bool enable)
>  {
> -    if (enabled != enable) {
> +    if (enabled_complex != enable) {
>          ovs_mutex_lock(&mutex);
>          if (enable) {
> -            if (!started) {
> -                ovs_thread_create("system_stats",
> -                                  system_stats_thread_func, NULL);
> -                latch_init(&latch);
> -                started = true;
> -            }
>              discard_stats();
> -            xpthread_cond_signal(&cond);
>          }
> -        enabled = enable;
> +        enabled_complex = enable;
>          ovs_mutex_unlock(&mutex);
>      }
>  }
> @@ -573,7 +749,7 @@ system_stats_run(void)
>      if (system_stats) {
>          latch_poll(&latch);
>
> -        if (enabled) {
> +        if (enabled_complex) {
>              stats = system_stats;
>              system_stats = NULL;
>          } else {
> @@ -585,12 +761,32 @@ system_stats_run(void)
>      return stats;
>  }
>
> +/* Gets new snapshot of system basic stats.
> + *
> + * Function returns current state of basic statistics. Returned data is
> + * owned by the caller.  The caller must use free() to completely
> + * free the returned data.
> + *
> + * If basic statistics are disabled, NULL is returned. */
> +struct system_stats_basic*
> +system_stats_run_basic(void)
> +{
> +    struct system_stats_basic *stats_basic_ret = NULL;
> +
> +    stats_basic_ret = xmalloc(sizeof *stats_basic_ret);
> +    ovs_mutex_lock(&mutex_basic);
> +    *stats_basic_ret = stats_basic;
> +    ovs_mutex_unlock(&mutex_basic);
> +
> +    return stats_basic_ret;
> +}
> +
>  /* Causes poll_block() to wake up when system_stats_run() needs to be
>   * called. */
>  void
>  system_stats_wait(void)
>  {
> -    if (enabled) {
> +    if (enabled_complex) {
>          latch_wait(&latch);
>      }
>  }
> @@ -612,32 +808,44 @@ system_stats_thread_func(void *arg OVS_UNUSED)
>
>      for (;;) {
>          long long int next_refresh;
> -        struct smap *stats;
> -
> -        ovs_mutex_lock(&mutex);
> -        while (!enabled) {
> -            /* The thread is sleeping, potentially for a long time, and
> it's
> -             * not holding RCU protected references, so it makes sense to
> -             * quiesce */
> -            ovsrcu_quiesce_start();
> -            ovs_mutex_cond_wait(&cond, &mutex);
> -            ovsrcu_quiesce_end();
> +        bool do_complex = false;
> +        struct smap *stats = NULL;
> +        struct system_stats_basic stats_current;
> +
> +        system_stats_basic_init(&stats_current);
> +
> +        /* Check status flags at the beginning to prevent some
> +         * synchronization problems during execution.
> +         *
> +         * Basic statistics are enabled by default */
> +        if (enabled_complex) {
> +            do_complex = true;
> +            stats = xmalloc(sizeof *stats);
> +            smap_init(stats);
>          }
> -        ovs_mutex_unlock(&mutex);
>
> -        stats = xmalloc(sizeof *stats);
> -        smap_init(stats);
> -        get_cpu_cores(stats);
> -        get_load_average(stats);
> -        get_memory_stats(stats);
> -        get_process_stats(stats);
> -        get_filesys_stats(stats);
> +        /* Get memory stats always */
> +        get_memory_stats(stats, &stats_current);
>
> -        ovs_mutex_lock(&mutex);
> -        discard_stats();
> -        system_stats = stats;
> -        latch_set(&latch);
> -        ovs_mutex_unlock(&mutex);
> +        /* Get basic statistics */
> +        update_cpu_utilization(&stats_current);
> +
> +        ovs_mutex_lock(&mutex_basic);
> +        system_stats_basic_copy(&stats_current, &stats_basic);
> +        ovs_mutex_unlock(&mutex_basic);
> +
> +        if (do_complex) {
> +            get_cpu_cores(stats);
> +            get_load_average(stats);
> +            get_process_stats(stats);
> +            get_filesys_stats(stats);
> +
> +            ovs_mutex_lock(&mutex);
> +            discard_stats();
> +            system_stats = stats;
> +            latch_set(&latch);
> +            ovs_mutex_unlock(&mutex);
> +        }
>
>          next_refresh = time_msec() + SYSTEM_STATS_INTERVAL;
>          do {
> diff --git a/vswitchd/system-stats.h b/vswitchd/system-stats.h
> index 83b4bcb..e0b3078 100644
> --- a/vswitchd/system-stats.h
> +++ b/vswitchd/system-stats.h
> @@ -17,9 +17,25 @@
>  #define VSWITCHD_SYSTEM_STATS 1
>
>  #include <stdbool.h>
> +#include <stdint.h>
>
> +struct system_stats_basic {
> +
> +    /* Percentage expressed in hundredths of a percent
> +       (e.g. 100 = 1%). If a percentage value is unknown then
> +       -1 value is used. */
> +    int32_t cpu_util_5s;
> +    int32_t cpu_util_1m;
> +    int32_t cpu_util_5m;
> +
> +    uint64_t total_memory;
> +    uint64_t free_memory;
> +};
> +
> +void system_stats_init(void);
>  void system_stats_enable(bool enable);
>  struct smap *system_stats_run(void);
> +struct system_stats_basic* system_stats_run_basic(void);
>  void system_stats_wait(void);
>
>  #endif /* vswitchd/system-stats.h */
> --
> 1.8.3.1
>
> _______________________________________________
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to