diff --git a/configure.ac b/configure.ac index a77ee281b..f767d0869 100644 --- a/configure.ac +++ b/configure.ac @@ -72,7 +72,7 @@ case $host_os in *mingw*) SRC_OS="win32" AC_DEFINE(SIGAR_TEST_OS_WIN32, [1], [for the tests]) - SIGAR_LIBS="-lws2_32 -liphlpapi -lnetapi32 -lversion" + SIGAR_LIBS="-lws2_32 -liphlpapi -lnetapi32 -lversion -lole32 -loleaut32" ;; *) ac_system="unknown" diff --git a/examples/cpuinfo.c b/examples/cpuinfo.c index 5eb4dbdd1..1f64061ad 100644 --- a/examples/cpuinfo.c +++ b/examples/cpuinfo.c @@ -23,6 +23,7 @@ int main(int argc, char **argv) { int status, i; sigar_t *sigar; sigar_cpu_list_t cpulist; + sigar_loadavg_t loadavg; sigar_open(&sigar); @@ -46,15 +47,16 @@ int main(int argc, char **argv) { } sigar_cpu_list_destroy(sigar, &cpulist); + + status = sigar_loadavg_get(sigar, &loadavg); - sigar_processor_queue_t proc_queue; - status = sigar_processor_queue_get(sigar, &proc_queue); if (status != SIGAR_OK) { - printf("processor_queue error: %d (%s)\n", + printf("sigar_loadavg_get: %d (%s)\n", status, sigar_strerror(sigar, status)); exit(1); } - printf("Processor Queue Length: %u\n", proc_queue.processor_queue); + + printf("Processor Queue Length: %u\n", loadavg.processor_queue); sigar_close(sigar); diff --git a/include/sigar.h b/include/sigar.h index ee8c849c5..74ad68df7 100644 --- a/include/sigar.h +++ b/include/sigar.h @@ -223,18 +223,12 @@ SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar, typedef struct { double loadavg[3]; + sigar_uint32_t processor_queue; } sigar_loadavg_t; SIGAR_DECLARE(int) sigar_loadavg_get(sigar_t *sigar, sigar_loadavg_t *loadavg); -typedef struct { - sigar_uint32_t processor_queue; -} sigar_processor_queue_t; - -SIGAR_DECLARE(int) sigar_processor_queue_get(sigar_t *sigar, - sigar_processor_queue_t *queue_info); - typedef struct { unsigned long number; unsigned long size; diff --git a/include/sigar_rma.h b/include/sigar_rma.h new file mode 100644 index 000000000..41a6de2cd --- /dev/null +++ b/include/sigar_rma.h @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +#ifndef SIGAR_RMA_H +#define SIGAR_RMA_H + +#include +#include + +#define SIGAR_RMA_RATE_1_MIN 1 * 60 +#define SIGAR_RMA_RATE_5_MIN 5 * 60 +#define SIGAR_RMA_RATE_15_MIN 15 * 60 + +typedef struct { + + /* Elements configured by the caller. */ + + int sample_rate_secs; /* Period of sample secs. */ + int element_count; /* Number of elements in the ring + * buffer. */ + + /* Internal items for tracking. */ + + float *values; /* Ring buffer sample set. */ + bool have_wrapped; /* Have we wrapped the buffer yet. */ + int current_pos; /* Current index location. */ +} sigar_rma_stat_handle_t; + +sigar_rma_stat_handle_t *sigar_rma_init(sigar_t *sigar, int sample_rate_secs, int max_average_time); +void sigar_rma_add_sample(sigar_t *sigar, sigar_rma_stat_handle_t * rma, float sample); +float sigar_rma_get_average(sigar_t *sigar, sigar_rma_stat_handle_t * rma, int rate); + +#endif /* SIGAR_RMA_H */ diff --git a/src/Makefile.am b/src/Makefile.am index b34437895..192ffdabe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,7 @@ libsigar_la_SOURCES = \ sigar_format.c \ sigar_getline.c \ sigar_ptql.c \ + sigar_rma.c \ sigar_signal.c \ sigar_util.c \ sigar_version_autoconf.c diff --git a/src/os/aix/aix_sigar.c b/src/os/aix/aix_sigar.c index 18c05aa1f..882e2723f 100644 --- a/src/os/aix/aix_sigar.c +++ b/src/os/aix/aix_sigar.c @@ -663,12 +663,6 @@ int sigar_who_list_get(sigar_t *sigar, return SIGAR_OK; } -int sigar_processor_queue_get(sigar_t *sigar, - sigar_processor_queue_t *queue_info) -{ - return SIGAR_ENOTIMPL; -} - int sigar_loadavg_get(sigar_t *sigar, sigar_loadavg_t *loadavg) { diff --git a/src/os/darwin/darwin_sigar.c b/src/os/darwin/darwin_sigar.c index 769f3f3a4..b8c7568a5 100644 --- a/src/os/darwin/darwin_sigar.c +++ b/src/os/darwin/darwin_sigar.c @@ -936,12 +936,6 @@ int sigar_uptime_get(sigar_t *sigar, return SIGAR_OK; } -int sigar_processor_queue_get(sigar_t *sigar, - sigar_processor_queue_t *queue_info) -{ - return SIGAR_ENOTIMPL; -} - int sigar_loadavg_get(sigar_t *sigar, sigar_loadavg_t *loadavg) { diff --git a/src/os/hpux/hpux_sigar.c b/src/os/hpux/hpux_sigar.c index 2499ff8e1..cb98f0a5d 100644 --- a/src/os/hpux/hpux_sigar.c +++ b/src/os/hpux/hpux_sigar.c @@ -201,12 +201,6 @@ int sigar_uptime_get(sigar_t *sigar, return SIGAR_OK; } -int sigar_processor_queue_get(sigar_t *sigar, - sigar_processor_queue_t *queue_info) -{ - return SIGAR_ENOTIMPL; -} - int sigar_loadavg_get(sigar_t *sigar, sigar_loadavg_t *loadavg) { diff --git a/src/os/linux/linux_sigar.c b/src/os/linux/linux_sigar.c index 6b7b9130d..a3fd23010 100644 --- a/src/os/linux/linux_sigar.c +++ b/src/os/linux/linux_sigar.c @@ -502,12 +502,6 @@ int sigar_uptime_get(sigar_t *sigar, return SIGAR_OK; } -int sigar_processor_queue_get(sigar_t *sigar, - sigar_processor_queue_t *queue_info) -{ - return SIGAR_ENOTIMPL; -} - int sigar_loadavg_get(sigar_t *sigar, sigar_loadavg_t *loadavg) { diff --git a/src/os/solaris/solaris_sigar.c b/src/os/solaris/solaris_sigar.c index f46cb12b3..aa6e59d7c 100644 --- a/src/os/solaris/solaris_sigar.c +++ b/src/os/solaris/solaris_sigar.c @@ -532,12 +532,6 @@ int sigar_uptime_get(sigar_t *sigar, return SIGAR_OK; } -int sigar_processor_queue_get(sigar_t *sigar, - sigar_processor_queue_t *queue_info) -{ - return SIGAR_ENOTIMPL; -} - static int loadavg_keys[] = { KSTAT_SYSTEM_LOADAVG_1, KSTAT_SYSTEM_LOADAVG_2, diff --git a/src/os/win32/sigar_os.h b/src/os/win32/sigar_os.h index 01dc661a8..5735748ec 100755 --- a/src/os/win32/sigar_os.h +++ b/src/os/win32/sigar_os.h @@ -50,7 +50,9 @@ #include #include #include +#include +#include "sigar_rma.h" #include "sigar_util.h" #ifdef MSVC @@ -572,6 +574,13 @@ typedef struct { sigar_dll_func_t end; } sigar_mpr_t; + +typedef struct wmi_handle { + int initialized; + IWbemLocator *locator; + IWbemServices *services; +} sigar_wmi_handle_t; + struct sigar_t { SIGAR_T_BASE; char *machine; @@ -580,6 +589,7 @@ struct sigar_t { HKEY handle; char *perfbuf; DWORD perfbuf_size; + sigar_wmi_handle_t *wmi_handle; sigar_wtsapi_t wtsapi; sigar_iphlpapi_t iphlpapi; sigar_advapi_t advapi; @@ -589,6 +599,7 @@ struct sigar_t { sigar_kernel_t kernel; sigar_mpr_t mpr; sigar_win32_pinfo_t pinfo; + sigar_rma_stat_handle_t *rma_process_queue; sigar_cache_t *netif_adapters; sigar_cache_t *netif_mib_rows; sigar_cache_t *netif_addr_rows; diff --git a/src/os/win32/win32_sigar.c b/src/os/win32/win32_sigar.c index e22b98d50..ddff3a200 100755 --- a/src/os/win32/win32_sigar.c +++ b/src/os/win32/win32_sigar.c @@ -20,6 +20,7 @@ #include "sigar_private.h" #include "sigar_pdh.h" #include "sigar_os.h" +#include "sigar_rma.h" #include "sigar_util.h" #include "sigar_format.h" #include @@ -557,6 +558,7 @@ int sigar_os_open(sigar_t **sigar_ptr) HINSTANCE h; OSVERSIONINFO version; int i; + int wmi_status; sigar_t *sigar; *sigar_ptr = sigar = malloc(sizeof(*sigar)); @@ -620,6 +622,16 @@ int sigar_os_open(sigar_t **sigar_ptr) /* increase process visibility */ sigar_enable_privilege(SE_DEBUG_NAME); + /* Open our WMI handle. */ + + sigar->wmi_handle = (sigar_wmi_handle_t *)wmi_handle_open(&wmi_status); + + if(wmi_status != 0) + { + /* TODO What shall we do if WMI open fails? Retry every call? */ + sigar_log_printf(sigar, SIGAR_LOG_WARN, "Unable to create WMI handle"); + } + return result; } @@ -1091,7 +1103,27 @@ SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar, SIGAR_DECLARE(int) sigar_loadavg_get(sigar_t *sigar, sigar_loadavg_t *loadavg) { - return SIGAR_ENOTIMPL; + sigar_uint32_t p_queue = 0; + int status; + + unsigned long num_elems; + status = wmi_query_sum_u32(sigar, + L"SELECT ProcessorQueueLength FROM Win32_PerfFormattedData_PerfOS_System", + L"ProcessorQueueLength", &p_queue, &num_elems); + + if (status == SIGAR_OK) + { + if(sigar->rma_process_queue == NULL) + sigar->rma_process_queue = sigar_rma_init(sigar, 1, SIGAR_RMA_RATE_15_MIN); + sigar_rma_add_sample(sigar, sigar->rma_process_queue, p_queue); + loadavg->processor_queue = p_queue; + loadavg->loadavg[0] = sigar_rma_get_average(sigar, sigar->rma_process_queue, SIGAR_RMA_RATE_1_MIN); + loadavg->loadavg[1] = sigar_rma_get_average(sigar, sigar->rma_process_queue, SIGAR_RMA_RATE_5_MIN); + loadavg->loadavg[2] = sigar_rma_get_average(sigar, sigar->rma_process_queue, SIGAR_RMA_RATE_15_MIN); + return SIGAR_OK; + } + + return status; } #define get_process_object(sigar, err) \ diff --git a/src/os/win32/wmi.cpp b/src/os/win32/wmi.cpp index 2e6a59ba1..04d739473 100644 --- a/src/os/win32/wmi.cpp +++ b/src/os/win32/wmi.cpp @@ -28,6 +28,12 @@ #include #include #include "sigar.h" +#include "sigar_private.h" +#include "sigar_pdh.h" +#include "sigar_os.h" +#include "sigar_rma.h" +#include "sigar_util.h" +#include "sigar_format.h" #pragma comment(lib, "wbemuuid.lib") @@ -48,14 +54,6 @@ template <> const GUID & __mingw_uuidof < IWbemLocator * >() { #endif extern "C" { -struct wmi_handle { - int initialized; - IWbemLocator *locator; - IWbemServices *services; -}; - -struct wmi_handle gWMI_handle; - int wmi_map_sigar_error(HRESULT hres) { switch (hres) { @@ -72,28 +70,29 @@ int wmi_map_sigar_error(HRESULT hres) } } -int wmi_handle_close(struct wmi_handle *wmi) +void wmi_handle_close(sigar_wmi_handle_t *wmi_handle) { - if (wmi->services) { - wmi->services->Release(); - wmi->services = NULL; + if(wmi_handle == NULL) + return; + + if (wmi_handle->services) { + wmi_handle->services->Release(); + wmi_handle->services = NULL; } - if (wmi->locator) { - wmi->locator->Release(); - wmi->services = NULL; + if (wmi_handle->locator) { + wmi_handle->locator->Release(); + wmi_handle->services = NULL; } } -struct wmi_handle * wmi_handle_open(int *error) +sigar_wmi_handle_t * wmi_handle_open(int *error) { *error = SIGAR_OK; - if(gWMI_handle.initialized) - { - return &gWMI_handle; - } - memset(&gWMI_handle, 0, sizeof(gWMI_handle)); + sigar_wmi_handle_t *handle; + + handle = (sigar_wmi_handle_t *)calloc(1, sizeof (*handle)); HRESULT hres; wchar_t root[] = L"root\\CIMV2"; @@ -104,42 +103,42 @@ struct wmi_handle * wmi_handle_open(int *error) } hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, - RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0); + RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0); if (FAILED(hres)) { goto err; } - hres = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&gWMI_handle.locator)); + hres = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&handle->locator)); if (FAILED(hres)) { goto err; } - hres = gWMI_handle.locator->ConnectServer(root, NULL, NULL, NULL, - WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &gWMI_handle.services); + hres = handle->locator->ConnectServer(root, NULL, NULL, NULL, + WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &handle->services); if (FAILED(hres)) { goto err; } - gWMI_handle.initialized = 1; - - return &gWMI_handle; - + return handle; err: - wmi_handle_close(&gWMI_handle); + wmi_handle_close(handle); *error = wmi_map_sigar_error(hres); return NULL; } -HRESULT wmi_get_proc_string_property(struct wmi_handle * wmi, DWORD pid, - TCHAR * name, TCHAR * value, DWORD len) +HRESULT wmi_get_proc_string_property(sigar_t *sigar, DWORD pid, TCHAR * name, TCHAR * value, DWORD len) { IWbemClassObject *obj; VARIANT var; + HRESULT result; + + if(sigar->wmi_handle == NULL) + return (E_INVALIDARG); wchar_t query[56]; wsprintf(query, L"Win32_Process.Handle=%d", pid); - HRESULT result = wmi->services->GetObject(query, 0, 0, &obj, 0); + result = sigar->wmi_handle->services->GetObject(query, 0, 0, &obj, 0); if (FAILED(result)) { return result; @@ -161,40 +160,40 @@ HRESULT wmi_get_proc_string_property(struct wmi_handle * wmi, DWORD pid, return result; } -HRESULT wmi_get_proc_executable_path(struct wmi_handle * wmi, DWORD pid, TCHAR * value) +HRESULT wmi_get_proc_executable_path(sigar_t *sigar, DWORD pid, TCHAR * value) { wchar_t prop[] = L"ExecutablePath"; - return wmi_get_proc_string_property(wmi, pid, prop, value, MAX_PATH); + return wmi_get_proc_string_property(sigar, pid, prop, value, MAX_PATH); } -HRESULT wmi_get_proc_command_line(struct wmi_handle * wmi, DWORD pid, TCHAR * value) +HRESULT wmi_get_proc_command_line(sigar_t *sigar, DWORD pid, TCHAR * value) { wchar_t prop[] = L"CommandLine"; - return wmi_get_proc_string_property(wmi, pid, prop, value, MAX_PATH); + return wmi_get_proc_string_property(sigar, pid, prop, value, MAX_PATH); } -IEnumWbemClassObject *wmi_query(struct wmi_handle * wmi, const wchar_t * query) +IEnumWbemClassObject *wmi_query(sigar_t *sigar, const wchar_t * query) { IEnumWbemClassObject *wmi_enum = NULL; - if (wmi) { + if (sigar->wmi_handle) { wchar_t lang[] = L"WQL"; wchar_t *query_cpy = wcsdup(query); HRESULT hres = - wmi->services->ExecQuery(lang, query_cpy, WBEM_FLAG_FORWARD_ONLY, NULL, &wmi_enum); + sigar->wmi_handle->services->ExecQuery(lang, query_cpy, WBEM_FLAG_FORWARD_ONLY, NULL, &wmi_enum); free(query_cpy); } return wmi_enum; } -int wmi_query_sum_u64(struct wmi_handle *wmi, const wchar_t * query, const wchar_t * attrib, +int wmi_query_sum_u64(sigar_t *sigar, const wchar_t * query, const wchar_t * attrib, sigar_uint64_t * sum, unsigned long *num_elems) { *sum = 0; *num_elems = 0; - IEnumWbemClassObject *wmi_enum = wmi_query(wmi, query); + IEnumWbemClassObject *wmi_enum = wmi_query(sigar, query); if (!wmi_enum) { return -1; } @@ -225,21 +224,21 @@ int wmi_query_sum_u64(struct wmi_handle *wmi, const wchar_t * query, const wchar return 0; } -int wmi_query_sum_u32(struct wmi_handle *wmi, const wchar_t * query, +int wmi_query_sum_u32(sigar_t *sigar, const wchar_t * query, const wchar_t * attrib, sigar_uint32_t * sum, unsigned long *num_elems) { sigar_uint64_t sum64 = 0; - int rc = wmi_query_sum_u64(wmi, query, attrib, &sum64, num_elems); + int rc = wmi_query_sum_u64(sigar, query, attrib, &sum64, num_elems); *sum = sum64; return rc; } -int wmi_query_avg(struct wmi_handle *wmi, const wchar_t * query, +int wmi_query_avg(sigar_t *sigar, const wchar_t * query, const wchar_t * attrib, float *avg) { sigar_uint64_t sum = 0; unsigned long num_elems = 0; - int rc = wmi_query_sum_u64(wmi, query, attrib, &sum, &num_elems); + int rc = wmi_query_sum_u64(sigar, query, attrib, &sum, &num_elems); if (!rc && num_elems) { *avg = sum / (double)(num_elems); } @@ -253,12 +252,8 @@ int sigar_proc_args_wmi_get(sigar_t * sigar, sigar_pid_t pid, sigar_proc_args_t { TCHAR buf[SIGAR_CMDLINE_MAX]; int status; - struct wmi_handle *wmi; - if ((wmi = wmi_handle_open(&status)) == NULL) { - return status; - } - if ((status = wmi_get_proc_command_line(wmi, pid, buf))) { + if ((status = wmi_get_proc_command_line(sigar, pid, buf))) { goto out; } else { status = sigar_parse_proc_args(sigar, buf, procargs); @@ -272,14 +267,10 @@ int sigar_proc_exe_wmi_get(sigar_t * sigar, sigar_pid_t pid, sigar_proc_exe_t * { TCHAR buf[MAX_PATH + 1]; int status; - struct wmi_handle *wmi; - if ((wmi = wmi_handle_open(&status)) == NULL) { - return status; - } procexe->name[0] = '\0'; - if ((status = wmi_get_proc_executable_path(wmi, pid, buf))) { + if ((status = wmi_get_proc_executable_path(sigar, pid, buf))) { goto out; } else { status = SIGAR_OK; @@ -291,24 +282,4 @@ int sigar_proc_exe_wmi_get(sigar_t * sigar, sigar_pid_t pid, sigar_proc_exe_t * out: return status; } - -int sigar_processor_queue_get(sigar_t *sigar, sigar_processor_queue_t *queue_info) -{ - memset(queue_info, 0, sizeof(*queue_info)); - - int status; - struct wmi_handle *wmi; - if ((wmi = wmi_handle_open(&status)) == NULL) { - return status; - } - - unsigned long num_elems; - status = wmi_query_sum_u32(wmi, - L"SELECT ProcessorQueueLength FROM Win32_PerfFormattedData_PerfOS_System", - L"ProcessorQueueLength", &queue_info->processor_queue, &num_elems); - -out: - return status; -} - } //extern "C" diff --git a/src/sigar_rma.c b/src/sigar_rma.c new file mode 100755 index 000000000..76e1a62c9 --- /dev/null +++ b/src/sigar_rma.c @@ -0,0 +1,132 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "sigar.h" +#include "sigar_log.h" +#include "sigar_rma.h" + +sigar_rma_stat_handle_t * +sigar_rma_init(sigar_t *sigar, int sample_rate_secs, int max_average_time) +{ + if(sample_rate_secs <= 0) + { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, \ + "sigar_rma_init: invalid sample_rate_secs : %d", \ + sample_rate_secs); + return NULL; + } + + if(max_average_time <= 0) + { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, \ + "sigar_rma_init: invalid max_average_time : %d", \ + sample_rate_secs); + return NULL; + } + + sigar_rma_stat_handle_t *rma; + rma = calloc(1, sizeof(*rma)); + + /* Allocate enough space to hold the longest period. */ + + rma->sample_rate_secs = sample_rate_secs; + rma->element_count = max_average_time / sample_rate_secs; + + rma->values = calloc(rma->element_count, sizeof(float)); + rma->current_pos = 0; + rma->have_wrapped = false; + + return rma; +} + +void +sigar_rma_add_sample(sigar_t *sigar, sigar_rma_stat_handle_t * rma, float sample) +{ + if(rma == NULL) + { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, \ + "sigar_rma_add_sample: NULL sigar_rma_stat_handle_t"); + return; + } + + rma->values[rma->current_pos++] = sample; + if (rma->current_pos == rma->element_count) { + rma->have_wrapped = true; + rma->current_pos = 0; + } +} + +float +sigar_rma_get_average(sigar_t *sigar, sigar_rma_stat_handle_t * rma, int rate) +{ + float avg = 0; + int pos; + int backup_size = rate / rma->sample_rate_secs; + int count; + + if(rma == NULL) + { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, \ + "sigar_rma_get_average: NULL sigar_rma_stat_handle_t"); + return 0.0; + } + + /* Safety check to avoid divide by 0. */ + + if(backup_size == 0) + { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, \ + "sigar_rma_get_average: Computed 0 backup for rate : %d and sample size %d", + rate, rma->sample_rate_secs); + return 0.0; + } + + /* + * * To compute the average, we first compute the number of samples + * to count based * on our sample rate, and how many samples/sec we + * are doing. * eg: (rate = RMA_RATE_1_MIN = 60) / (sample_rate_secs + * = 5) = 12 elements. * We then work backwards adding the number of + * elements, taking into account * buffer wrapping, and partial + * buffer (not yet having the total number of elements.) + */ + + /* + * If our buffer has wrapped, then we are assured to have a full + * sample set. + */ + + if (rma->have_wrapped) { + for (count = 0, pos = rma->current_pos - 1; count < backup_size; count++, pos--) { + if (pos < 0) + pos = rma->element_count - 1; + avg += rma->values[pos]; + } + } + /* We may or may not have a full sample set. */ + else { + pos = rma->current_pos; + + if ((pos - backup_size) < 0) { + /* We don't have a complete backup sample yet. */ + backup_size = pos; + } + for (count = backup_size; count > 0; count--) { + avg += rma->values[pos - count]; + } + } + + return (avg / backup_size); +}