001e5eb5e7b11768e9d9e6fe7956a73e28fba1db
[dragonfly.git] / sys / dsched / fq / dsched_fq.h
1 /*
2  * Copyright (c) 2009, 2010 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Alex Hornung <ahornung@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 #ifndef _DSCHED_FQ_H_
35 #define _DSCHED_FQ_H_
36
37 #if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
38
39 #ifndef _SYS_QUEUE_H_
40 #include <sys/queue.h>
41 #endif
42 #ifndef _SYS_BIO_H_
43 #include <sys/bio.h>
44 #endif
45 #ifndef _SYS_BIOTRACK_H_
46 #include <sys/biotrack.h>
47 #endif
48 #ifndef _SYS_SPINLOCK_H_
49 #include <sys/spinlock.h>
50 #endif
51
52 #define FQ_THREAD_IO_LOCKINIT(x)        lockinit(&(x)->lock, "tdiobioq", 0, LK_CANRECURSE)
53 #define FQ_THREAD_IO_LOCK(x)            fq_thread_io_ref((x)); \
54                                         lockmgr(&(x)->lock, LK_EXCLUSIVE)
55 #define FQ_THREAD_IO_UNLOCK(x)          lockmgr(&(x)->lock, LK_RELEASE); \
56                                         fq_thread_io_unref((x));
57
58 #define FQ_DISK_CTX_LOCKINIT(x)         lockinit(&(x)->lock, "tdiodiskq", 0, LK_CANRECURSE)
59 #define FQ_DISK_CTX_LOCK(x)             fq_disk_ctx_ref((x)); \
60                                         lockmgr(&(x)->lock, LK_EXCLUSIVE)
61 #define FQ_DISK_CTX_UNLOCK(x)           lockmgr(&(x)->lock, LK_RELEASE); \
62                                         fq_disk_ctx_unref((x))
63 #define FQ_DISK_CTX_LOCK_ASSERT(x)      KKASSERT(lockstatus(&(x)->lock, curthread) == LK_EXCLUSIVE)
64
65 #define FQ_GLOBAL_THREAD_CTX_LOCKINIT(x)        lockinit(&fq_tdctx_lock, "tdctxglob", 0, LK_CANRECURSE)
66 #define FQ_GLOBAL_THREAD_CTX_LOCK(x)            lockmgr(&fq_tdctx_lock, LK_EXCLUSIVE)
67 #define FQ_GLOBAL_THREAD_CTX_UNLOCK(x)  lockmgr(&fq_tdctx_lock, LK_RELEASE)
68
69
70
71 #define FQ_THREAD_CTX_LOCKINIT(x)       spin_init(&(x)->lock)
72 #if 0
73 #define FQ_THREAD_IO_LOCKINIT(x)        spin_init(&(x)->lock)
74 #endif
75 #if 0
76 #define FQ_DISK_CTX_LOCKINIT(x) spin_init(&(x)->lock)
77 #endif
78 #if 0
79 #define FQ_GLOBAL_THREAD_CTX_LOCKINIT(x)        spin_init(&fq_tdctx_lock)
80 #endif
81
82 #define FQ_THREAD_CTX_LOCK(x)           fq_thread_ctx_ref((x)); \
83                                 spin_lock_wr(&(x)->lock)
84 #if 0
85 #define FQ_THREAD_IO_LOCK(x)            fq_thread_io_ref((x)); \
86                                 spin_lock_wr(&(x)->lock)
87 #endif
88 #if 0
89 #define FQ_DISK_CTX_LOCK(x)     fq_disk_ctx_ref((x)); \
90                                 spin_lock_wr(&(x)->lock)
91 #endif
92 #if 0
93 #define FQ_GLOBAL_THREAD_CTX_LOCK(x)    spin_lock_wr(&fq_tdctx_lock)
94 #endif
95
96 #define FQ_THREAD_CTX_UNLOCK(x) spin_unlock_wr(&(x)->lock); \
97                                 fq_thread_ctx_unref((x))
98
99 #if 0
100 #define FQ_THREAD_IO_UNLOCK(x)  spin_unlock_wr(&(x)->lock); \
101                                 fq_thread_io_unref((x))
102 #endif
103 #if 0
104 #define FQ_DISK_CTX_UNLOCK(x)   spin_unlock_wr(&(x)->lock); \
105                                 fq_disk_ctx_unref((x))
106 #endif
107 #if 0
108 #define FQ_GLOBAL_THREAD_CTX_UNLOCK(x) spin_unlock_wr(&fq_tdctx_lock)
109 #endif
110
111 #define FQ_PRIO_BIAS            5
112 #define FQ_PRIO_MAX             10
113 #define FQ_PRIO_MIN             1
114 #define FQ_PRIO_IDLE            -1
115 #define FQ_BUCKET_ACTIVE        0x01
116
117 #define FQ_DRAIN_CANCEL 0x1
118 #define FQ_DRAIN_FLUSH  0x2
119
120 struct disk;
121 struct proc;
122
123 #define FQ_LINKED_DISK_CTX      0x01
124 #define FQ_LINKED_THREAD_CTX            0x02
125
126 struct fq_thread_io {
127         TAILQ_ENTRY(fq_thread_io)       link;
128         TAILQ_ENTRY(fq_thread_io)       dlink;
129         TAILQ_HEAD(, bio)       queue;  /* IO queue (bio) */
130
131         struct lock             lock;
132         struct disk             *dp;
133         struct fq_disk_ctx      *diskctx;
134         struct fq_thread_ctx    *tdctx;
135         struct proc             *p;
136
137         int32_t qlength;        /* IO queue length */
138         int32_t flags;
139
140         int     refcount;
141         int32_t transactions;   /* IOs completed so far during current interval */
142         int32_t avg_latency;    /* avg latency for current interval IOs */
143         int32_t interval_transactions;  /* IOs completed during last interval */
144         int32_t interval_avg_latency;   /* avg latency for last interval IOs */
145         int32_t max_tp;         /* rate limit of transactions per interval */
146         int32_t issued;         /* IOs issued to disk (but not completed) */
147
148         int     rebalance;      /* thread needs to rebalance w/ fq_balance_self */
149 };
150
151 struct fq_disk_ctx {
152         struct thread   *td;            /* dispatcher thread td */
153         struct thread   *td_balance;    /* balancer thread td */
154         struct disk     *dp;            /* back pointer to disk struct */
155         struct lock     lock;
156         int     refcount;
157
158         int     avg_rq_time;            /* XXX: not yet used */
159         int32_t incomplete_tp;          /* IOs issued but not completed */
160         int     idle;                   /* disk idle ? */
161         struct timeval start_idle;      /* disk idleness start time */
162         int     idle_time;              /* aggregate idle time in interval */
163         int     die;                    /* flag to kill related threads */
164         struct timeval start_interval;  /* current interval start time */
165
166         int     prev_full;              /* disk >90% busy during prev. to last
167                                            interval? */
168         int     last_full;              /* disk >90% busy during last interval */
169         int     disk_busy;              /* disk >90% busy during cur. interval */
170         int64_t budgetpb[FQ_PRIO_MAX+1];/* next interval budget for each thread
171                                            in each prio */
172
173         /* list contains all fq_thread_io for this disk */
174         TAILQ_HEAD(, fq_thread_io)      fq_tdio_list;   /* list of thread_io of disk */
175         TAILQ_ENTRY(fq_disk_ctx)        link;
176 };
177
178 struct fq_thread_ctx {
179         struct proc *p;
180         struct thread *td;
181         int dead;
182         struct spinlock lock;
183         int     refcount;
184         TAILQ_HEAD(, fq_thread_io)      fq_tdio_list;   /* list of thread_io */
185         TAILQ_ENTRY(fq_thread_ctx)      link;
186 };
187
188
189
190
191
192 struct fq_thread_io     *fq_thread_io_alloc(struct disk *dp, struct fq_thread_ctx *tdctx);
193 struct fq_disk_ctx      *fq_disk_ctx_alloc(struct disk *dp);
194 struct fq_thread_ctx    *fq_thread_ctx_alloc(struct proc *p);
195 void    fq_balance_thread(struct fq_disk_ctx *diskctx);
196 void    fq_dispatcher(struct fq_disk_ctx *diskctx);
197 biodone_t       fq_completed;
198
199 void    fq_disk_ctx_ref(struct fq_disk_ctx *diskctx);
200 void    fq_thread_io_ref(struct fq_thread_io *tdio);
201 void    fq_thread_ctx_ref(struct fq_thread_ctx *tdctx);
202 void    fq_disk_ctx_unref(struct fq_disk_ctx *diskctx);
203 void    fq_thread_io_unref(struct fq_thread_io *tdio);
204 void    fq_thread_ctx_unref(struct fq_thread_ctx *tdctx);
205 void    fq_dispatch(struct fq_disk_ctx *diskctx, struct bio *bio,
206                         struct fq_thread_io *tdio);
207 void    fq_drain(struct fq_disk_ctx *diskctx, int mode);
208 void    fq_balance_self(struct fq_thread_io *tdio);
209 #endif /* _KERNEL || _KERNEL_STRUCTURES */
210
211
212 struct dsched_fq_stats {
213         int32_t tdctx_allocations;
214         int32_t tdio_allocations;
215         int32_t diskctx_allocations;
216
217         int32_t procs_limited;
218
219         int32_t transactions;
220         int32_t transactions_completed;
221         int32_t cancelled;
222
223         int32_t no_tdctx;
224
225         int32_t nthreads;
226         int32_t nprocs;
227 };
228
229 #endif /* _DSCHED_FQ_H_ */