[ovs-dev] [PATCH] Expose sFLOW "Processor information" counters.

Weglicki, MichalX michalx.weglicki at intel.com
Tue Nov 22 09:53:03 UTC 2016


Hello Neil,

Definitely I’m not sFLOW expert, as I didn’t even know anything about hsflowd.

Nevertheless before declining my proposal, maybe it is good to think about other benefits. I do think that such basic statistics which are available by default without any third party tool can simplify configuration for some users. Also I can’t find in sflow_host cpu_utilization, load average is little different statistic type, I know this is minor. I also thing that keeping simple API to get most common system stats on OVS level, could be also beneficial for some other functionalities in the future.

Br,
Michal.

From: Neil McKee [mailto:neil.mckee at inmon.com]
Sent: Tuesday, November 22, 2016 12:14 AM
To: Weglicki, MichalX <michalx.weglicki at intel.com>
Cc: dev at openvswitch.org
Subject: Re: [ovs-dev] [PATCH] Expose sFLOW "Processor information" counters.

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.weglicki at intel.com<mailto:michalx.weglicki at 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.weglicki at intel.com<mailto:michalx.weglicki at intel.com>>
---
 lib/sflow.h                  |  12 ++
 lib/sflow_receiver.c         |   8 ++
 ofproto/ofproto-dpif-sflow.c |  17 ++-
 tests/ofproto-dpif.at<http://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<http://ofproto-dpif.at> b/tests/ofproto-dpif.at<http://ofproto-dpif.at>
index ec7bd60..c8ee532 100644
--- a/tests/ofproto-dpif.at<http://ofproto-dpif.at>
+++ b/tests/ofproto-dpif.at<http://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
dev at openvswitch.org<mailto:dev at openvswitch.org>
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

--------------------------------------------------------------
Intel Research and Development Ireland Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263


This e-mail and any attachments may contain confidential material for the sole
use of the intended recipient(s). Any review or distribution by others is
strictly prohibited. If you are not the intended recipient, please contact the
sender and delete all copies.


More information about the dev mailing list