Skip to contentSkip to conversation

cfq: Fixes for unaccounted_time variable

PATCH Applied Justin TerAvest 3 participants 7 messages Mar 22, 2011

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover cfq: Fixes for unaccounted_time variable

This should fix both issues that Vivek pointed out:
* We can't set active queue at preempt time, because select queue might select a different queue than the one we chose to preempt.
* Move the new variable to only be exported when debugging options are

    on.
#1 lore raw

PATCH 1/2 cfq-iosched: Don't set active queue in preempt

Commit "Add unaccounted time to timeslice_used" changed the behavior of cfq_preempt_queue to set cfqq active. Vivek pointed out that other preemption rules might get involved, so we shouldn't manually set which queue is active.

This cleans up the code to just clear the queue stats at preemption time.

---
 block/cfq-iosched.c |   39 +++++++++++++++++++++++----------------
 1 files changed, 23 insertions(+), 16 deletions(-)
block/cfq-iosched.c +23 -16
index 12e380b..69208d7 100644
@@ -1620,27 +1620,33 @@ static inline void cfq_del_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 	cfq_blkiocg_update_idle_time_stats(&cfqq->cfqg->blkg);
 }
 
+static void cfq_clear_queue_stats(struct cfq_data *cfqd,
+				  struct cfq_queue *cfqq)
+{
+	cfq_blkiocg_update_avg_queue_size_stats(&cfqq->cfqg->blkg);
+	cfqq->slice_start = 0;
+	cfqq->dispatch_start = jiffies;
+	cfqq->allocated_slice = 0;
+	cfqq->slice_end = 0;
+	cfqq->slice_dispatch = 0;
+	cfqq->nr_sectors = 0;
+
+	cfq_clear_cfqq_wait_request(cfqq);
+	cfq_clear_cfqq_must_dispatch(cfqq);
+	cfq_clear_cfqq_must_alloc_slice(cfqq);
+	cfq_clear_cfqq_fifo_expire(cfqq);
+	cfq_mark_cfqq_slice_new(cfqq);
+
+	cfq_del_timer(cfqd, cfqq);
+}
+
 static void __cfq_set_active_queue(struct cfq_data *cfqd,
 				   struct cfq_queue *cfqq)
 {
 	if (cfqq) {
 		cfq_log_cfqq(cfqd, cfqq, "set_active wl_prio:%d wl_type:%d",
 				cfqd->serving_prio, cfqd->serving_type);
-		cfq_blkiocg_update_avg_queue_size_stats(&cfqq->cfqg->blkg);
-		cfqq->slice_start = 0;
-		cfqq->dispatch_start = jiffies;
-		cfqq->allocated_slice = 0;
-		cfqq->slice_end = 0;
-		cfqq->slice_dispatch = 0;
-		cfqq->nr_sectors = 0;
-
-		cfq_clear_cfqq_wait_request(cfqq);
-		cfq_clear_cfqq_must_dispatch(cfqq);
-		cfq_clear_cfqq_must_alloc_slice(cfqq);
-		cfq_clear_cfqq_fifo_expire(cfqq);
-		cfq_mark_cfqq_slice_new(cfqq);
-
-		cfq_del_timer(cfqd, cfqq);
+		cfq_clear_queue_stats(cfqd, cfqq);
 	}
 
 	cfqd->active_queue = cfqq;
@@ -3332,7 +3338,8 @@ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 	BUG_ON(!cfq_cfqq_on_rr(cfqq));
 
 	cfq_service_tree_add(cfqd, cfqq, 1);
-	__cfq_set_active_queue(cfqd, cfqq);
+
+	cfq_clear_queue_stats(cfqd, cfqq);
 }
 
 /*
Signature · 1 line
1.7.3.1
#2 lore raw

Re: [PATCH 1/2] cfq-iosched: Don't set active queue in preempt

Quoted 67 lines · Justin TerAvest

Commit "Add unaccounted time to timeslice_used" changed the behavior of cfq_preempt_queue to set cfqq active. Vivek pointed out that other preemption rules might get involved, so we shouldn't manually set which queue is active.

This cleans up the code to just clear the queue stats at preemption time.

---
 block/cfq-iosched.c |   39 +++++++++++++++++++++++----------------
 1 files changed, 23 insertions(+), 16 deletions(-)
block/cfq-iosched.c +21 -15
index 12e380b..69208d7 100644
@@ -1620,27 +1620,33 @@ static inline void cfq_del_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 	cfq_blkiocg_update_idle_time_stats(&cfqq->cfqg->blkg);
 }
 
+static void cfq_clear_queue_stats(struct cfq_data *cfqd,
+				  struct cfq_queue *cfqq)
+{
+	cfq_blkiocg_update_avg_queue_size_stats(&cfqq->cfqg->blkg);
+	cfqq->slice_start = 0;
+	cfqq->dispatch_start = jiffies;
+	cfqq->allocated_slice = 0;
+	cfqq->slice_end = 0;
+	cfqq->slice_dispatch = 0;
+	cfqq->nr_sectors = 0;
+
+	cfq_clear_cfqq_wait_request(cfqq);
+	cfq_clear_cfqq_must_dispatch(cfqq);
+	cfq_clear_cfqq_must_alloc_slice(cfqq);
+	cfq_clear_cfqq_fifo_expire(cfqq);
+	cfq_mark_cfqq_slice_new(cfqq);
+
+	cfq_del_timer(cfqd, cfqq);
+}
+
 static void __cfq_set_active_queue(struct cfq_data *cfqd,
 				   struct cfq_queue *cfqq)
 {
 	if (cfqq) {
 		cfq_log_cfqq(cfqd, cfqq, "set_active wl_prio:%d wl_type:%d",
 				cfqd->serving_prio, cfqd->serving_type);
-		cfq_blkiocg_update_avg_queue_size_stats(&cfqq->cfqg->blkg);
-		cfqq->slice_start = 0;
-		cfqq->dispatch_start = jiffies;
-		cfqq->allocated_slice = 0;
-		cfqq->slice_end = 0;
-		cfqq->slice_dispatch = 0;
-		cfqq->nr_sectors = 0;
-
-		cfq_clear_cfqq_wait_request(cfqq);
-		cfq_clear_cfqq_must_dispatch(cfqq);
-		cfq_clear_cfqq_must_alloc_slice(cfqq);
-		cfq_clear_cfqq_fifo_expire(cfqq);
-		cfq_mark_cfqq_slice_new(cfqq);
-
-		cfq_del_timer(cfqd, cfqq);
+		cfq_clear_queue_stats(cfqd, cfqq);
 	}
 
 	cfqd->active_queue = cfqq;

block/cfq-iosched.c static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) · line 3342

Quoted 6 lines
block/cfq-iosched.c +2 -1
@@ -3332,7 +3338,8 @@ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 	BUG_ON(!cfq_cfqq_on_rr(cfqq));
 
 	cfq_service_tree_add(cfqd, cfqq, 1);
-	__cfq_set_active_queue(cfqd, cfqq);
+
+	cfq_clear_queue_stats(cfqd, cfqq);

Hi Justin,

Why do we have to clear queue stats here for the preempting queue?

Especially look at cfqq->dispatch_start = jiffies. We have not started the dispatch yet. When this queue is selected next, then we will start the dispatch.

So this patch has introduced another bug now. Now after preemption if we don't select this group, then we have a queue with wrong dispatch start and that will result in huge slice_used for the queue and it will not get its fair share.

Thanks
Vivek

#3 lore raw

Re: [PATCH 1/2] cfq-iosched: Don't set active queue in preempt

Quoted 79 lines · Vivek Goyal
Quoted 67 lines · Justin TerAvest

Commit "Add unaccounted time to timeslice_used" changed the behavior of cfq_preempt_queue to set cfqq active. Vivek pointed out that other preemption rules might get involved, so we shouldn't manually set which queue is active.

This cleans up the code to just clear the queue stats at preemption time.

---
 block/cfq-iosched.c |   39 +++++++++++++++++++++++----------------

 1 files changed, 23 insertions(+), 16 deletions(-)
block/cfq-iosched.c +21 -15
index 12e380b..69208d7 100644
@@ -1620,27 +1620,33 @@ static inline void cfq_del_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
       cfq_blkiocg_update_idle_time_stats(&cfqq->cfqg->blkg);
  }
 
+static void cfq_clear_queue_stats(struct cfq_data *cfqd,
+                               struct cfq_queue *cfqq)
+{
+     cfq_blkiocg_update_avg_queue_size_stats(&cfqq->cfqg->blkg);
+     cfqq->slice_start = 0;
+     cfqq->dispatch_start = jiffies;
+     cfqq->allocated_slice = 0;
+     cfqq->slice_end = 0;
+     cfqq->slice_dispatch = 0;
+     cfqq->nr_sectors = 0;
+
+     cfq_clear_cfqq_wait_request(cfqq);
+     cfq_clear_cfqq_must_dispatch(cfqq);
+     cfq_clear_cfqq_must_alloc_slice(cfqq);
+     cfq_clear_cfqq_fifo_expire(cfqq);
+     cfq_mark_cfqq_slice_new(cfqq);
+
+     cfq_del_timer(cfqd, cfqq);
+}
+
  static void __cfq_set_active_queue(struct cfq_data *cfqd,
                                  struct cfq_queue *cfqq)
  {
       if (cfqq) {
               cfq_log_cfqq(cfqd, cfqq, "set_active wl_prio:%d wl_type:%d",
                               cfqd->serving_prio, cfqd->serving_type);
-             cfq_blkiocg_update_avg_queue_size_stats(&cfqq->cfqg->blkg);
-             cfqq->slice_start = 0;
-             cfqq->dispatch_start = jiffies;
-             cfqq->allocated_slice = 0;
-             cfqq->slice_end = 0;
-             cfqq->slice_dispatch = 0;
-             cfqq->nr_sectors = 0;
-
-             cfq_clear_cfqq_wait_request(cfqq);
-             cfq_clear_cfqq_must_dispatch(cfqq);
-             cfq_clear_cfqq_must_alloc_slice(cfqq);
-             cfq_clear_cfqq_fifo_expire(cfqq);
-             cfq_mark_cfqq_slice_new(cfqq);
-
-             cfq_del_timer(cfqd, cfqq);
+             cfq_clear_queue_stats(cfqd, cfqq);
       }
 
       cfqd->active_queue = cfqq;

block/cfq-iosched.c static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) · line 3342

Quoted 6 lines
block/cfq-iosched.c +2 -1
@@ -3332,7 +3338,8 @@ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
       BUG_ON(!cfq_cfqq_on_rr(cfqq));
 
       cfq_service_tree_add(cfqd, cfqq, 1);
-     __cfq_set_active_queue(cfqd, cfqq);
+
+     cfq_clear_queue_stats(cfqd, cfqq);

Hi Justin,

Why do we have to clear queue stats here for the preempting queue?

Quoted 8 lines

Especially look at cfqq->dispatch_start = jiffies. We have not started the dispatch yet. When this queue is selected next, then we will start the dispatch.

So this patch has introduced another bug now. Now after preemption if we don't select this group, then we have a queue with wrong dispatch start and that will result in huge slice_used for the queue and it will not get its fair share.

Hi Vivek,

Ugh, you're right. Sorry, I had some bad ideas in my head for how preemption worked that clearly aren't true.
I think that if the stats aren't cleared here, everything should then be fine because jiffies will then be picked up when the active queue is set. Does that sound sane to you?

Thanks for explaining this problem.

Justin

Quoted 4 lines

Thanks
Vivek

#4 lore raw

Re: [PATCH 1/2] cfq-iosched: Don't set active queue in preempt

On Tue, Mar 22, 2011 at 02:58:48PM -0700, Justin TerAvest wrote:
[..]

Quoted 22 lines
Quoted 13 lines

block/cfq-iosched.c static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) · line 3342

Quoted 8 lines

      cfqd->active_queue = cfqq;

block/cfq-iosched.c +2 -1
@@ -3332,7 +3338,8 @@ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
       BUG_ON(!cfq_cfqq_on_rr(cfqq));
 
       cfq_service_tree_add(cfqd, cfqq, 1);
-     __cfq_set_active_queue(cfqd, cfqq);
+
+     cfq_clear_queue_stats(cfqd, cfqq);

Hi Justin,

Why do we have to clear queue stats here for the preempting queue?

Quoted 8 lines

Especially look at cfqq->dispatch_start = jiffies. We have not started the dispatch yet. When this queue is selected next, then we will start the dispatch.

So this patch has introduced another bug now. Now after preemption if we don't select this group, then we have a queue with wrong dispatch start and that will result in huge slice_used for the queue and it will not get its fair share.

Quoted 8 lines

Hi Vivek,

Ugh, you're right. Sorry, I had some bad ideas in my head for how preemption worked that clearly aren't true.
I think that if the stats aren't cleared here, everything should then be fine because jiffies will then be picked up when the active queue is set. Does that sound sane to you?

Yes, that makes sense. Primarily you are looking for unaccounted seek time (slice_start - dispatch_start) and dispatch_start will be set when the preempting queue is selected for dispatch. So I don't think you have to clear up anything in cfq_preempt_queue().

Thanks
Vivek

#5 lore raw

PATCH 2/2 blk-cgroup: Only give unaccounted_time under debug

In reply to Justin TerAvest

This change moves unaccounted_time to only be reported when CONFIG_DEBUG_BLK_CGROUP is true.

---
 block/blk-cgroup.c |   20 ++++++++++----------
 1 files changed, 10 insertions(+), 10 deletions(-)
block/blk-cgroup.c +10 -10
index 77ee3c1..2bef570 100644
@@ -605,10 +605,10 @@ static uint64_t blkio_get_stat(struct blkio_group *blkg,
 	if (type == BLKIO_STAT_SECTORS)
 		return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
 					blkg->stats.sectors, cb, dev);
+#ifdef CONFIG_DEBUG_BLK_CGROUP
 	if (type == BLKIO_STAT_UNACCOUNTED_TIME)
 		return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
 					blkg->stats.unaccounted_time, cb, dev);
-#ifdef CONFIG_DEBUG_BLK_CGROUP
 	if (type == BLKIO_STAT_AVG_QUEUE_SIZE) {
 		uint64_t sum = blkg->stats.avg_queue_size_sum;
 		uint64_t samples = blkg->stats.avg_queue_size_samples;
@@ -1111,9 +1111,6 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
 		case BLKIO_PROP_sectors:
 			return blkio_read_blkg_stats(blkcg, cft, cb,
 						BLKIO_STAT_SECTORS, 0);
-		case BLKIO_PROP_unaccounted_time:
-			return blkio_read_blkg_stats(blkcg, cft, cb,
-						BLKIO_STAT_UNACCOUNTED_TIME, 0);
 		case BLKIO_PROP_io_service_bytes:
 			return blkio_read_blkg_stats(blkcg, cft, cb,
 						BLKIO_STAT_SERVICE_BYTES, 1);
@@ -1133,6 +1130,9 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
 			return blkio_read_blkg_stats(blkcg, cft, cb,
 						BLKIO_STAT_QUEUED, 1);
 #ifdef CONFIG_DEBUG_BLK_CGROUP
+		case BLKIO_PROP_unaccounted_time:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_UNACCOUNTED_TIME, 0);
 		case BLKIO_PROP_dequeue:
 			return blkio_read_blkg_stats(blkcg, cft, cb,
 						BLKIO_STAT_DEQUEUE, 0);
@@ -1270,12 +1270,6 @@ struct cftype blkio_files[] = {
 		.read_map = blkiocg_file_read_map,
 	},
 	{
-		.name = "unaccounted_time",
-		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
-				BLKIO_PROP_unaccounted_time),
-		.read_map = blkiocg_file_read_map,
-	},
-	{
 		.name = "io_service_bytes",
 		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
 				BLKIO_PROP_io_service_bytes),
@@ -1396,6 +1390,12 @@ struct cftype blkio_files[] = {
 				BLKIO_PROP_dequeue),
 		.read_map = blkiocg_file_read_map,
 	},
+	{
+		.name = "unaccounted_time",
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_unaccounted_time),
+		.read_map = blkiocg_file_read_map,
+	},
 #endif
 };
 
Signature · 1 line
1.7.3.1
Applied
#6 lore raw
In reply to Justin TerAvest
Quoted 5 lines · Justin TerAvest

This should fix both issues that Vivek pointed out:
* We can't set active queue at preempt time, because select queue might select a different queue than the one we chose to preempt.
* Move the new variable to only be exported when debugging options are

    on.

Thanks, applied.

Signature · 1 line
Jens Axboe