Skip to contentSkip to conversation

Add infrastructure to compute timed averages

PATCH Applied Alberto Garcia 2 participants 6 messages Jun 12, 2015 – Jun 26, 2015

lore
Share & tools
lore
#0 lore raw

cover Add infrastructure to compute timed averages

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
Signature · 1 line
2.1.4
#1 lore raw

PATCH 1/3 timer: Move NANOSECONDS_PER_SECONDS to timer.h

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.

---
 include/qemu/throttle.h | 2 --
 include/qemu/timer.h    | 2 ++
 2 files changed, 2 insertions(+), 2 deletions(-)
include/qemu/throttle.h +0 -2
index b890613..1c639d2 100644
@@ -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,
include/qemu/timer.h +2 -0
index e5bd494..1f1e56b 100644
@@ -5,6 +5,8 @@
 #include "qemu-common.h"
 #include "qemu/notify.h"
 
+#define NANOSECONDS_PER_SECOND 1000000000LL
+
 /* timers */
 
 #define SCALE_MS 1000000
Signature · 1 line
2.1.4
#2 lore raw

PATCH 2/3 timer: Use a single definition of NSEC_PER_SEC for the whole codebase

In reply to Alberto Garcia
---
 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(-)
hw/ppc/ppc.c +0 -2
index 99db56c..2a4b8e1 100644
@@ -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);
 
hw/ppc/spapr_rtc.c +1 -2
index 83eb7c1..9da3746 100644
@@ -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);
hw/timer/mc146818rtc.c +0 -1
index f2b77fa..41563be 100644
@@ -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
hw/usb/hcd-ehci.c +1 -1
index d4d7547..d7cd40b 100644
@@ -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
include/qemu/timer.h +1 -1
index 1f1e56b..72a2529 100644
@@ -5,7 +5,7 @@
 #include "qemu-common.h"
 #include "qemu/notify.h"
 
-#define NANOSECONDS_PER_SECOND 1000000000LL
+#define NSEC_PER_SEC 1000000000LL
 
 /* timers */
 
tests/rtl8139-test.c +5 -5
index 4e0bf02..3bff0e3 100644
@@ -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;
tests/test-throttle.c +4 -4
index d8ba415..00e4c70 100644
@@ -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);
 }
 
tests/wdt_ib700-test.c +7 -8
index 513a533..10a5472 100644
@@ -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");
 }
 
util/throttle.c +2 -2
index f976ac7..7678027 100644
@@ -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;
 }
Signature · 1 line
2.1.4
#3 lore raw

PATCH 3/3 util: Infrastructure for computing recent averages

In reply to Alberto Garcia

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.

---
 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
include/qemu/timed-average.h new file +58 -0
new file mode 100644
index 0000000..b9532e6
@@ -0,0 +1,58 @@
+/*
+ * QEMU timed average computation
+ *
+ * Copyright (C) Nodalink, EURL. 2014
+ * Copyright (C) Igalia, S.L. 2015
+ *
+ * Authors:
+ *   Benoît Canet <[email protected]>
+ *   Alberto Garcia <[email protected]>
+ *
+ * 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
tests/Makefile +4 -0
index c5e4744..9109b61 100644
@@ -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)
tests/test-timed-average.c new file +89 -0

89 lines not on this page · raw message

util/Makefile.objs +1 -0
index ceaba30..b4e304b 100644
@@ -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
util/timed-average.c new file +208 -0

208 lines not on this page · raw message

Signature · 1 line
2.1.4
#4 lore raw
In reply to Alberto Garcia
Quoted 27 lines · Alberto Garcia

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 ++++++++++++++++++
Quoted 8 lines
 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

#5 lore raw
Quoted 6 lines · Stefan Hajnoczi

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,

I'm actually about to finish the work on the accounting series. Shall I try to send it these days or should I bettter wait until QEMU 2.4 is released?

Berto