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 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 if (nd->io_us) 90 free(nd->io_us); 91 free(nd); 92 } 93 } 94 95 static int fio_null_init(struct thread_data *td) 96 { 97 struct null_data *nd = (struct null_data *) malloc(sizeof(*nd)); 98 99 memset(nd, 0, sizeof(*nd)); 100 101 if (td->o.iodepth != 1) { 102 nd->io_us = (struct io_u **) malloc(td->o.iodepth * sizeof(struct io_u *)); 103 memset(nd->io_us, 0, td->o.iodepth * sizeof(struct io_u *)); 104 } else 105 td->io_ops->flags |= FIO_SYNCIO; 106 107 td->io_ops->data = nd; 108 return 0; 109 } 110 111 #ifndef __cplusplus 112 static struct ioengine_ops ioengine = { 113 .name = "null", 114 .version = FIO_IOOPS_VERSION, 115 .queue = fio_null_queue, 116 .commit = fio_null_commit, 117 .getevents = fio_null_getevents, 118 .event = fio_null_event, 119 .init = fio_null_init, 120 .cleanup = fio_null_cleanup, 121 .open_file = fio_null_open, 122 .flags = FIO_DISKLESSIO, 123 }; 124 125 static void fio_init fio_null_register(void) 126 { 127 register_ioengine(&ioengine); 128 } 129 130 static void fio_exit fio_null_unregister(void) 131 { 132 unregister_ioengine(&ioengine); 133 } 134 135 #else 136 137 #ifdef FIO_EXTERNAL_ENGINE 138 extern "C" { 139 void get_ioengine(struct ioengine_ops **ioengine_ptr) 140 { 141 struct ioengine_ops *ioengine; 142 143 *ioengine_ptr = (struct ioengine_ops *) malloc(sizeof(struct ioengine_ops)); 144 ioengine = *ioengine_ptr; 145 146 strcpy(ioengine->name, "cpp_null"); 147 ioengine->version = FIO_IOOPS_VERSION; 148 ioengine->queue = fio_null_queue; 149 ioengine->commit = fio_null_commit; 150 ioengine->getevents = fio_null_getevents; 151 ioengine->event = fio_null_event; 152 ioengine->init = fio_null_init; 153 ioengine->cleanup = fio_null_cleanup; 154 ioengine->open_file = fio_null_open; 155 ioengine->flags = FIO_DISKLESSIO; 156 } 157 } 158 #endif /* FIO_EXTERNAL_ENGINE */ 159 160 #endif /* __cplusplus */ 161