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