engines/null: fill issue_time during commit
[fio.git] / engines / null.c
... / ...
CommitLineData
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
22struct null_data {
23 struct io_u **io_us;
24 int queued;
25 int events;
26};
27
28static struct io_u *null_event(struct null_data *nd, int event)
29{
30 return nd->io_us[event];
31}
32
33static 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
47static 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
64static 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
79static 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
93static int null_open(struct null_data fio_unused *nd,
94 struct fio_file fio_unused *f)
95{
96 return 0;
97}
98
99static void null_cleanup(struct null_data *nd)
100{
101 if (nd) {
102 free(nd->io_us);
103 free(nd);
104 }
105}
106
107static 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
124static struct io_u *fio_null_event(struct thread_data *td, int event)
125{
126 return null_event(td->io_ops_data, event);
127}
128
129static 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
136static int fio_null_commit(struct thread_data *td)
137{
138 return null_commit(td, td->io_ops_data);
139}
140
141static 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
147static int fio_null_open(struct thread_data *td, struct fio_file *f)
148{
149 return null_open(td->io_ops_data, f);
150}
151
152static void fio_null_cleanup(struct thread_data *td)
153{
154 null_cleanup(td->io_ops_data);
155}
156
157static 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
164static 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
177static void fio_init fio_null_register(void)
178{
179 register_ioengine(&ioengine);
180}
181
182static void fio_exit fio_null_unregister(void)
183{
184 unregister_ioengine(&ioengine);
185}
186
187#else
188
189#ifdef FIO_EXTERNAL_ENGINE
190
191struct 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
234private:
235 struct null_data *impl_;
236};
237
238extern "C" {
239
240static 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
245static 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
251static int fio_null_commit(struct thread_data *td)
252{
253 return NullData::get(td)->fio_null_commit(td);
254}
255
256static 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
261static 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
266static int fio_null_init(struct thread_data *td)
267{
268 td->io_ops_data = new NullData(td);
269 return 0;
270}
271
272static void fio_null_cleanup(struct thread_data *td)
273{
274 delete NullData::get(td);
275}
276
277static struct ioengine_ops ioengine;
278void 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 */