qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Benoît Canet" <benoit.canet@irqsave.net>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, "Benoît Canet" <benoit.canet@irqsave.net>,
	"Benoit Canet" <benoit@irqsave.net>,
	stefanha@redhat.com
Subject: [Qemu-devel] [RFC 2/5] throttle: Add throttle group infrastructure.
Date: Tue, 12 Aug 2014 15:42:24 +0200	[thread overview]
Message-ID: <1407850947-17625-3-git-send-email-benoit.canet@irqsave.net> (raw)
In-Reply-To: <1407850947-17625-1-git-send-email-benoit.canet@irqsave.net>

The throttle_group_incref increment the refcount of a throttle group given it's
name and return the associated throttle state.

The throttle_group_unref is the mirror function for cleaning up.

Signed-off-by: Benoit Canet <benoit@irqsave.net>
---
 include/block/block_int.h      |   1 +
 include/qemu/throttle-groups.h |  43 +++++++++
 util/Makefile.objs             |   1 +
 util/throttle-groups.c         | 195 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 240 insertions(+)
 create mode 100644 include/qemu/throttle-groups.h
 create mode 100644 util/throttle-groups.c

diff --git a/include/block/block_int.h b/include/block/block_int.h
index 2a0c146..6066f63 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -339,6 +339,7 @@ struct BlockDriverState {
     ThrottleTimers throttle_timers; 
     CoQueue      throttled_reqs[2];
     bool         io_limits_enabled;
+    QLIST_ENTRY(BlockDriverState) round_robin;
 
     /* I/O stats (display with "info blockstats"). */
     uint64_t nr_bytes[BDRV_MAX_IOTYPE];
diff --git a/include/qemu/throttle-groups.h b/include/qemu/throttle-groups.h
new file mode 100644
index 0000000..12c56e6
--- /dev/null
+++ b/include/qemu/throttle-groups.h
@@ -0,0 +1,43 @@
+/*
+ * QEMU throttling group infrastructure
+ *
+ * Copyright (C) Nodalink, EURL. 2014
+ *
+ * Author:
+ *   Benoît Canet <benoit.canet@irqsave.net>
+ *
+ * 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 or
+ * (at your option) version 3 of the License.
+ *
+ * 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 THROTTLE_GROUPS_H
+#define THROTTLE_GROUPS_H
+
+#include "qemu/throttle.h"
+#include "block/block_int.h"
+
+ThrottleState *throttle_group_incref(const char *name);
+bool throttle_group_unref(ThrottleState *ts);
+
+void throttle_group_register_bs(ThrottleState *ts, BlockDriverState *bs);
+BlockDriverState *throttle_group_next_bs(BlockDriverState *bs);
+
+void throttle_group_set_token(ThrottleState *ts,
+                              BlockDriverState *token,
+                              bool is_write);
+BlockDriverState *throttle_group_token(ThrottleState *ts, bool is_write);
+
+void throttle_group_lock(ThrottleState *ts);
+void throttle_group_unlock(ThrottleState *ts);
+
+#endif
diff --git a/util/Makefile.objs b/util/Makefile.objs
index 6b3c83b..3c95397 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -12,6 +12,7 @@ util-obj-y += qemu-option.o qemu-progress.o
 util-obj-y += hexdump.o
 util-obj-y += crc32c.o
 util-obj-y += throttle.o
+util-obj-y += throttle-groups.o
 util-obj-y += getauxval.o
 util-obj-y += readline.o
 util-obj-y += rfifolock.o
diff --git a/util/throttle-groups.c b/util/throttle-groups.c
new file mode 100644
index 0000000..153bacc
--- /dev/null
+++ b/util/throttle-groups.c
@@ -0,0 +1,195 @@
+/*
+ * QEMU throttling group infrastructure
+ *
+ * Copyright (C) Nodalink, EURL. 2014
+ *
+ * Author:
+ *   Benoît Canet <benoit.canet@irqsave.net>
+ *
+ * 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 or
+ * (at your option) version 3 of the License.
+ *
+ * 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 "qemu/throttle-groups.h"
+#include "qemu/queue.h"
+#include "qemu/thread.h"
+
+typedef struct ThrottleGroup {
+    char name[32];
+    ThrottleState ts;
+    uint64_t refcount;
+    QTAILQ_ENTRY(ThrottleGroup) list;
+    QLIST_HEAD(, BlockDriverState) head;
+    BlockDriverState *tokens[2]; /* current round-robin tokens */
+    QemuMutex lock; /* Used to synchronize all elements belonging to a group */
+} ThrottleGroup;
+
+static QTAILQ_HEAD(, ThrottleGroup) throttle_groups =
+    QTAILQ_HEAD_INITIALIZER(throttle_groups);
+
+/* increments a ThrottleGroup reference count given it's name
+ *
+ * If no ThrottleGroup is found with the given name a new one is created.
+ *
+ * @name: the name of the ThrottleGroup
+ * @ret:  the ThrottleGroup's ThrottleState address
+ */
+ThrottleState *throttle_group_incref(const char *name)
+{
+    ThrottleGroup *tg;
+
+    /* return the correct ThrottleState if a group with this name exists */
+    QTAILQ_FOREACH(tg, &throttle_groups, list) {
+        /* group not found -> continue */
+        if (strcmp(name, tg->name)) {
+            continue;
+        }
+        /* group found -> increment it's refcount and return ThrottleState */
+        tg->refcount++;
+        return &tg->ts;
+    }
+
+    /* throttle group not found -> prepare new entry */
+    tg = g_new0(ThrottleGroup, 1);
+    throttle_init(&tg->ts);
+    pstrcpy(tg->name, sizeof(tg->name), name);
+    tg->refcount = 1;
+    qemu_mutex_init(&tg->lock);
+    QLIST_INIT(&tg->head);
+
+    /* insert new entry in the list */
+    QTAILQ_INSERT_TAIL(&throttle_groups, tg, list);
+
+    /* return newly allocated ThrottleState */
+    return &tg->ts;
+}
+
+/* decrement a ThrottleGroup given it's ThrottleState address
+ *
+ * When the refcount reach zero the ThrottleGroup is destroyed
+ *
+ * @ts:  The ThrottleState address belonging to the ThrottleGroup to unref
+ * @ret: true on success else false
+ */
+bool throttle_group_unref(ThrottleState *ts)
+{
+    ThrottleGroup *tg;
+    bool found = false;
+
+    /* Find the ThrottleGroup of the given ThrottleState */
+    QTAILQ_FOREACH(tg, &throttle_groups, list) {
+        /* correct group found stop iterating */
+        if (&tg->ts == ts) {
+            qemu_mutex_lock(&tg->lock);
+            found = true;
+            break;
+        }
+    }
+
+    /* If the ThrottleState was not found something is seriously broken */
+    if (!found) {
+        return false;
+    }
+
+    tg->refcount--;
+
+    /* If ThrottleGroup is used keep it. */
+    if (tg->refcount) {
+        qemu_mutex_unlock(&tg->lock);
+        return true;
+    }
+
+    /* Else destroy it */
+    QTAILQ_REMOVE(&throttle_groups, tg, list);
+    qemu_mutex_unlock(&tg->lock);
+    qemu_mutex_destroy(&tg->lock);
+    g_free(tg);
+    return true;
+}
+
+/* Register a BlockDriverState in the doubly linked list
+ *
+ * @ts: the ThrottleState the code is working on
+ * @bs: the BlockDriverState to insert
+ */
+void throttle_group_register_bs(ThrottleState *ts, BlockDriverState *bs)
+{
+    ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
+    QLIST_INSERT_HEAD(&tg->head, bs, round_robin);
+}
+
+/* Return the next BlockDriverState in the round-robin sequence
+ *
+ * This takes care of simulating a circular list
+ *
+ * @bs:  the input current BlockDriverState
+ * @ret: the next BlockDriverState in the sequence
+ */
+BlockDriverState *throttle_group_next_bs(BlockDriverState *bs)
+{
+    ThrottleState *ts = &bs->throttle_state;
+    ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
+    BlockDriverState *next = QLIST_NEXT(bs, round_robin);
+
+    if (!next) {
+        return QLIST_FIRST(&tg->head);
+    }
+
+    return next;
+}
+
+/* Used to set a token BlockDriverState into a ThrottleState's ThrottleGroup
+ *
+ * @ts:       the ThrottleState the code is working on
+ * @token:    the token BlockDriverState to set
+ * @is_write: true if we are talking about write operations else false
+ */
+void throttle_group_set_token(ThrottleState *ts,
+                              BlockDriverState *token,
+                              bool is_write)
+{
+    ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
+    tg->tokens[is_write] = token;
+}
+
+/* Used to get the token BlockDriverState of a ThrottleState's ThrottleGroup
+ *
+ * @ts:  the ThrottleState the code is working on
+ * @ret: the token BlockDriverState that is retrieved
+ * @is_write: true if we are talking about write operations else false
+ */
+BlockDriverState *throttle_group_token(ThrottleState *ts, bool is_write)
+{
+    ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
+    return tg->tokens[is_write];
+}
+
+/* Used to lock a ThrottleState's ThrottleGroup
+ *
+ * @ts:     the ThrottleState the code is working on
+ */
+void throttle_group_lock(ThrottleState *ts)
+{
+    ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
+    qemu_mutex_lock(&tg->lock);
+}
+
+/* Used to unlock a ThrottleState's ThrottleGroup
+ *
+ * @ts:  the ThrottleState the code is working on
+ */
+void throttle_group_unlock(ThrottleState *ts)
+{
+    ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
+    qemu_mutex_unlock(&tg->lock);
+}
-- 
2.1.0.rc1

  parent reply	other threads:[~2014-08-12 13:43 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-12 13:42 [Qemu-devel] [RFC 0/5] Throttle group cooperative round robin scheduling Benoît Canet
2014-08-12 13:42 ` [Qemu-devel] [RFC 1/5] throttle: Extract timers from ThrottleState into a separate ThrottleTimers structure Benoît Canet
2014-08-12 13:42 ` Benoît Canet [this message]
2014-08-12 13:42 ` [Qemu-devel] [RFC 3/5] throttle: Add throttle group infrastructure tests Benoît Canet
2014-08-12 13:42 ` [Qemu-devel] [RFC 4/5] throttle: Prepare to have multiple timers for one ThrottleState Benoît Canet
2014-08-12 13:42 ` [Qemu-devel] [RFC 5/5] throttle: Add throttle group support Benoît Canet

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1407850947-17625-3-git-send-email-benoit.canet@irqsave.net \
    --to=benoit.canet@irqsave.net \
    --cc=benoit@irqsave.net \
    --cc=kwolf@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).