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 20 struct null_data { 21 struct io_u **io_us; 22 int queued; 23 int events; 24 }; 25 26 static 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 33 static 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 48 static 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 63 static 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 78 static int fio_null_open(struct thread_data fio_unused *td, 79 struct fio_file fio_unused *f) 80 { 81 return 0; 82 } 83 84 static 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 94 static 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 111 static 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 124 static void fio_init fio_null_register(void) 125 { 126 register_ioengine(&ioengine); 127 } 128 129 static void fio_exit fio_null_unregister(void) 130 { 131 unregister_ioengine(&ioengine); 132 } 133 134 #else 135 136 #ifdef FIO_EXTERNAL_ENGINE 137 extern "C" { 138 static struct ioengine_ops ioengine; 139 void 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