[dm-devel] [PATCH] dm-kcopyd: monitor io activity

Mikulas Patocka mpatocka at redhat.com
Mon May 30 16:40:39 UTC 2011


Hi

Here I'm sending three patches that limit kcopyd speed. There is global 
limit for all kcopyds running in a system. The user can set percentage of 
kcopyd speed in /sys/module/dm_mod/parameters/dm_kcopyd_throttle

Mikulas

---

dm-kcopyd: monitor io activity

There are two activity counters, "total_period" and "io_period".
total_period counts all time ticks, io_period counts timer ticks when
some I/O is active.

Thus, (100 * io_period / total_period) represents the percentage of
time when kcopyd is active.

Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>

---
 drivers/md/dm-kcopyd.c |   67 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

Index: linux-2.6.39-fast/drivers/md/dm-kcopyd.c
===================================================================
--- linux-2.6.39-fast.orig/drivers/md/dm-kcopyd.c	2011-05-30 18:04:08.000000000 +0200
+++ linux-2.6.39-fast/drivers/md/dm-kcopyd.c	2011-05-30 18:07:36.000000000 +0200
@@ -66,6 +66,69 @@ struct dm_kcopyd_client {
 	struct list_head pages_jobs;
 };
 
+static DEFINE_SPINLOCK(activity_spinlock);
+static unsigned long num_io_jobs = 0;
+
+/*
+ * kcopyd is active (100 * io_period / total_period) percent of time.
+ */
+static unsigned io_period = 0;
+static unsigned total_period = 0;
+static unsigned last_jiffies = 0;
+
+/*
+ * IO/IDLE accounting slowly decays after (1 << ACOUNT_INTERVAL_SHIFT) period.
+ * When total_period >= (1 << ACOUNT_INTERVAL_SHIFT) the counters are divided
+ * by 2.
+ */
+#define ACOUNT_INTERVAL_SHIFT		SHIFT_HZ
+
+static void io_job_start(void)
+{
+	unsigned now, difference;
+
+	spin_lock_irq(&activity_spinlock);
+
+	now = jiffies;
+	difference = now - last_jiffies;
+	last_jiffies = now;
+	if (num_io_jobs)
+		io_period += difference;
+	total_period += difference;
+
+	if (unlikely(total_period >= (1 << ACOUNT_INTERVAL_SHIFT))) {
+		int shift = fls(total_period >> ACOUNT_INTERVAL_SHIFT);
+		total_period >>= shift;
+		io_period >>= shift;
+	}
+
+	num_io_jobs++;
+
+	spin_unlock_irq(&activity_spinlock);
+}
+
+static void io_job_finish(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&activity_spinlock, flags);
+
+	num_io_jobs--;
+
+	if (!num_io_jobs) {
+		unsigned now, difference;
+
+		now = jiffies;
+		difference = now - last_jiffies;
+		last_jiffies = now;
+
+		io_period += difference;
+		total_period += difference;
+	}
+
+	spin_unlock_irqrestore(&activity_spinlock, flags);
+}
+
 static void wake(struct dm_kcopyd_client *kc)
 {
 	queue_work(kc->kcopyd_wq, &kc->kcopyd_work);
@@ -324,6 +387,8 @@ static void complete_io(unsigned long er
 	struct kcopyd_job *job = (struct kcopyd_job *) context;
 	struct dm_kcopyd_client *kc = job->kc;
 
+	io_job_finish();
+
 	if (error) {
 		if (job->rw == WRITE)
 			job->write_err |= error;
@@ -365,6 +430,8 @@ static int run_io_job(struct kcopyd_job 
 		.client = job->kc->io_client,
 	};
 
+	io_job_start();
+
 	if (job->rw == READ)
 		r = dm_io(&io_req, 1, &job->source, NULL);
 	else




More information about the dm-devel mailing list