aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <axboe@suse.de>2006-03-28 01:59:01 -0500
committerJens Axboe <axboe@suse.de>2006-03-28 01:59:01 -0500
commite2d74ac0664c89757bde8fb18c98cd7bf53da61c (patch)
tree1e858044a9180766eae4ec694d4200c4ae850406
parent329b10bb0feacb7fb9a41389313ff0a51ae56f2a (diff)
[PATCH] [BLOCK] cfq-iosched: change cfq io context linking from list to tree
On setups with many disks, we spend a considerable amount of time looking up the process-disk mapping on each queue of io. Testing with a NULL based block driver, this costs 40-50% reduction in throughput for 1000 disks. Signed-off-by: Jens Axboe <axboe@suse.de>
-rw-r--r--block/cfq-iosched.c205
-rw-r--r--block/ll_rw_blk.c19
-rw-r--r--include/linux/blkdev.h14
3 files changed, 114 insertions, 124 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index bde40a6ae6..bb43a16776 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -1190,19 +1190,19 @@ cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio)
1190 return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT)); 1190 return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
1191} 1191}
1192 1192
1193static void cfq_free_io_context(struct cfq_io_context *cic) 1193static void cfq_free_io_context(struct io_context *ioc)
1194{ 1194{
1195 struct cfq_io_context *__cic; 1195 struct cfq_io_context *__cic;
1196 struct list_head *entry, *next; 1196 struct rb_node *n;
1197 int freed = 1; 1197 int freed = 0;
1198 1198
1199 list_for_each_safe(entry, next, &cic->list) { 1199 while ((n = rb_first(&ioc->cic_root)) != NULL) {
1200 __cic = list_entry(entry, struct cfq_io_context, list); 1200 __cic = rb_entry(n, struct cfq_io_context, rb_node);
1201 rb_erase(&__cic->rb_node, &ioc->cic_root);
1201 kmem_cache_free(cfq_ioc_pool, __cic); 1202 kmem_cache_free(cfq_ioc_pool, __cic);
1202 freed++; 1203 freed++;
1203 } 1204 }
1204 1205
1205 kmem_cache_free(cfq_ioc_pool, cic);
1206 if (atomic_sub_and_test(freed, &ioc_count) && ioc_gone) 1206 if (atomic_sub_and_test(freed, &ioc_count) && ioc_gone)
1207 complete(ioc_gone); 1207 complete(ioc_gone);
1208} 1208}
@@ -1210,8 +1210,7 @@ static void cfq_free_io_context(struct cfq_io_context *cic)
1210static void cfq_trim(struct io_context *ioc) 1210static void cfq_trim(struct io_context *ioc)
1211{ 1211{
1212 ioc->set_ioprio = NULL; 1212 ioc->set_ioprio = NULL;
1213 if (ioc->cic) 1213 cfq_free_io_context(ioc);
1214 cfq_free_io_context(ioc->cic);
1215} 1214}
1216 1215
1217/* 1216/*
@@ -1250,26 +1249,26 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic)
1250 spin_unlock(q->queue_lock); 1249 spin_unlock(q->queue_lock);
1251} 1250}
1252 1251
1253static void cfq_exit_io_context(struct cfq_io_context *cic) 1252static void cfq_exit_io_context(struct io_context *ioc)
1254{ 1253{
1255 struct cfq_io_context *__cic; 1254 struct cfq_io_context *__cic;
1256 struct list_head *entry;
1257 unsigned long flags; 1255 unsigned long flags;
1258 1256 struct rb_node *n;
1259 local_irq_save(flags);
1260 1257
1261 /* 1258 /*
1262 * put the reference this task is holding to the various queues 1259 * put the reference this task is holding to the various queues
1263 */ 1260 */
1264 read_lock(&cfq_exit_lock); 1261 read_lock_irqsave(&cfq_exit_lock, flags);
1265 list_for_each(entry, &cic->list) { 1262
1266 __cic = list_entry(entry, struct cfq_io_context, list); 1263 n = rb_first(&ioc->cic_root);
1264 while (n != NULL) {
1265 __cic = rb_entry(n, struct cfq_io_context, rb_node);
1266
1267 cfq_exit_single_io_context(__cic); 1267 cfq_exit_single_io_context(__cic);
1268 n = rb_next(n);
1268 } 1269 }
1269 1270
1270 cfq_exit_single_io_context(cic); 1271 read_unlock_irqrestore(&cfq_exit_lock, flags);
1271 read_unlock(&cfq_exit_lock);
1272 local_irq_restore(flags);
1273} 1272}
1274 1273
1275static struct cfq_io_context * 1274static struct cfq_io_context *
@@ -1278,10 +1277,10 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
1278 struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask); 1277 struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
1279 1278
1280 if (cic) { 1279 if (cic) {
1281 INIT_LIST_HEAD(&cic->list); 1280 RB_CLEAR(&cic->rb_node);
1281 cic->key = NULL;
1282 cic->cfqq[ASYNC] = NULL; 1282 cic->cfqq[ASYNC] = NULL;
1283 cic->cfqq[SYNC] = NULL; 1283 cic->cfqq[SYNC] = NULL;
1284 cic->key = NULL;
1285 cic->last_end_request = jiffies; 1284 cic->last_end_request = jiffies;
1286 cic->ttime_total = 0; 1285 cic->ttime_total = 0;
1287 cic->ttime_samples = 0; 1286 cic->ttime_samples = 0;
@@ -1373,15 +1372,17 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
1373static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio) 1372static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
1374{ 1373{
1375 struct cfq_io_context *cic; 1374 struct cfq_io_context *cic;
1375 struct rb_node *n;
1376 1376
1377 write_lock(&cfq_exit_lock); 1377 write_lock(&cfq_exit_lock);
1378 1378
1379 cic = ioc->cic; 1379 n = rb_first(&ioc->cic_root);
1380 1380 while (n != NULL) {
1381 changed_ioprio(cic); 1381 cic = rb_entry(n, struct cfq_io_context, rb_node);
1382 1382
1383 list_for_each_entry(cic, &cic->list, list)
1384 changed_ioprio(cic); 1383 changed_ioprio(cic);
1384 n = rb_next(n);
1385 }
1385 1386
1386 write_unlock(&cfq_exit_lock); 1387 write_unlock(&cfq_exit_lock);
1387 1388
@@ -1445,14 +1446,67 @@ out:
1445 return cfqq; 1446 return cfqq;
1446} 1447}
1447 1448
1449static struct cfq_io_context *
1450cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
1451{
1452 struct rb_node *n = ioc->cic_root.rb_node;
1453 struct cfq_io_context *cic;
1454 void *key = cfqd;
1455
1456 while (n) {
1457 cic = rb_entry(n, struct cfq_io_context, rb_node);
1458
1459 if (key < cic->key)
1460 n = n->rb_left;
1461 else if (key > cic->key)
1462 n = n->rb_right;
1463 else
1464 return cic;
1465 }
1466
1467 return NULL;
1468}
1469
1470static inline void
1471cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
1472 struct cfq_io_context *cic)
1473{
1474 struct rb_node **p = &ioc->cic_root.rb_node;
1475 struct rb_node *parent = NULL;
1476 struct cfq_io_context *__cic;
1477
1478 read_lock(&cfq_exit_lock);
1479
1480 cic->ioc = ioc;
1481 cic->key = cfqd;
1482
1483 ioc->set_ioprio = cfq_ioc_set_ioprio;
1484
1485 while (*p) {
1486 parent = *p;
1487 __cic = rb_entry(parent, struct cfq_io_context, rb_node);
1488
1489 if (cic->key < __cic->key)
1490 p = &(*p)->rb_left;
1491 else if (cic->key > __cic->key)
1492 p = &(*p)->rb_right;
1493 else
1494 BUG();
1495 }
1496
1497 rb_link_node(&cic->rb_node, parent, p);
1498 rb_insert_color(&cic->rb_node, &ioc->cic_root);
1499 list_add(&cic->queue_list, &cfqd->cic_list);
1500 read_unlock(&cfq_exit_lock);
1501}
1502
1448/* 1503/*
1449 * Setup general io context and cfq io context. There can be several cfq 1504 * Setup general io context and cfq io context. There can be several cfq
1450 * io contexts per general io context, if this process is doing io to more 1505 * io contexts per general io context, if this process is doing io to more
1451 * than one device managed by cfq. Note that caller is holding a reference to 1506 * than one device managed by cfq.
1452 * cfqq, so we don't need to worry about it disappearing
1453 */ 1507 */
1454static struct cfq_io_context * 1508static struct cfq_io_context *
1455cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) 1509cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
1456{ 1510{
1457 struct io_context *ioc = NULL; 1511 struct io_context *ioc = NULL;
1458 struct cfq_io_context *cic; 1512 struct cfq_io_context *cic;
@@ -1463,88 +1517,15 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask)
1463 if (!ioc) 1517 if (!ioc)
1464 return NULL; 1518 return NULL;
1465 1519
1466restart: 1520 cic = cfq_cic_rb_lookup(cfqd, ioc);
1467 if ((cic = ioc->cic) == NULL) { 1521 if (cic)
1468 cic = cfq_alloc_io_context(cfqd, gfp_mask); 1522 goto out;
1469
1470 if (cic == NULL)
1471 goto err;
1472
1473 /*
1474 * manually increment generic io_context usage count, it