engines/null: fill issue_time during commit
[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 = (struct null_data *) malloc(sizeof(*nd));
110
111         memset(nd, 0, sizeof(*nd));
112
113         if (td->o.iodepth != 1) {
114                 nd->io_us = (struct io_u **) malloc(td->o.iodepth * sizeof(struct io_u *));
115                 memset(nd->io_us, 0, td->o.iodepth * sizeof(struct io_u *));
116         } else
117                 td->io_ops->flags |= FIO_SYNCIO;
118
119         return nd;
120 }
121
122 #ifndef __cplusplus
123
124 static struct io_u *fio_null_event(struct thread_data *td, int event)
125 {
126         return null_event(td->io_ops_data, event);
127 }
128
129 static int fio_null_getevents(struct thread_data *td, unsigned int min_events,
130                               unsigned int max, const struct timespec *t)
131 {
132         struct null_data *nd = td->io_ops_data;
133         return null_getevents(nd, min_events, max, t);
134 }
135
136 static int fio_null_commit(struct thread_data *td)
137 {
138         return null_commit(td, td->io_ops_data);
139 }
140
141 static enum fio_q_status fio_null_queue(struct thread_data *td,
142                                         struct io_u *io_u)
143 {
144         return null_queue(td, td->io_ops_data, io_u);
145 }
146
147 static int fio_null_open(struct thread_data *td, struct fio_file *f)
148 {
149         return null_open(td->io_ops_data, f);
150 }
151
152 static void fio_null_cleanup(struct thread_data *td)
153 {
154         null_cleanup(td->io_ops_data);
155 }
156
157 static int fio_null_init(struct thread_data *td)
158 {
159         td->io_ops_data = null_init(td);
160         assert(td->io_ops_data);
161         return 0;
162 }
163
164 static struct ioengine_ops ioengine = {
165         .name           = "null",
166         .version        = FIO_IOOPS_VERSION,
167         .queue          = fio_null_queue,
168         .commit         = fio_null_commit,
169         .getevents      = fio_null_getevents,
170         .event          = fio_null_event,
171         .init           = fio_null_init,
172         .cleanup        = fio_null_cleanup,
173         .open_file      = fio_null_open,
174         .flags          = FIO_DISKLESSIO | FIO_FAKEIO,
175 };
176
177 static void fio_init fio_null_register(void)
178 {
179         register_ioengine(&ioengine);
180 }
181
182 static void fio_exit fio_null_unregister(void)
183 {
184         unregister_ioengine(&ioengine);
185 }
186
187 #else
188
189 #ifdef FIO_EXTERNAL_ENGINE
190
191 struct NullData {
192         NullData(struct thread_data *td)
193         {
194                 impl_ = null_init(td);
195                 assert(impl_);
196         }
197
198         ~NullData()
199         {
200                 null_cleanup(impl_);
201         }
202
203         static NullData *get(struct thread_data *td)
204         {
205                 return reinterpret_cast<NullData *>(td->io_ops_data);
206         }
207
208         io_u *fio_null_event(struct thread_data *, int event)
209         {
210                 return null_event(impl_, event);
211         }
212
213         int fio_null_getevents(struct thread_data *, unsigned int min_events,
214                                unsigned int max, const struct timespec *t)
215         {
216                 return null_getevents(impl_, min_events, max, t);
217         }
218
219         int fio_null_commit(struct thread_data *td)
220         {
221                 return null_commit(td, impl_);
222         }
223
224         fio_q_status fio_null_queue(struct thread_data *td, struct io_u *io_u)
225         {
226                 return null_queue(td, impl_, io_u);
227         }
228
229         int fio_null_open(struct thread_data *, struct fio_file *f)
230         {
231                 return null_open(impl_, f);
232         }
233
234 private:
235         struct null_data *impl_;
236 };
237
238 extern "C" {
239
240 static struct io_u *fio_null_event(struct thread_data *td, int event)
241 {
242         return NullData::get(td)->fio_null_event(td, event);
243 }
244
245 static int fio_null_getevents(struct thread_data *td, unsigned int min_events,
246                               unsigned int max, const struct timespec *t)
247 {
248         return NullData::get(td)->fio_null_getevents(td, min_events, max, t);
249 }
250
251 static int fio_null_commit(struct thread_data *td)
252 {
253         return NullData::get(td)->fio_null_commit(td);
254 }
255
256 static fio_q_status fio_null_queue(struct thread_data *td, struct io_u *io_u)
257 {
258         return NullData::get(td)->fio_null_queue(td, io_u);
259 }
260
261 static int fio_null_open(struct thread_data *td, struct fio_file *f)
262 {
263         return NullData::get(td)->fio_null_open(td, f);
264 }
265
266 static int fio_null_init(struct thread_data *td)
267 {
268         td->io_ops_data = new NullData(td);
269         return 0;
270 }
271
272 static void fio_null_cleanup(struct thread_data *td)
273 {
274         delete NullData::get(td);
275 }
276
277 static struct ioengine_ops ioengine;
278 void get_ioengine(struct ioengine_ops **ioengine_ptr)
279 {
280         *ioengine_ptr = &ioengine;
281
282         ioengine.name           = "cpp_null";
283         ioengine.version        = FIO_IOOPS_VERSION;
284         ioengine.queue          = fio_null_queue;
285         ioengine.commit         = fio_null_commit;
286         ioengine.getevents      = fio_null_getevents;
287         ioengine.event          = fio_null_event;
288         ioengine.init           = fio_null_init;
289         ioengine.cleanup        = fio_null_cleanup;
290         ioengine.open_file      = fio_null_open;
291         ioengine.flags          = FIO_DISKLESSIO | FIO_FAKEIO;
292 }
293 }
294 #endif /* FIO_EXTERNAL_ENGINE */
295
296 #endif /* __cplusplus */