IOR
aiori-aio.c
Go to the documentation of this file.
1 /*
2  This backend uses linux-aio
3  Requires: libaio-dev
4  */
5 
6 #ifdef HAVE_CONFIG_H
7 # include "config.h"
8 #endif
9 
10 #include <libaio.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 
14 #include <sys/ioctl.h>
15 #include <fcntl.h>
16 #include <errno.h>
17 #include <sys/stat.h>
18 #include <assert.h>
19 #include <unistd.h>
20 
21 #include "ior.h"
22 #include "aiori.h"
23 #include "iordef.h"
24 #include "utilities.h"
25 
26 #include "aiori-POSIX.h"
27 
28 /************************** O P T I O N S *****************************/
29 typedef struct{
30  aiori_mod_opt_t * p; // posix options
32  int granularity; // how frequent to submit, submit ever granularity elements
33 
34  // runtime data
35  io_context_t ioctx; // one context per fs
36  struct iocb ** iocbs;
37  int iocbs_pos; // how many are pending in iocbs
38 
39  int in_flight; // total pending ops
40  IOR_offset_t pending_bytes; // track pending IO volume for error checking
42 
43 option_help * aio_options(aiori_mod_opt_t ** init_backend_options, aiori_mod_opt_t * init_values){
44  aio_options_t * o = malloc(sizeof(aio_options_t));
45 
46  if (init_values != NULL){
47  memcpy(o, init_values, sizeof(aio_options_t));
48  }else{
49  memset(o, 0, sizeof(aio_options_t));
50  o->max_pending = 128;
51  o->granularity = 16;
52  }
53  option_help * p_help = POSIX_options((aiori_mod_opt_t**)& o->p, init_values == NULL ? NULL : (aiori_mod_opt_t*) ((aio_options_t*)init_values)->p);
54  *init_backend_options = (aiori_mod_opt_t*) o;
55 
56  option_help h [] = {
57  {0, "aio.max-pending", "Max number of pending ops", OPTION_OPTIONAL_ARGUMENT, 'd', & o->max_pending},
58  {0, "aio.granularity", "How frequent to submit pending IOs, submit every *granularity* elements", OPTION_OPTIONAL_ARGUMENT, 'd', & o->granularity},
60  };
61  option_help * help = option_merge(h, p_help);
62  free(p_help);
63  return help;
64 }
65 
66 
67 /************************** D E C L A R A T I O N S ***************************/
68 
69 typedef struct{
70  aiori_fd_t * pfd; // the underlying POSIX fd
71 } aio_fd_t;
72 
73 /***************************** F U N C T I O N S ******************************/
74 
76 
77 static void aio_xfer_hints(aiori_xfer_hint_t * params){
78  hints = params;
79  POSIX_xfer_hints(params);
80 }
81 
82 static void aio_initialize(aiori_mod_opt_t * param){
83  aio_options_t * o = (aio_options_t*) param;
84  if(io_setup(o->max_pending, & o->ioctx) != 0){
85  ERRF("Couldn't initialize io context %s", strerror(errno));
86  }
87  printf("%d\n", (o->max_pending));
88 
89  o->iocbs = malloc(sizeof(struct iocb *) * o->granularity);
90  o->iocbs_pos = 0;
91  o->in_flight = 0;
92 }
93 
94 static void aio_finalize(aiori_mod_opt_t * param){
95  aio_options_t * o = (aio_options_t*) param;
96  io_destroy(o->ioctx);
97 }
98 
99 static int aio_check_params(aiori_mod_opt_t * param){
100  aio_options_t * o = (aio_options_t*) param;
102  if(o->max_pending < 8){
103  ERRF("AIO max-pending = %d < 8", o->max_pending);
104  }
105  if(o->granularity > o->max_pending){
106  ERRF("AIO granularity must be < max-pending, is %d > %d", o->granularity, o->max_pending);
107  }
108  return 0;
109 }
110 
111 static aiori_fd_t *aio_Open(char *testFileName, int flags, aiori_mod_opt_t * param){
112  aio_options_t * o = (aio_options_t*) param;
113  aio_fd_t * fd = malloc(sizeof(aio_fd_t));
114  fd->pfd = POSIX_Open(testFileName, flags, o->p);
115  return (aiori_fd_t*) fd;
116 }
117 
118 static aiori_fd_t *aio_create(char *testFileName, int flags, aiori_mod_opt_t * param){
119  aio_options_t * o = (aio_options_t*) param;
120  aio_fd_t * fd = malloc(sizeof(aio_fd_t));
121  fd->pfd = POSIX_Create(testFileName, flags, o->p);
122  return (aiori_fd_t*) fd;
123 }
124 
125 /* called whenever the granularity is met */
127  if(o->iocbs_pos == 0){
128  return;
129  }
130  int res;
131  res = io_submit(o->ioctx, o->iocbs_pos, o->iocbs);
132  //printf("AIO submit %d jobs\n", o->iocbs_pos);
133  if(res != o->iocbs_pos){
134  if(errno == EAGAIN){
135  ERR("AIO: errno == EAGAIN; this should't happen");
136  }
137  ERRF("AIO: submitted %d, error: \"%s\" ; this should't happen", res, strerror(errno));
138  }
139  o->iocbs_pos = 0;
140 }
141 
142 /* complete all pending ops */
143 static void complete_all(aio_options_t * o){
144  submit_pending(o);
145 
146  struct io_event events[o->in_flight];
147  int num_events;
148  num_events = io_getevents(o->ioctx, o->in_flight, o->in_flight, events, NULL);
149  for (int i = 0; i < num_events; i++) {
150  struct io_event event = events[i];
151  if(event.res == -1){
152  ERR("AIO, error in io_getevents(), IO incomplete!");
153  }else{
154  o->pending_bytes -= event.res;
155  }
156  free(event.obj);
157  }
158  if(o->pending_bytes != 0){
159  ERRF("AIO, error in flushing data, pending bytes: %lld", o->pending_bytes);
160  }
161  o->in_flight = 0;
162 }
163 
164 /* called if we must make *some* progress */
165 static void process_some(aio_options_t * o){
166  if(o->in_flight == 0){
167  return;
168  }
169  struct io_event events[o->in_flight];
170  int num_events;
171  int mn = o->in_flight < o->granularity ? o->in_flight : o->granularity;
172  num_events = io_getevents(o->ioctx, mn, o->in_flight, events, NULL);
173  //printf("Completed: %d\n", num_events);
174  for (int i = 0; i < num_events; i++) {
175  struct io_event event = events[i];
176  if(event.res == -1){
177  ERR("AIO, error in io_getevents(), IO incomplete!");
178  }else{
179  o->pending_bytes -= event.res;
180  }
181  free(event.obj);
182  }
183  o->in_flight -= num_events;
184 }
185 
186 static IOR_offset_t aio_Xfer(int access, aiori_fd_t *fd, IOR_size_t * buffer,
188  aio_options_t * o = (aio_options_t*) param;
189  aio_fd_t * afd = (aio_fd_t*) fd;
190 
191  if(o->in_flight >= o->max_pending){
192  process_some(o);
193  }
194  o->pending_bytes += length;
195 
196  struct iocb * iocb = malloc(sizeof(struct iocb));
197  if(access == WRITE){
198  io_prep_pwrite(iocb, *(int*)afd->pfd, buffer, length, offset);
199  }else{
200  io_prep_pread(iocb, *(int*)afd->pfd, buffer, length, offset);
201  }
202  o->iocbs[o->iocbs_pos] = iocb;
203  o->iocbs_pos++;
204  o->in_flight++;
205 
206  if(o->iocbs_pos == o->granularity){
207  submit_pending(o);
208  }
209  return length;
210 }
211 
212 static void aio_Close(aiori_fd_t *fd, aiori_mod_opt_t * param){
213  aio_options_t * o = (aio_options_t*) param;
214  aio_fd_t * afd = (aio_fd_t*) fd;
215  complete_all(o);
216  POSIX_Close(afd->pfd, o->p);
217 }
218 
219 static void aio_Fsync(aiori_fd_t *fd, aiori_mod_opt_t * param){
220  aio_options_t * o = (aio_options_t*) param;
221  complete_all(o);
222  aio_fd_t * afd = (aio_fd_t*) fd;
223  POSIX_Fsync(afd->pfd, o->p);
224 }
225 
226 static void aio_Sync(aiori_mod_opt_t * param){
227  aio_options_t * o = (aio_options_t*) param;
228  complete_all(o);
230 }
231 
232 
233 
235  .name = "AIO",
236  .name_legacy = NULL,
237  .create = aio_create,
238  .get_options = aio_options,
239  .initialize = aio_initialize,
240  .finalize = aio_finalize,
241  .xfer_hints = aio_xfer_hints,
242  .get_options = aio_options,
243  .fsync = aio_Fsync,
244  .open = aio_Open,
245  .xfer = aio_Xfer,
246  .close = aio_Close,
247  .sync = aio_Sync,
248  .check_params = aio_check_params,
249  .delete = POSIX_Delete,
250  .get_version = aiori_get_version,
251  .get_file_size = POSIX_GetFileSize,
252  .statfs = aiori_posix_statfs,
253  .mkdir = aiori_posix_mkdir,
254  .rmdir = aiori_posix_rmdir,
255  .access = aiori_posix_access,
256  .stat = aiori_posix_stat,
257  .enable_mdtest = true
258 };
io_context_t ioctx
Definition: aiori-aio.c:35
#define ERRF(FORMAT,...)
Definition: aiori-debug.h:77
static void aio_Sync(aiori_mod_opt_t *param)
Definition: aiori-aio.c:226
static void aio_Close(aiori_fd_t *fd, aiori_mod_opt_t *param)
Definition: aiori-aio.c:212
#define LAST_OPTION
Definition: option.h:39
static void aio_finalize(aiori_mod_opt_t *param)
Definition: aiori-aio.c:94
int errno
static int aio_check_params(aiori_mod_opt_t *param)
Definition: aiori-aio.c:99
struct benchmark_options o
Definition: md-workbench.c:128
static void aio_Fsync(aiori_fd_t *fd, aiori_mod_opt_t *param)
Definition: aiori-aio.c:219
void POSIX_Close(aiori_fd_t *afd, aiori_mod_opt_t *param)
Definition: aiori-POSIX.c:688
int granularity
Definition: aiori-aio.c:32
#define WRITE
Definition: iordef.h:86
int aiori_posix_stat(const char *path, struct stat *buf, aiori_mod_opt_t *module_options)
Definition: aiori.c:227
aiori_fd_t * POSIX_Open(char *testFileName, int flags, aiori_mod_opt_t *param)
Definition: aiori-POSIX.c:529
char * aiori_get_version()
Definition: aiori.c:232
ior_aiori_t aio_aiori
Definition: aiori-aio.c:234
aiori_fd_t * POSIX_Create(char *testFileName, int flags, aiori_mod_opt_t *param)
Definition: aiori-POSIX.c:401
void POSIX_Delete(char *testFileName, aiori_mod_opt_t *param)
Definition: aiori-POSIX.c:708
static aiori_xfer_hint_t * hints
Definition: aiori-aio.c:75
static void submit_pending(aio_options_t *o)
Definition: aiori-aio.c:126
aiori_fd_t * pfd
Definition: aiori-aio.c:70
void POSIX_Sync(aiori_mod_opt_t *param)
Definition: aiori-POSIX.c:676
static void aio_xfer_hints(aiori_xfer_hint_t *params)
Definition: aiori-aio.c:77
IOR_offset_t pending_bytes
Definition: aiori-aio.c:40
Definition: ior.h:56
static aiori_fd_t * aio_Open(char *testFileName, int flags, aiori_mod_opt_t *param)
Definition: aiori-aio.c:111
int POSIX_check_params(aiori_mod_opt_t *param)
Definition: aiori-POSIX.c:195
int aiori_posix_access(const char *path, int mode, aiori_mod_opt_t *module_options)
Definition: aiori.c:222
static void process_some(aio_options_t *o)
Definition: aiori-aio.c:165
long long int IOR_size_t
Definition: iordef.h:110
int aiori_posix_rmdir(const char *path, aiori_mod_opt_t *module_options)
Definition: aiori.c:217
void POSIX_Fsync(aiori_fd_t *afd, aiori_mod_opt_t *param)
Definition: aiori-POSIX.c:668
void POSIX_xfer_hints(aiori_xfer_hint_t *params)
Definition: aiori-POSIX.c:191
int aiori_posix_mkdir(const char *path, mode_t mode, aiori_mod_opt_t *module_options)
Definition: aiori.c:212
aiori_mod_opt_t * p
Definition: aiori-aio.c:30
option_help * aio_options(aiori_mod_opt_t **init_backend_options, aiori_mod_opt_t *init_values)
Definition: aiori-aio.c:43
static aiori_fd_t * aio_create(char *testFileName, int flags, aiori_mod_opt_t *param)
Definition: aiori-aio.c:118
int max_pending
Definition: aiori-aio.c:31
int aiori_posix_statfs(const char *path, ior_aiori_statfs_t *stat_buf, aiori_mod_opt_t *module_options)
Definition: aiori.c:166
#define ERR(MSG)
Definition: aiori-debug.h:92
option_help * POSIX_options(aiori_mod_opt_t **init_backend_options, aiori_mod_opt_t *init_values)
Definition: aiori-POSIX.c:113
struct iocb ** iocbs
Definition: aiori-aio.c:36
char * name
Definition: aiori.h:88
static void complete_all(aio_options_t *o)
Definition: aiori-aio.c:143
long long int IOR_offset_t
Definition: iordef.h:109
IOR_offset_t POSIX_GetFileSize(aiori_mod_opt_t *test, char *testFileName)
Definition: aiori-POSIX.c:731
static void aio_initialize(aiori_mod_opt_t *param)
Definition: aiori-aio.c:82
static IOR_offset_t aio_Xfer(int access, aiori_fd_t *fd, IOR_size_t *buffer, IOR_offset_t length, IOR_offset_t offset, aiori_mod_opt_t *param)
Definition: aiori-aio.c:186
option_help * option_merge(option_help *a, option_help *b)
Definition: option.c:12
#define NULL
Definition: iordef.h:70