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 null.so null.c -DFIO_EXTERNAL_ENGINE 10 * 11 */ 12#include <stdio.h> 13#include <stdlib.h> 14#include <unistd.h> 15#include <errno.h> 16#include <assert.h> 17 18#include "../fio.h" 19 20struct null_data { 21 struct io_u **io_us; 22 int queued; 23 int events; 24}; 25 26static struct io_u *fio_null_event(struct thread_data *td, int event) 27{ 28 struct null_data *nd = (struct null_data *) td->io_ops_data; 29 30 return nd->io_us[event]; 31} 32 33static int fio_null_getevents(struct thread_data *td, unsigned int min_events, 34 unsigned int fio_unused max, 35 const struct timespec fio_unused *t) 36{ 37 struct null_data *nd = (struct null_data *) td->io_ops_data; 38 int ret = 0; 39 40 if (min_events) { 41 ret = nd->events; 42 nd->events = 0; 43 } 44 45 return ret; 46} 47 48static int fio_null_commit(struct thread_data *td) 49{ 50 struct null_data *nd = (struct null_data *) td->io_ops_data; 51 52 if (!nd->events) { 53#ifndef FIO_EXTERNAL_ENGINE 54 io_u_mark_submit(td, nd->queued); 55#endif 56 nd->events = nd->queued; 57 nd->queued = 0; 58 } 59 60 return 0; 61} 62 63static int fio_null_queue(struct thread_data *td, struct io_u *io_u) 64{ 65 struct null_data *nd = (struct null_data *) td->io_ops_data; 66 67 fio_ro_check(td, io_u); 68 69 if (td->io_ops->flags & FIO_SYNCIO) 70 return FIO_Q_COMPLETED; 71 if (nd->events) 72 return FIO_Q_BUSY; 73 74 nd->io_us[nd->queued++] = io_u; 75 return FIO_Q_QUEUED; 76} 77 78static int fio_null_open(struct thread_data fio_unused *td, 79 struct fio_file fio_unused *f) 80{ 81 return 0; 82} 83 84static void fio_null_cleanup(struct thread_data *td) 85{ 86 struct null_data *nd = (struct null_data *) td->io_ops_data; 87 88 if (nd) { 89 free(nd->io_us); 90 free(nd); 91 } 92} 93 94static int fio_null_init(struct thread_data *td) 95{ 96 struct null_data *nd = (struct null_data *) malloc(sizeof(*nd)); 97 98 memset(nd, 0, sizeof(*nd)); 99 100 if (td->o.iodepth != 1) { 101 nd->io_us = (struct io_u **) malloc(td->o.iodepth * sizeof(struct io_u *)); 102 memset(nd->io_us, 0, td->o.iodepth * sizeof(struct io_u *)); 103 } else 104 td->io_ops->flags |= FIO_SYNCIO; 105 106 td->io_ops_data = nd; 107 return 0; 108} 109 110#ifndef __cplusplus 111static struct ioengine_ops ioengine = { 112 .name = "null", 113 .version = FIO_IOOPS_VERSION, 114 .queue = fio_null_queue, 115 .commit = fio_null_commit, 116 .getevents = fio_null_getevents, 117 .event = fio_null_event, 118 .init = fio_null_init, 119 .cleanup = fio_null_cleanup, 120 .open_file = fio_null_open, 121 .flags = FIO_DISKLESSIO | FIO_FAKEIO, 122}; 123 124static void fio_init fio_null_register(void) 125{ 126 register_ioengine(&ioengine); 127} 128 129static void fio_exit fio_null_unregister(void) 130{ 131 unregister_ioengine(&ioengine); 132} 133 134#else 135 136#ifdef FIO_EXTERNAL_ENGINE 137extern "C" { 138static struct ioengine_ops ioengine; 139void get_ioengine(struct ioengine_ops **ioengine_ptr) 140{ 141 *ioengine_ptr = &ioengine; 142 143 ioengine.name = "cpp_null"; 144 ioengine.version = FIO_IOOPS_VERSION; 145 ioengine.queue = fio_null_queue; 146 ioengine.commit = fio_null_commit; 147 ioengine.getevents = fio_null_getevents; 148 ioengine.event = fio_null_event; 149 ioengine.init = fio_null_init; 150 ioengine.cleanup = fio_null_cleanup; 151 ioengine.open_file = fio_null_open; 152 ioengine.flags = FIO_DISKLESSIO | FIO_FAKEIO; 153} 154} 155#endif /* FIO_EXTERNAL_ENGINE */ 156 157#endif /* __cplusplus */ 158