aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorJoe Thornber <ejt@redhat.com>2014-10-22 09:30:58 -0400
committerMike Snitzer <snitzer@redhat.com>2014-11-10 15:25:29 -0500
commitb155aa0e5a81ea1f05ff7aced0ec8e34c980c19e (patch)
tree56f73848b2e70f8a9eb4d97d51b742fc93c3ad0f /drivers/md
parent41abc4e1af369bb5438eaee398e3beee690cc8ca (diff)
dm cache policy mq: tweak algorithm that decides when to promote a block
Rather than maintaining a separate promote_threshold variable that we periodically update we now use the hit count of the oldest clean block. Also add a fudge factor to discourage demoting dirty blocks. With some tests this has a sizeable difference, because the old code was too eager to demote blocks. For example, device-mapper-test-suite's git_extract_cache_quick test goes from taking 190 seconds, to 142 (linear on spindle takes 250). Signed-off-by: Joe Thornber <ejt@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-cache-policy-mq.c75
1 files changed, 50 insertions, 25 deletions
diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c
index 0e385e40909e..334d098d720d 100644
--- a/drivers/md/dm-cache-policy-mq.c
+++ b/drivers/md/dm-cache-policy-mq.c
@@ -181,24 +181,30 @@ static void queue_shift_down(struct queue *q)
181 * Gives us the oldest entry of the lowest popoulated level. If the first 181 * Gives us the oldest entry of the lowest popoulated level. If the first
182 * level is emptied then we shift down one level. 182 * level is emptied then we shift down one level.
183 */ 183 */
184static struct list_head *queue_pop(struct queue *q) 184static struct list_head *queue_peek(struct queue *q)
185{ 185{
186 unsigned level; 186 unsigned level;
187 struct list_head *r;
188 187
189 for (level = 0; level < NR_QUEUE_LEVELS; level++) 188 for (level = 0; level < NR_QUEUE_LEVELS; level++)
190 if (!list_empty(q->qs + level)) { 189 if (!list_empty(q->qs + level))
191 r = q->qs[level].next; 190 return q->qs[level].next;
192 list_del(r);
193 191
194 /* have we just emptied the bottom level? */ 192 return NULL;
195 if (level == 0 && list_empty(q->qs)) 193}
196 queue_shift_down(q);
197 194
198 return r; 195static struct list_head *queue_pop(struct queue *q)
199 } 196{
197 struct list_head *r = queue_peek(q);
200 198
201 return NULL; 199 if (r) {
200 list_del(r);
201
202 /* have we just emptied the bottom level? */
203 if (list_empty(q->qs))
204 queue_shift_down(q);
205 }
206
207 return r;
202} 208}
203 209
204static struct list_head *list_pop(struct list_head *lh) 210static struct list_head *list_pop(struct list_head *lh)
@@ -383,13 +389,6 @@ struct mq_policy {
383 unsigned generation; 389 unsigned generation;
384 unsigned generation_period; /* in lookups (will probably change) */ 390 unsigned generation_period; /* in lookups (will probably change) */
385 391
386 /*
387 * Entries in the pre_cache whose hit count passes the promotion
388 * threshold move to the cache proper. Working out the correct
389 * value for the promotion_threshold is crucial to this policy.
390 */
391 unsigned promote_threshold;
392
393 unsigned discard_promote_adjustment; 392 unsigned discard_promote_adjustment;
394 unsigned read_promote_adjustment; 393 unsigned read_promote_adjustment;
395 unsigned write_promote_adjustment; 394 unsigned write_promote_adjustment;
@@ -406,6 +405,7 @@ struct mq_policy {
406#define DEFAULT_DISCARD_PROMOTE_ADJUSTMENT 1 405#define DEFAULT_DISCARD_PROMOTE_ADJUSTMENT 1
407#define DEFAULT_READ_PROMOTE_ADJUSTMENT 4 406#define DEFAULT_READ_PROMOTE_ADJUSTMENT 4
408#define DEFAULT_WRITE_PROMOTE_ADJUSTMENT 8 407#define DEFAULT_WRITE_PROMOTE_ADJUSTMENT 8
408#define DISCOURAGE_DEMOTING_DIRTY_THRESHOLD 128
409 409
410/*----------------------------------------------------------------*/ 410/*----------------------------------------------------------------*/
411 411
@@ -518,6 +518,12 @@ static struct entry *pop(struct mq_policy *mq, struct queue *q)
518 return e; 518 return e;
519} 519}
520 520
521static struct entry *peek(struct queue *q)
522{
523 struct list_head *h = queue_peek(q);
524 return h ? container_of(h, struct entry, list) : NULL;
525}
526
521/* 527/*
522 * Has this entry already been updated? 528 * Has this entry already been updated?
523 */ 529 */
@@ -570,10 +576,6 @@ static void check_generation(struct mq_policy *mq)
570 break; 576 break;
571 } 577 }
572 } 578 }
573
574 mq->promote_threshold = nr ? total / nr : 1;
575 if (mq->promote_threshold * nr < total)
576 mq->promote_threshold++;
577 } 579 }
578} 580}
579 581
@@ -641,6 +643,30 @@ static int demote_cblock(struct mq_policy *mq, dm_oblock_t *oblock)
641} 643}
642 644
643/* 645/*
646 * Entries in the pre_cache whose hit count passes the promotion
647 * threshold move to the cache proper. Working out the correct
648 * value for the promotion_threshold is crucial to this policy.
649 */
650static unsigned promote_threshold(struct mq_policy *mq)
651{
652 struct entry *e;
653
654 if (any_free_cblocks(mq))
655 return 0;
656
657 e = peek(&mq->cache_clean);
658 if (e)
659 return e->hit_count;
660
661 e = peek(&mq->cache_dirty);
662 if (e)
663 return e->hit_count + DISCOURAGE_DEMOTING_DIRTY_THRESHOLD;
664
665 /* This should never happen */
666 return 0;
667}
668
669/*
644 * We modify the basic promotion_threshold depending on the specific io. 670 * We modify the basic promotion_threshold depending on the specific io.
645 * 671 *
646 * If the origin block has been discarded then there's no cost to copy it 672 * If the origin block has been discarded then there's no cost to copy it
@@ -653,7 +679,7 @@ static unsigned adjusted_promote_threshold(struct mq_policy *mq,
653 bool discarded_oblock, int data_dir) 679 bool discarded_oblock, int data_dir)
654{ 680{
655 if (data_dir == READ) 681 if (data_dir == READ)
656 return mq->promote_threshold + mq->read_promote_adjustment; 682 return promote_threshold(mq) + mq->read_promote_adjustment;
657 683
658 if (discarded_oblock && (any_free_cblocks(mq) || any_clean_cblocks(mq))) { 684 if (discarded_oblock && (any_free_cblocks(mq) || any_clean_cblocks(mq))) {
659 /* 685 /*
@@ -663,7 +689,7 @@ static unsigned adjusted_promote_threshold(struct mq_policy *mq,
663 return mq->discard_promote_adjustment; 689 return mq->discard_promote_adjustment;
664 } 690 }
665 691
666 return mq->promote_threshold + mq->write_promote_adjustment; 692 return promote_threshold(mq) + mq->write_promote_adjustment;
667} 693}
668 694
669static bool should_promote(struct mq_policy *mq, struct entry *e, 695static bool should_promote(struct mq_policy *mq, struct entry *e,
@@ -1230,7 +1256,6 @@ static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
1230 mq->tick = 0; 1256 mq->tick = 0;
1231 mq->hit_count = 0; 1257 mq->hit_count = 0;
1232 mq->generation = 0; 1258 mq->generation = 0;
1233 mq->promote_threshold = 0;
1234 mq->discard_promote_adjustment = DEFAULT_DISCARD_PROMOTE_ADJUSTMENT; 1259 mq->discard_promote_adjustment = DEFAULT_DISCARD_PROMOTE_ADJUSTMENT;
1235 mq->read_promote_adjustment = DEFAULT_READ_PROMOTE_ADJUSTMENT; 1260 mq->read_promote_adjustment = DEFAULT_READ_PROMOTE_ADJUSTMENT;
1236 mq->write_promote_adjustment = DEFAULT_WRITE_PROMOTE_ADJUSTMENT; 1261 mq->write_promote_adjustment = DEFAULT_WRITE_PROMOTE_ADJUSTMENT;