* [Qemu-devel] [PATCH 1/3] timer: Move NANOSECONDS_PER_SECONDS to timer.h
2015-06-12 13:01 [Qemu-devel] [PATCH 0/3] Add infrastructure to compute timed averages Alberto Garcia
@ 2015-06-12 13:01 ` Alberto Garcia
2015-06-12 13:01 ` [Qemu-devel] [PATCH 2/3] timer: Use a single definition of NSEC_PER_SEC for the whole codebase Alberto Garcia
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Alberto Garcia @ 2015-06-12 13:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Alberto Garcia, qemu-block, Stefan Hajnoczi
We want to be able to reuse this define by making it common to
multiple QEMU modules.
This also makes it an integer since there's no need for it to be a
float.
Signed-off-by: Alberto Garcia <berto@igalia.com>
---
include/qemu/throttle.h | 2 --
include/qemu/timer.h | 2 ++
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
index b890613..1c639d2 100644
--- a/include/qemu/throttle.h
+++ b/include/qemu/throttle.h
@@ -27,8 +27,6 @@
#include "qemu-common.h"
#include "qemu/timer.h"
-#define NANOSECONDS_PER_SECOND 1000000000.0
-
typedef enum {
THROTTLE_BPS_TOTAL,
THROTTLE_BPS_READ,
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index e5bd494..1f1e56b 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -5,6 +5,8 @@
#include "qemu-common.h"
#include "qemu/notify.h"
+#define NANOSECONDS_PER_SECOND 1000000000LL
+
/* timers */
#define SCALE_MS 1000000
--
2.1.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 2/3] timer: Use a single definition of NSEC_PER_SEC for the whole codebase
2015-06-12 13:01 [Qemu-devel] [PATCH 0/3] Add infrastructure to compute timed averages Alberto Garcia
2015-06-12 13:01 ` [Qemu-devel] [PATCH 1/3] timer: Move NANOSECONDS_PER_SECONDS to timer.h Alberto Garcia
@ 2015-06-12 13:01 ` Alberto Garcia
2015-06-12 13:01 ` [Qemu-devel] [PATCH 3/3] util: Infrastructure for computing recent averages Alberto Garcia
2015-06-26 9:09 ` [Qemu-devel] [PATCH 0/3] Add infrastructure to compute timed averages Stefan Hajnoczi
3 siblings, 0 replies; 6+ messages in thread
From: Alberto Garcia @ 2015-06-12 13:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Alberto Garcia, qemu-block, Stefan Hajnoczi
Signed-off-by: Alberto Garcia <berto@igalia.com>
---
hw/ppc/ppc.c | 2 --
hw/ppc/spapr_rtc.c | 3 +--
hw/timer/mc146818rtc.c | 1 -
hw/usb/hcd-ehci.c | 2 +-
include/qemu/timer.h | 2 +-
tests/rtl8139-test.c | 10 +++++-----
tests/test-throttle.c | 8 ++++----
tests/wdt_ib700-test.c | 15 +++++++--------
util/throttle.c | 4 ++--
9 files changed, 21 insertions(+), 26 deletions(-)
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 99db56c..2a4b8e1 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -51,8 +51,6 @@
# define LOG_TB(...) do { } while (0)
#endif
-#define NSEC_PER_SEC 1000000000LL
-
static void cpu_ppc_tb_stop (CPUPPCState *env);
static void cpu_ppc_tb_start (CPUPPCState *env);
diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c
index 83eb7c1..9da3746 100644
--- a/hw/ppc/spapr_rtc.c
+++ b/hw/ppc/spapr_rtc.c
@@ -26,6 +26,7 @@
*
*/
#include "cpu.h"
+#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "hw/ppc/spapr.h"
#include "qapi-event.h"
@@ -40,8 +41,6 @@ struct sPAPRRTCState {
int64_t ns_offset;
};
-#define NSEC_PER_SEC 1000000000LL
-
void spapr_rtc_read(DeviceState *dev, struct tm *tm, uint32_t *ns)
{
sPAPRRTCState *rtc = SPAPR_RTC(dev);
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index f2b77fa..41563be 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -48,7 +48,6 @@
# define DPRINTF_C(format, ...) do { } while (0)
#endif
-#define NSEC_PER_SEC 1000000000LL
#define SEC_PER_MIN 60
#define MIN_PER_HOUR 60
#define SEC_PER_HOUR 3600
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index d4d7547..d7cd40b 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -32,7 +32,7 @@
#include "trace.h"
#define FRAME_TIMER_FREQ 1000
-#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
+#define FRAME_TIMER_NS (NSEC_PER_SEC / FRAME_TIMER_FREQ)
#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8)
#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index 1f1e56b..72a2529 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -5,7 +5,7 @@
#include "qemu-common.h"
#include "qemu/notify.h"
-#define NANOSECONDS_PER_SECOND 1000000000LL
+#define NSEC_PER_SEC 1000000000LL
/* timers */
diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c
index 4e0bf02..3bff0e3 100644
--- a/tests/rtl8139-test.c
+++ b/tests/rtl8139-test.c
@@ -12,6 +12,7 @@
#include "libqtest.h"
#include "libqos/pci-pc.h"
#include "qemu/osdep.h"
+#include "qemu/timer.h"
#include "qemu-common.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
@@ -20,7 +21,6 @@ static void nop(void)
}
#define CLK 33000000
-#define NS_PER_SEC 1000000000ULL
static QPCIBus *pcibus;
static QPCIDevice *dev;
@@ -86,7 +86,7 @@ static void test_timer(void)
fatal("time too big %u\n", curr);
}
for (cnt = 0; ; ) {
- clock_step(1 * NS_PER_SEC);
+ clock_step(1 * NSEC_PER_SEC);
prev = curr;
curr = in_Timer();
@@ -125,7 +125,7 @@ static void test_timer(void)
out_IntrStatus(0x4000);
curr = in_Timer();
out_TimerInt(curr + 0.5 * CLK);
- clock_step(1 * NS_PER_SEC);
+ clock_step(1 * NSEC_PER_SEC);
out_Timer(0);
if ((in_IntrStatus() & 0x4000) == 0) {
fatal("we should have an interrupt here!\n");
@@ -137,7 +137,7 @@ static void test_timer(void)
out_IntrStatus(0x4000);
curr = in_Timer();
out_TimerInt(curr + 0.5 * CLK);
- clock_step(1 * NS_PER_SEC);
+ clock_step(1 * NSEC_PER_SEC);
out_TimerInt(0);
if ((in_IntrStatus() & 0x4000) == 0) {
fatal("we should have an interrupt here!\n");
@@ -148,7 +148,7 @@ static void test_timer(void)
next = curr + 5.0 * CLK;
out_TimerInt(next);
for (cnt = 0; ; ) {
- clock_step(1 * NS_PER_SEC);
+ clock_step(1 * NSEC_PER_SEC);
prev = curr;
curr = in_Timer();
diff = (curr-prev) & 0xffffffffu;
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
index d8ba415..00e4c70 100644
--- a/tests/test-throttle.c
+++ b/tests/test-throttle.c
@@ -36,19 +36,19 @@ static void test_leak_bucket(void)
bkt.level = 1.5;
/* leak an op work of time */
- throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
+ throttle_leak_bucket(&bkt, NSEC_PER_SEC / 150);
g_assert(bkt.avg == 150);
g_assert(bkt.max == 15);
g_assert(double_cmp(bkt.level, 0.5));
/* leak again emptying the bucket */
- throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
+ throttle_leak_bucket(&bkt, NSEC_PER_SEC / 150);
g_assert(bkt.avg == 150);
g_assert(bkt.max == 15);
g_assert(double_cmp(bkt.level, 0));
/* check that the bucket level won't go lower */
- throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 150);
+ throttle_leak_bucket(&bkt, NSEC_PER_SEC / 150);
g_assert(bkt.avg == 150);
g_assert(bkt.max == 15);
g_assert(double_cmp(bkt.level, 0));
@@ -86,7 +86,7 @@ static void test_compute_wait(void)
bkt.level = 15.5;
wait = throttle_compute_wait(&bkt);
/* time required to do half an operation */
- result = (int64_t) NANOSECONDS_PER_SECOND / 150 / 2;
+ result = (int64_t) NSEC_PER_SEC / 150 / 2;
g_assert(wait == result);
}
diff --git a/tests/wdt_ib700-test.c b/tests/wdt_ib700-test.c
index 513a533..10a5472 100644
--- a/tests/wdt_ib700-test.c
+++ b/tests/wdt_ib700-test.c
@@ -11,8 +11,7 @@
#include <string.h>
#include "libqtest.h"
#include "qemu/osdep.h"
-
-#define NS_PER_SEC 1000000000ULL
+#include "qemu/timer.h"
static void qmp_check_no_event(void)
{
@@ -41,29 +40,29 @@ static QDict *qmp_get_event(const char *name)
static QDict *ib700_program_and_wait(QTestState *s)
{
- clock_step(NS_PER_SEC * 40);
+ clock_step(NSEC_PER_SEC * 40);
qmp_check_no_event();
/* 2 second limit */
outb(0x443, 14);
/* Ping */
- clock_step(NS_PER_SEC);
+ clock_step(NSEC_PER_SEC);
qmp_check_no_event();
outb(0x443, 14);
/* Disable */
- clock_step(NS_PER_SEC);
+ clock_step(NSEC_PER_SEC);
qmp_check_no_event();
outb(0x441, 1);
- clock_step(3 * NS_PER_SEC);
+ clock_step(3 * NSEC_PER_SEC);
qmp_check_no_event();
/* Enable and let it fire */
outb(0x443, 13);
- clock_step(3 * NS_PER_SEC);
+ clock_step(3 * NSEC_PER_SEC);
qmp_check_no_event();
- clock_step(2 * NS_PER_SEC);
+ clock_step(2 * NSEC_PER_SEC);
return qmp_get_event("WATCHDOG");
}
diff --git a/util/throttle.c b/util/throttle.c
index f976ac7..7678027 100644
--- a/util/throttle.c
+++ b/util/throttle.c
@@ -34,7 +34,7 @@ void throttle_leak_bucket(LeakyBucket *bkt, int64_t delta_ns)
double leak;
/* compute how much to leak */
- leak = (bkt->avg * (double) delta_ns) / NANOSECONDS_PER_SECOND;
+ leak = (bkt->avg * (double) delta_ns) / NSEC_PER_SEC;
/* make the bucket leak */
bkt->level = MAX(bkt->level - leak, 0);
@@ -70,7 +70,7 @@ static void throttle_do_leak(ThrottleState *ts, int64_t now)
*/
static int64_t throttle_do_compute_wait(double limit, double extra)
{
- double wait = extra * NANOSECONDS_PER_SECOND;
+ double wait = extra * NSEC_PER_SEC;
wait /= limit;
return wait;
}
--
2.1.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 3/3] util: Infrastructure for computing recent averages
2015-06-12 13:01 [Qemu-devel] [PATCH 0/3] Add infrastructure to compute timed averages Alberto Garcia
2015-06-12 13:01 ` [Qemu-devel] [PATCH 1/3] timer: Move NANOSECONDS_PER_SECONDS to timer.h Alberto Garcia
2015-06-12 13:01 ` [Qemu-devel] [PATCH 2/3] timer: Use a single definition of NSEC_PER_SEC for the whole codebase Alberto Garcia
@ 2015-06-12 13:01 ` Alberto Garcia
2015-06-26 9:09 ` [Qemu-devel] [PATCH 0/3] Add infrastructure to compute timed averages Stefan Hajnoczi
3 siblings, 0 replies; 6+ messages in thread
From: Alberto Garcia @ 2015-06-12 13:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Paolo Bonzini, Alberto Garcia, qemu-block, Stefan Hajnoczi
This module computes the average of a set of values within a time
window, keeping also track of the minimum and maximum values.
In order to produce more accurate results it works internally by
creating two time windows of the same period, offsetted by half of
that period. Values are accounted on both windows and the data is
always returned from the oldest one.
Signed-off-by: Alberto Garcia <berto@igalia.com>
---
include/qemu/timed-average.h | 58 ++++++++++++
tests/Makefile | 4 +
tests/test-timed-average.c | 89 ++++++++++++++++++
util/Makefile.objs | 1 +
util/timed-average.c | 208 +++++++++++++++++++++++++++++++++++++++++++
5 files changed, 360 insertions(+)
create mode 100644 include/qemu/timed-average.h
create mode 100644 tests/test-timed-average.c
create mode 100644 util/timed-average.c
diff --git a/include/qemu/timed-average.h b/include/qemu/timed-average.h
new file mode 100644
index 0000000..b9532e6
--- /dev/null
+++ b/include/qemu/timed-average.h
@@ -0,0 +1,58 @@
+/*
+ * QEMU timed average computation
+ *
+ * Copyright (C) Nodalink, EURL. 2014
+ * Copyright (C) Igalia, S.L. 2015
+ *
+ * Authors:
+ * Benoît Canet <benoit.canet@nodalink.com>
+ * Alberto Garcia <berto@igalia.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) version 3 or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TIMED_AVERAGE_H
+#define TIMED_AVERAGE_H
+
+#include <stdint.h>
+
+#include "qemu/timer.h"
+
+typedef struct TimedAverageWindow {
+ uint64_t min; /* minimum value accounted in the window */
+ uint64_t max; /* maximum value accounted in the window */
+ uint64_t sum; /* sum of all values */
+ uint64_t count; /* number of values */
+ int64_t expiration; /* the end of the current window in ns */
+} TimedAverageWindow;
+
+typedef struct TimedAverage {
+ uint64_t period; /* period in nanoseconds */
+ TimedAverageWindow windows[2]; /* two overlapping windows of with
+ * an offset of period / 2 between them */
+ unsigned current; /* the current window index: it's also the
+ * oldest window index */
+ QEMUClockType clock_type; /* the clock used */
+} TimedAverage;
+
+void timed_average_init(TimedAverage *ta, QEMUClockType clock_type,
+ unsigned period);
+
+void timed_average_account(TimedAverage *ta, uint64_t value);
+
+uint64_t timed_average_min(TimedAverage *ta);
+uint64_t timed_average_avg(TimedAverage *ta);
+uint64_t timed_average_max(TimedAverage *ta);
+
+#endif
diff --git a/tests/Makefile b/tests/Makefile
index c5e4744..9109b61 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -72,6 +72,7 @@ check-unit-y += tests/test-qemu-opts$(EXESUF)
gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c
check-unit-y += tests/test-write-threshold$(EXESUF)
gcov-files-test-write-threshold-y = block/write-threshold.c
+check-unit-y += tests/test-timed-average$(EXESUF)
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@@ -301,6 +302,9 @@ tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
migration/qemu-file-unix.o qjson.o \
$(qom-core-obj) \
libqemuutil.a libqemustub.a
+tests/test-timed-average$(EXESUF): tests/test-timed-average.o qemu-timer.o \
+ libqemuutil.a stubs/clock-warp.o stubs/cpu-get-icount.o \
+ stubs/notify-event.o
tests/test-qapi-types.c tests/test-qapi-types.h :\
$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
diff --git a/tests/test-timed-average.c b/tests/test-timed-average.c
new file mode 100644
index 0000000..abea61c
--- /dev/null
+++ b/tests/test-timed-average.c
@@ -0,0 +1,89 @@
+/*
+ * Timed average computation tests
+ *
+ * Copyright Nodalink, EURL. 2014
+ *
+ * Authors:
+ * Benoît Canet <benoit.canet@nodalink.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <unistd.h>
+
+#include "qemu/timed-average.h"
+
+static int64_t my_clock_value;
+
+int64_t cpu_get_clock(void)
+{
+ return my_clock_value;
+}
+
+static void account(TimedAverage *ta)
+{
+ timed_average_account(ta, 1);
+ timed_average_account(ta, 5);
+ timed_average_account(ta, 2);
+ timed_average_account(ta, 4);
+ timed_average_account(ta, 3);
+}
+
+static void test_average(void)
+{
+ TimedAverage ta;
+ uint64_t result;
+ int i;
+
+ /* we will compute some average on a period of 1 second */
+ timed_average_init(&ta, QEMU_CLOCK_VIRTUAL, 1);
+
+ result = timed_average_min(&ta);
+ g_assert(result == 0);
+ result = timed_average_avg(&ta);
+ g_assert(result == 0);
+ result = timed_average_max(&ta);
+ g_assert(result == 0);
+
+ for (i = 0; i < 100; i++) {
+ account(&ta);
+ result = timed_average_min(&ta);
+ g_assert(result == 1);
+ result = timed_average_avg(&ta);
+ g_assert(result == 3);
+ result = timed_average_max(&ta);
+ g_assert(result == 5);
+ my_clock_value += NSEC_PER_SEC / 10;
+ }
+
+ my_clock_value += NSEC_PER_SEC * 100;
+
+ result = timed_average_min(&ta);
+ g_assert(result == 0);
+ result = timed_average_avg(&ta);
+ g_assert(result == 0);
+ result = timed_average_max(&ta);
+ g_assert(result == 0);
+
+ for (i = 0; i < 100; i++) {
+ account(&ta);
+ result = timed_average_min(&ta);
+ g_assert(result == 1);
+ result = timed_average_avg(&ta);
+ g_assert(result == 3);
+ result = timed_average_max(&ta);
+ g_assert(result == 5);
+ my_clock_value += NSEC_PER_SEC / 10;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ /* tests in the same order as the header function declarations */
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/timed-average/average", test_average);
+ return g_test_run();
+}
+
diff --git a/util/Makefile.objs b/util/Makefile.objs
index ceaba30..b4e304b 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -18,3 +18,4 @@ util-obj-y += getauxval.o
util-obj-y += readline.o
util-obj-y += rfifolock.o
util-obj-y += rcu.o
+util-obj-y += timed-average.o
diff --git a/util/timed-average.c b/util/timed-average.c
new file mode 100644
index 0000000..d4d3a3f
--- /dev/null
+++ b/util/timed-average.c
@@ -0,0 +1,208 @@
+/*
+ * QEMU timed average computation
+ *
+ * Copyright (C) Nodalink, EURL. 2014
+ * Copyright (C) Igalia, S.L. 2015
+ *
+ * Authors:
+ * Benoît Canet <benoit.canet@nodalink.com>
+ * Alberto Garcia <berto@igalia.com>
+ *
+ * This program is free sofware: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Sofware Foundation, either version 2 of the License, or
+ * (at your option) version 3 or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+
+#include "qemu/timed-average.h"
+
+/* This module computes an average of a set of values within a time
+ * window.
+ *
+ * Algorithm:
+ *
+ * - Create two windows with a certain expiration period, and
+ * offsetted by period / 2.
+ * - Each time you want to account a new value, do it in both windows.
+ * - The minimum / maximum / average values are always returned from
+ * the oldest window.
+ *
+ * Example:
+ *
+ * t=0 |t=0.5 |t=1 |t=1.5 |t=2
+ * wnd0: [0,0.5)|wnd0: [0.5,1.5) | |wnd0: [1.5,2.5) |
+ * wnd1: [0,1) | |wnd1: [1,2) | |
+ *
+ * Values are returned from:
+ *
+ * wnd0---------|wnd1------------|wnd0---------|wnd1-------------|
+ */
+
+/* Update the expiration of a time window
+ *
+ * @w: the window used
+ * @now: the current time in nanoseconds
+ * @period: the expiration period in nanoseconds
+ */
+static void update_expiration(TimedAverageWindow *w, int64_t now,
+ int64_t period)
+{
+ /* time elapsed since the last theoretical expiration */
+ int64_t elapsed = (now - w->expiration) % period;
+ /* time remaininging until the next expiration */
+ int64_t remaining = period - elapsed;
+ /* compute expiration */
+ w->expiration = now + remaining;
+}
+
+/* Reset a window
+ *
+ * @w: the window to reset
+ */
+static void window_reset(TimedAverageWindow *w)
+{
+ w->min = UINT64_MAX;
+ w->max = 0;
+ w->sum = 0;
+ w->count = 0;
+}
+
+/* Get the current window (that is, the one with the earliest
+ * expiration time).
+ *
+ * @ta: the TimedAverage structure
+ * @ret: a pointer to the current window
+ */
+static TimedAverageWindow *current_window(TimedAverage *ta)
+{
+ return &ta->windows[ta->current];
+}
+
+/* Initialize a TimedAverage structure
+ *
+ * @ta: the TimedAverage structure
+ * @clock_type: the type of clock to use
+ * @period: the time window period in seconds
+ */
+void timed_average_init(TimedAverage *ta, QEMUClockType clock_type,
+ unsigned period)
+{
+ int64_t now = qemu_clock_get_ns(clock_type);
+
+ /* Returned values are from the oldest window, so they belong to
+ * the interval [ta->period/2,ta->period). By adjusting the
+ * requested period by 4/3, we guarantee that they're in the
+ * interval [2/3 period,4/3 period), closer to the requested
+ * period on average */
+ ta->period = (uint64_t) period * NSEC_PER_SEC * 4 / 3;
+ ta->clock_type = clock_type;
+ ta->current = 0;
+
+ window_reset(&ta->windows[0]);
+ window_reset(&ta->windows[1]);
+
+ /* Both windows are offsetted by half a period */
+ ta->windows[0].expiration = now + ta->period / 2;
+ ta->windows[1].expiration = now + ta->period;
+}
+
+/* Check if the time windows have expired, updating their counters and
+ * expiration time if that's the case.
+ *
+ * @ta: the TimedAverage structure
+ */
+static void check_expirations(TimedAverage *ta)
+{
+ int64_t now = qemu_clock_get_ns(ta->clock_type);
+ int i;
+
+ /* Check if the windows have expired */
+ for (i = 0; i < 2; i++) {
+ TimedAverageWindow *w = &ta->windows[i];
+ if (w->expiration <= now) {
+ window_reset(w);
+ update_expiration(w, now, ta->period);
+ }
+ }
+
+ /* Make ta->current point to the oldest window */
+ if (ta->windows[0].expiration < ta->windows[1].expiration) {
+ ta->current = 0;
+ } else {
+ ta->current = 1;
+ }
+}
+
+/* Account a value
+ *
+ * @ta: the TimedAverage structure
+ * @value: the value to account
+ */
+void timed_average_account(TimedAverage *ta, uint64_t value)
+{
+ int i;
+ check_expirations(ta);
+
+ /* Do the accouting in both windows at the same time */
+ for (i = 0; i < 2; i++) {
+ TimedAverageWindow *w = &ta->windows[i];
+
+ w->sum += value;
+ w->count++;
+
+ if (value < w->min) {
+ w->min = value;
+ }
+
+ if (value > w->max) {
+ w->max = value;
+ }
+ }
+}
+
+/* Get the minimum value
+ *
+ * @ta: the TimedAverage structure
+ * @ret: the minimum value
+ */
+uint64_t timed_average_min(TimedAverage *ta)
+{
+ TimedAverageWindow *w;
+ check_expirations(ta);
+ w = current_window(ta);
+ return w->min < UINT64_MAX ? w->min : 0;
+}
+
+/* Get the average value
+ *
+ * @ta: the TimedAverage structure
+ * @ret: the average value
+ */
+uint64_t timed_average_avg(TimedAverage *ta)
+{
+ TimedAverageWindow *w;
+ check_expirations(ta);
+ w = current_window(ta);
+ return w->count > 0 ? w->sum / w->count : 0;
+}
+
+/* Get the maximum value
+ *
+ * @ta: the TimedAverage structure
+ * @ret: the maximum value
+ */
+uint64_t timed_average_max(TimedAverage *ta)
+{
+ check_expirations(ta);
+ return current_window(ta)->max;
+}
--
2.1.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH 0/3] Add infrastructure to compute timed averages
2015-06-12 13:01 [Qemu-devel] [PATCH 0/3] Add infrastructure to compute timed averages Alberto Garcia
` (2 preceding siblings ...)
2015-06-12 13:01 ` [Qemu-devel] [PATCH 3/3] util: Infrastructure for computing recent averages Alberto Garcia
@ 2015-06-26 9:09 ` Stefan Hajnoczi
2015-06-26 9:18 ` Alberto Garcia
3 siblings, 1 reply; 6+ messages in thread
From: Stefan Hajnoczi @ 2015-06-26 9:09 UTC (permalink / raw)
To: Alberto Garcia; +Cc: Paolo Bonzini, qemu-devel, qemu-block
[-- Attachment #1: Type: text/plain, Size: 1811 bytes --]
On Fri, Jun 12, 2015 at 04:01:28PM +0300, Alberto Garcia wrote:
> This series adds a new module that can be used to compute the average
> of a set of values in a certain period of time. This will be used by
> the accounting code to obtain statistics such as the min / max /
> average latency of I/O commands.
>
> This is based on Benoît's code, originally written last year.
>
> Regards,
>
> Berto
>
> Alberto Garcia (3):
> timer: Move NANOSECONDS_PER_SECONDS to timer.h
> timer: Use a single definition of NSEC_PER_SEC for the whole codebase
> util: Infrastructure for computing recent averages
>
> hw/ppc/ppc.c | 2 -
> hw/ppc/spapr_rtc.c | 3 +-
> hw/timer/mc146818rtc.c | 1 -
> hw/usb/hcd-ehci.c | 2 +-
> include/qemu/throttle.h | 2 -
> include/qemu/timed-average.h | 58 ++++++++++++
> include/qemu/timer.h | 2 +
> tests/Makefile | 4 +
> tests/rtl8139-test.c | 10 +--
> tests/test-throttle.c | 8 +-
> tests/test-timed-average.c | 89 ++++++++++++++++++
> tests/wdt_ib700-test.c | 15 ++--
> util/Makefile.objs | 1 +
> util/throttle.c | 4 +-
> util/timed-average.c | 208 +++++++++++++++++++++++++++++++++++++++++++
> 15 files changed, 382 insertions(+), 27 deletions(-)
> create mode 100644 include/qemu/timed-average.h
> create mode 100644 tests/test-timed-average.c
> create mode 100644 util/timed-average.c
Thanks, applied patches 1 & 2 to my block tree:
https://github.com/stefanha/qemu/commits/block
Patch 3 is going to be unused in QEMU 2.4 for I'm holding off on merging
it. Please resend it together with the accounting series so it can be
merged for QEMU 2.5.
Thanks,
Stefan
[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread