Skip to content

Instantly share code, notes, and snippets.

@adolgarev
Created December 24, 2013 13:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adolgarev/8113387 to your computer and use it in GitHub Desktop.
Save adolgarev/8113387 to your computer and use it in GitHub Desktop.
#define _XOPEN_SOURCE 600
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <fcntl.h>
#include <errno.h>
#include <libaio.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <time.h>
#include "log.h"
#define EVENTS_DEV 100
typedef struct dev_s_ {
uint64_t dev_siz;
int fd;
} dev_s;
static uint64_t blk_get_size(const char *file);
static int io_submit_one(dev_s *devp, io_context_t ioctx, void *buffer, long sz, size_t len);
//-------------------------------------------------------------------
int main(int argc, const char* argv[]) {
int ret = 0;
int nr = (argc - 1) * EVENTS_DEV;
dev_s devs[argc-1];
dev_s *devp;
int i;
void *buffer = NULL;
size_t len;
struct io_event events[nr];
long sz;
if (argc < 2) {
log_err("./prog dev1 dev2...");
goto err_end;
}
srand(time(NULL));
{
sz = sysconf(_SC_PAGESIZE);
len = sz * 1;
ret = posix_memalign(&buffer, sz, len);
switch (ret) {
case EINVAL:
log_err("posix_memalign: The alignment argument was not a power of two, or was not a multiple of sizeof(void *).");
goto err_end;
case ENOMEM:
log_err("posix_memalign: There was insufficient memory to fulfill the allocation request.");
goto err_end;
case 0:
break;
default:
log_err("posix_memalign");
goto err_end;
}
}
io_context_t ioctx;
memset(&ioctx, 0, sizeof(ioctx));
if (io_setup(nr, &ioctx)) {
log_err("io_setup");
goto err_end;
}
for (devp = devs; devp < devs + argc-1; devp++) {
const char *name = argv[devp - devs + 1];
if ((devp->fd = open(name, O_RDWR | O_DIRECT | O_SYNC | O_LARGEFILE)) == -1) {
log_syserr("open %s", name);
goto err_end;
}
log_debug("opened %s", name);
if ((devp->dev_siz = blk_get_size(name)) == -1)
goto err_end;
for (i = 0; i < EVENTS_DEV; i++) {
if (io_submit_one(devp, ioctx, buffer, sz, len))
goto err_end;
}
}
for (i = 0; i < 1000000; ) {
int num;
struct io_event *ep;
if ((num = io_getevents(ioctx, 1, nr, events, NULL)) < 1) {
log_err("io_getevents");
goto err_end;
}
for (ep = events; ep < events + num; ep++) {
if (ep->res < len)
log_err("res is only %ld bytes instead of %lu", ep->res, len);
if (io_submit_one(ep->data, ioctx, buffer, sz, len))
goto err_end;
}
i += num;
}
for (devp = devs; devp < devs + argc-1; devp++)
close(devp->fd);
io_destroy(ioctx);
free(buffer);
return 0;
err_end:
io_destroy(ioctx);
free(buffer);
return 1;
}
//-------------------------------------------------------------------
uint64_t blk_get_size(const char *file) {
int d = -1;
uint64_t oct = 0LL;
if ((d = open(file, O_RDONLY)) == -1) {
log_syserr("open");
goto err_end;
}
if (ioctl(d, BLKGETSIZE64, &oct)) {
log_syserr("ioctl");
goto err_end;
}
return oct;
err_end:
if (d != -1)
close(d);
return -1;
}
//-------------------------------------------------------------------
int io_submit_one(dev_s *devp, io_context_t ioctx, void *buffer, long sz, size_t len) {
int ret;
struct iocb iocb;
struct iocb* iocbs = &iocb;
long long int off;
off = (rand() % devp->dev_siz) / sz * sz;
if (rand() % 100 < 50)
io_prep_pread(&iocb, devp->fd, buffer, len, off);
else
io_prep_pwrite(&iocb, devp->fd, buffer, len, off);
iocb.data = devp;
ret = io_submit(ioctx, 1, &iocbs);
switch (ret) {
case -EAGAIN:
log_err("io_submit: EAGAIN");
break;
case -EBADF:
log_err("io_submit: EBADF");
break;
case -EFAULT:
log_err("io_submit: EFAULT");
break;
case -EINVAL:
log_err("io_submit: EINVAL");
break;
case -ENOSYS:
log_err("io_submit: ENOSYS");
break;
default:
if (ret < 0)
log_err("io_submit");
break;
}
if (ret != 1)
goto err_end;
return 0;
err_end:
return 1;
}
//-------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment