diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2008-09-13 14:26:01 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2008-10-09 02:56:09 -0400 |
commit | c7c22e4d5c1fdebfac4dba76de7d0338c2b0d832 (patch) | |
tree | ecc3d2517b3471ccc35d4cb4e3b48d4b57205061 /include | |
parent | 18887ad910e56066233a07fd3cfb2fa11338b782 (diff) |
block: add support for IO CPU affinity
This patch adds support for controlling the IO completion CPU of
either all requests on a queue, or on a per-request basis. We export
a sysfs variable (rq_affinity) which, if set, migrates completions
of requests to the CPU that originally submitted it. A bio helper
(bio_set_completion_cpu()) is also added, so that queuers can ask
for completion on that specific CPU.
In testing, this has been show to cut the system time by as much
as 20-40% on synthetic workloads where CPU affinity is desired.
This requires a little help from the architecture, so it'll only
work as designed for archs that are using the new generic smp
helper infrastructure.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/bio.h | 11 | ||||
-rw-r--r-- | include/linux/blkdev.h | 5 | ||||
-rw-r--r-- | include/linux/elevator.h | 8 |
3 files changed, 19 insertions, 5 deletions
diff --git a/include/linux/bio.h b/include/linux/bio.h index 2c0c09034fd2..13aba20edb2d 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h | |||
@@ -81,6 +81,8 @@ struct bio { | |||
81 | 81 | ||
82 | unsigned int bi_max_vecs; /* max bvl_vecs we can hold */ | 82 | unsigned int bi_max_vecs; /* max bvl_vecs we can hold */ |
83 | 83 | ||
84 | unsigned int bi_comp_cpu; /* completion CPU */ | ||
85 | |||
84 | struct bio_vec *bi_io_vec; /* the actual vec list */ | 86 | struct bio_vec *bi_io_vec; /* the actual vec list */ |
85 | 87 | ||
86 | bio_end_io_t *bi_end_io; | 88 | bio_end_io_t *bi_end_io; |
@@ -105,6 +107,7 @@ struct bio { | |||
105 | #define BIO_BOUNCED 5 /* bio is a bounce bio */ | 107 | #define BIO_BOUNCED 5 /* bio is a bounce bio */ |
106 | #define BIO_USER_MAPPED 6 /* contains user pages */ | 108 | #define BIO_USER_MAPPED 6 /* contains user pages */ |
107 | #define BIO_EOPNOTSUPP 7 /* not supported */ | 109 | #define BIO_EOPNOTSUPP 7 /* not supported */ |
110 | #define BIO_CPU_AFFINE 8 /* complete bio on same CPU as submitted */ | ||
108 | #define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag))) | 111 | #define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag))) |
109 | 112 | ||
110 | /* | 113 | /* |
@@ -343,6 +346,14 @@ extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set | |||
343 | extern unsigned int bvec_nr_vecs(unsigned short idx); | 346 | extern unsigned int bvec_nr_vecs(unsigned short idx); |
344 | 347 | ||
345 | /* | 348 | /* |
349 | * Allow queuer to specify a completion CPU for this bio | ||
350 | */ | ||
351 | static inline void bio_set_completion_cpu(struct bio *bio, unsigned int cpu) | ||
352 | { | ||
353 | bio->bi_comp_cpu = cpu; | ||
354 | } | ||
355 | |||
356 | /* | ||
346 | * bio_set is used to allow other portions of the IO system to | 357 | * bio_set is used to allow other portions of the IO system to |
347 | * allocate their own private memory pools for bio and iovec structures. | 358 | * allocate their own private memory pools for bio and iovec structures. |
348 | * These memory pools in turn all allocate from the bio_slab | 359 | * These memory pools in turn all allocate from the bio_slab |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 10aa46c8f170..93204bf7b297 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/stringify.h> | 18 | #include <linux/stringify.h> |
19 | #include <linux/bsg.h> | 19 | #include <linux/bsg.h> |
20 | #include <linux/smp.h> | ||
20 | 21 | ||
21 | #include <asm/scatterlist.h> | 22 | #include <asm/scatterlist.h> |
22 | 23 | ||
@@ -139,7 +140,8 @@ enum rq_flag_bits { | |||
139 | */ | 140 | */ |
140 | struct request { | 141 | struct request { |
141 | struct list_head queuelist; | 142 | struct list_head queuelist; |
142 | struct list_head donelist; | 143 | struct call_single_data csd; |
144 | int cpu; | ||
143 | 145 | ||
144 | struct request_queue *q; | 146 | struct request_queue *q; |
145 | 147 | ||
@@ -420,6 +422,7 @@ struct request_queue | |||
420 | #define QUEUE_FLAG_ELVSWITCH 8 /* don't use elevator, just do FIFO */ | 422 | #define QUEUE_FLAG_ELVSWITCH 8 /* don't use elevator, just do FIFO */ |
421 | #define QUEUE_FLAG_BIDI 9 /* queue supports bidi requests */ | 423 | #define QUEUE_FLAG_BIDI 9 /* queue supports bidi requests */ |
422 | #define QUEUE_FLAG_NOMERGES 10 /* disable merge attempts */ | 424 | #define QUEUE_FLAG_NOMERGES 10 /* disable merge attempts */ |
425 | #define QUEUE_FLAG_SAME_COMP 11 /* force complete on same CPU */ | ||
423 | 426 | ||
424 | static inline int queue_is_locked(struct request_queue *q) | 427 | static inline int queue_is_locked(struct request_queue *q) |
425 | { | 428 | { |
diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 639624b55fbe..bb791c311a56 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h | |||
@@ -173,15 +173,15 @@ enum { | |||
173 | #define rb_entry_rq(node) rb_entry((node), struct request, rb_node) | 173 | #define rb_entry_rq(node) rb_entry((node), struct request, rb_node) |
174 | 174 | ||
175 | /* | 175 | /* |
176 | * Hack to reuse the donelist list_head as the fifo time holder while | 176 | * Hack to reuse the csd.list list_head as the fifo time holder while |
177 | * the request is in the io scheduler. Saves an unsigned long in rq. | 177 | * the request is in the io scheduler. Saves an unsigned long in rq. |
178 | */ | 178 | */ |
179 | #define rq_fifo_time(rq) ((unsigned long) (rq)->donelist.next) | 179 | #define rq_fifo_time(rq) ((unsigned long) (rq)->csd.list.next) |
180 | #define rq_set_fifo_time(rq,exp) ((rq)->donelist.next = (void *) (exp)) | 180 | #define rq_set_fifo_time(rq,exp) ((rq)->csd.list.next = (void *) (exp)) |
181 | #define rq_entry_fifo(ptr) list_entry((ptr), struct request, queuelist) | 181 | #define rq_entry_fifo(ptr) list_entry((ptr), struct request, queuelist) |
182 | #define rq_fifo_clear(rq) do { \ | 182 | #define rq_fifo_clear(rq) do { \ |
183 | list_del_init(&(rq)->queuelist); \ | 183 | list_del_init(&(rq)->queuelist); \ |
184 | INIT_LIST_HEAD(&(rq)->donelist); \ | 184 | INIT_LIST_HEAD(&(rq)->csd.list); \ |
185 | } while (0) | 185 | } while (0) |
186 | 186 | ||
187 | /* | 187 | /* |