1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <sched.h>
#include <string.h>
#include <getopt.h>
#include <stdbool.h>
#include <linux/fs.h>
#include "dev.h"
#define MAX_BUFSIZE (64 * 1024 * 1024)
static inline long long time_to_ns(struct timespec *ts)
{
return (long long)ts->tv_sec * 1000 * 1000 * 1000 + ts->tv_nsec;
}
static long long get_ns(void)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return time_to_ns(&ts);
}
long long time_read(struct device *dev, off_t pos, size_t size)
{
long long now = get_ns();
ssize_t ret;
if (size > MAX_BUFSIZE)
return -ENOMEM;
do {
ret = pread(dev->fd, dev->readbuf, size, pos % dev->size);
if (ret > 0) {
size -= ret;
pos += ret;
}
} while (ret > 0 || errno == -EAGAIN);
if (ret) {
perror("time_read");
return 0;
}
return get_ns() - now;
}
long long time_write(struct device *dev, off_t pos, size_t size, enum writebuf which)
{
long long now = get_ns();
ssize_t ret;
unsigned long *p;
if (size > MAX_BUFSIZE)
return -ENOMEM;
p = dev->writebuf[which];
do {
ret = pwrite(dev->fd, p, size, pos % dev->size);
if (ret > 0) {
size -= ret;
pos += ret;
}
} while (ret > 0 || errno == -EAGAIN);
if (ret) {
perror("time_write");
return 0;
}
return get_ns() - now;
}
long long time_erase(struct device *dev, off_t pos, size_t size)
{
long long now = get_ns();
ssize_t ret;
unsigned long long args[2] = { size, pos % dev->size };
if (size > MAX_BUFSIZE)
return -ENOMEM;
ret = ioctl(dev->fd, BLKDISCARD, &args);
if (ret) {
perror("time_erase");
}
return get_ns() - now;
}
static void set_rtprio(void)
{
int ret;
struct sched_param p = {
.sched_priority = 10,
};
ret = sched_setscheduler(0, SCHED_FIFO, &p);
if (ret)
perror("sched_setscheduler");
}
int setup_dev(struct device *dev, const char *filename)
{
int err;
void *p;
set_rtprio();
dev->fd = open(filename, O_RDWR | O_DIRECT | O_SYNC | O_NOATIME);
if (dev->fd < 0) {
perror(filename);
return -errno;
}
dev->size = lseek(dev->fd, 0, SEEK_END);
if (dev->size < 0) {
perror("seek");
return -errno;
}
err = posix_memalign(&dev->readbuf, 4096, MAX_BUFSIZE);
if (err)
return -err;
err = posix_memalign(&p, 4096, MAX_BUFSIZE);
if (err)
return -err;
memset(p, 0, MAX_BUFSIZE);
dev->writebuf[WBUF_ZERO] = p;
err = posix_memalign(&p, 4096, MAX_BUFSIZE);
if (err)
return -err;
memset(p, 0xff, MAX_BUFSIZE);
dev->writebuf[WBUF_ONE] = p;
err = posix_memalign(&p , 4096, MAX_BUFSIZE);
if (err)
return -err;
memset(p, 0x5a, MAX_BUFSIZE);
dev->writebuf[WBUF_RAND] = p;
return 0;
}
|