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 if (nd->io_us) 90 free(nd->io_us); 91 free(nd); 92 } 93} 94 95static 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 112static 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 | FIO_FAKEIO, 123}; 124 125static void fio_init fio_null_register(void) 126{ 127 register_ioengine(&ioengine); 128} 129 130static void fio_exit fio_null_unregister(void) 131{ 132 unregister_ioengine(&ioengine); 133} 134 135#else 136 137#ifdef FIO_EXTERNAL_ENGINE 138extern "C" { 139void 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 | FIO_FAKEIO; 156} 157} 158#endif /* FIO_EXTERNAL_ENGINE */ 159 160#endif /* __cplusplus */ 161