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

Reply via email to