docs: update for new data placement options
[fio.git] / engines / null.c
1 /*
2  * null engine
3  *
4  * IO engine that doesn't do any real IO transfers, it just pretends to.
5  * The main purpose is to test fio itself.
6  *
7  * It also can act as external C++ engine - compiled with:
8  *
9  * g++ -O2 -g -shared -rdynamic -fPIC -o cpp_null null.c \
10  *      -include ../config-host.h -DFIO_EXTERNAL_ENGINE
11  *
12  * to test it execute:
13  *
14  * LD_LIBRARY_PATH=./engines ./fio examples/cpp_null.fio
15  *
16  */
17 #include <stdlib.h>
18 #include <assert.h>
19
20 #include "../fio.h"
21
22 struct null_data {
23         struct io_u **io_us;
24         int queued;
25         int events;
26 };
27
28 static struct io_u *null_event(struct null_data *nd, int event)
29 {
30         return nd->io_us[event];
31 }
32
33 static int null_getevents(struct null_data *nd, unsigned int min_events,
34                           unsigned int fio_unused max,
35                           const struct timespec fio_unused *t)
36 {
37         int ret = 0;
38
39         if (min_events) {
40                 ret = nd->events;
41                 nd->events = 0;
42         }
43
44         return ret;
45 }
46
47 static void null_queued(struct thread_data *td, struct null_data *nd)
48 {
49         struct timespec now;
50
51         if (!fio_fill_issue_time(td))
52                 return;
53
54         fio_gettime(&now, NULL);
55
56         for (int i = 0; i < nd->queued; i++) {
57                 struct io_u *io_u = nd->io_us[i];
58
59                 memcpy(&io_u->issue_time, &now, sizeof(now));
60                 io_u_queued(td, io_u);
61         }
62 }
63
64 static int null_commit(struct thread_data *td, struct null_data *nd)
65 {
66         if (!nd->events) {
67                 null_queued(td, nd);
68
69 #ifndef FIO_EXTERNAL_ENGINE
70                 io_u_mark_submit(td, nd->queued);
71 #endif
72                 nd->events = nd->queued;
73                 nd->queued = 0;
74         }
75
76         return 0;
77 }
78
79 static enum fio_q_status null_queue(struct thread_data *td,
80                                     struct null_data *nd, struct io_u *io_u)
81 {
82         fio_ro_check(td, io_u);
83
84         if (td->io_ops->flags & FIO_SYNCIO)
85                 return FIO_Q_COMPLETED;
86         if (nd->events)
87                 return FIO_Q_BUSY;
88
89         nd->io_us[nd->queued++] = io_u;
90         return FIO_Q_QUEUED;
91 }
92
93 static int null_open(struct null_data fio_unused *nd,
94                      struct fio_file fio_unused *f)
95 {
96         return 0;
97 }
98
99 static void null_cleanup(struct null_data *nd)
100 {
101         if (nd) {
102                 free(nd->io_us);
103                 free(nd);
104         }
105 }
106
107 static struct null_data *null_init(struct thread_data *td)
108 {
109         struct null_data *nd;
110         nd = malloc(sizeof(*nd));
111
112         memset(nd, 0, sizeof(*nd));
113
114         if (td->o.iodepth != 1) {
115                 nd->io_us = calloc(td->o.iodepth, sizeof(struct io_u *));
116                 td->io_ops->flags |= FIO_ASYNCIO_SETS_ISSUE_TIME;
117         } else
118                 td->io_ops->flags |= FIO_SYNCIO;
119
120         td_set_ioengine_flags(td);
121         return nd;
122 }
123
124 #ifndef __cplusplus
125
126 static struct io_u *fio_null_event(struct thread_data *td, int event)
127 {
128         return null_event(td->io_ops_data, event);
129 }
130
131 static int fio_null_getevents(struct thread_data *td, unsigned int min_events,
132                               unsigned int max, const struct timespec *t)
133 {
134         struct null_data *nd = td->io_ops_data;
135         return null_getevents(nd, min_events, max, t);
136 }
137
138 static int fio_null_commit(struct thread_data *td)
139 {
140         return null_commit(td, td->io_ops_data);
141 }
142
143 static enum fio_q_status fio_null_queue(struct thread_data *td,
144                                         struct io_u *io_u)
145 {
146         return null_queue(td, td->io_ops_data, io_u);
147 }
148
149 static int fio_null_open(struct thread_data *td, struct fio_file *f)
150 {
151         return null_open(td->io_ops_data, f);
152 }
153
154 static void fio_null_cleanup(struct thread_data *td)
155 {
156         null_cleanup(td->io_ops_data);
157 }
158
159 static int fio_null_init(struct thread_data *td)
160 {
161         td->io_ops_data = null_init(td);
162         assert(td->io_ops_data);
163         return 0;
164 }
165
166 static struct ioengine_ops ioengine = {
167         .name           = "null",
168         .version        = FIO_IOOPS_VERSION,
169         .queue          = fio_null_queue,
170         .commit         = fio_null_commit,
171         .getevents      = fio_null_getevents,
172         .event          = fio_null_event,
173         .init           = fio_null_init,
174         .cleanup        = fio_null_cleanup,
175         .open_file      = fio_null_open,
176         .flags          = FIO_DISKLESSIO | FIO_FAKEIO,
177 };
178
179 static void fio_init fio_null_register(void)
180 {
181         register_ioengine(&ioengine);
182 }
183
184 static void fio_exit fio_null_unregister(void)
185 {
186         unregister_ioengine(&ioengine);
187 }
188
189 #else
190
191 #ifdef FIO_EXTERNAL_ENGINE
192
193 struct NullData {
194         NullData(struct thread_data *td)
195         {
196                 impl_ = null_init(td);
197                 assert(impl_);
198         }
199
200         ~NullData()
201         {
202                 null_cleanup(impl_);
203         }
204
205         static NullData *get(struct thread_data *td)
206         {
207                 return reinterpret_cast<NullData *>(td->io_ops_data);
208         }
209
210         io_u *fio_null_event(struct thread_data *, int event)
211         {
212                 return null_event(impl_, event);
213         }
214
215         int fio_null_getevents(struct thread_data *, unsigned int min_events,
216                                unsigned int max, const struct timespec *t)
217         {
218                 return null_getevents(impl_, min_events, max, t);
219         }
220
221         int fio_null_commit(struct thread_data *td)
222         {
223                 return null_commit(td, impl_);
224         }
225
226         fio_q_status fio_null_queue(struct thread_data *td, struct io_u *io_u)
227         {
228                 return null_queue(td, impl_, io_u);
229         }
230
231         int fio_null_open(struct thread_data *, struct fio_file *f)
232         {
233                 return null_open(impl_, f);
234         }
235
236 private:
237         struct null_data *impl_;
238 };
239
240 extern "C" {
241
242 static struct io_u *fio_null_event(struct thread_data *td, int event)
243 {
244         return NullData::get(td)->fio_null_event(td, event);
245 }
246
247 static int fio_null_getevents(struct thread_data *td, unsigned int min_events,
248                               unsigned int max, const struct timespec *t)
249 {
250         return NullData::get(td)->fio_null_getevents(td, min_events, max, t);
251 }
252
253 static int fio_null_commit(struct thread_data *td)
254 {
255         return NullData::get(td)->fio_null_commit(td);
256 }
257
258 static fio_q_status fio_null_queue(struct thread_data *td, struct io_u *io_u)
259 {
260         return NullData::get(td)->fio_null_queue(td, io_u);
261 }
262
263 static int fio_null_open(struct thread_data *td, struct fio_file *f)
264 {
265         return NullData::get(td)->fio_null_open(td, f);
266 }
267
268 static int fio_null_init(struct thread_data *td)
269 {
270         td->io_ops_data = new NullData(td);
271         return 0;
272 }
273
274 static void fio_null_cleanup(struct thread_data *td)
275 {
276         delete NullData::get(td);
277 }
278
279 static struct ioengine_ops ioengine;
280 void get_ioengine(struct ioengine_ops **ioengine_ptr)
281 {
282         *ioengine_ptr = &ioengine;
283
284         ioengine.name           = "cpp_null";
285         ioengine.version        = FIO_IOOPS_VERSION;
286         ioengine.queue          = fio_null_queue;
287         ioengine.commit         = fio_null_commit;
288         ioengine.getevents      = fio_null_getevents;
289         ioengine.event          = fio_null_event;
290         ioengine.init           = fio_null_init;
291         ioengine.cleanup        = fio_null_cleanup;
292         ioengine.open_file      = fio_null_open;
293         ioengine.flags          = FIO_DISKLESSIO | FIO_FAKEIO;
294 }
295 }
296 #endif /* FIO_EXTERNAL_ENGINE */
297
298 #endif /* __cplusplus */