-
-
Save aclements/ed22be5849651cf332551ed1eeb8e695 to your computer and use it in GitHub Desktop.
Benchmark different file allocation strategies
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <fcntl.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/errno.h> | |
#include <sys/mman.h> | |
#include <sys/stat.h> | |
#include <time.h> | |
#include <unistd.h> | |
void printusage(char *name) { | |
printf("usage: %s <filename> <size> <iters>\n", name); | |
} | |
void error(char *name) { | |
printf("error(%d): %s\n", errno, name); | |
exit(-1); | |
} | |
int64_t diffns(struct timespec *a, struct timespec *b) { | |
return ((int64_t)a->tv_sec - (int64_t)b->tv_sec) * 1000000000 + | |
((int64_t)a->tv_nsec - (int64_t)b->tv_nsec); | |
} | |
int slow_fallocate(int fd, int length) { | |
struct stat stat; | |
if (fstat(fd, &stat) < 0) { | |
error("fstat"); | |
} | |
if (stat.st_blksize <= 0) { | |
stat.st_blksize = 512; | |
} | |
for (off_t i = 0; i < length; i += stat.st_blksize) { | |
if (pwrite(fd, "", 1, i) < 0) { | |
return -1; | |
} | |
} | |
return 0; | |
} | |
double run(char *benchname, bool prealloc, bool writeall, bool dosync, int count, char *name, int length) { | |
struct timespec start, end; | |
clock_gettime(CLOCK_MONOTONIC, &start); | |
for (int i = 0; i < count; i++) { | |
int fd = open(name, O_CREAT|O_EXCL|O_RDWR, 0666); | |
if (fd < 0) { | |
error("open"); | |
} | |
if (ftruncate(fd, length)) { | |
error("ftruncate"); | |
} | |
if (prealloc) { | |
#if defined(__APPLE__) | |
fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, length}; | |
store.fst_flags = F_ALLOCATEALL; | |
if (fcntl(fd, F_PREALLOCATE, &store)) { | |
error("fcntl"); | |
} | |
#endif | |
#if defined(__linux__) | |
if (posix_fallocate(fd, 0, length)) { | |
error("fallocate"); | |
} | |
#endif | |
} else if (writeall) { | |
if (slow_fallocate(fd, length) < 0) { | |
error("slow_fallocate"); | |
} | |
} | |
char *buffer = mmap(0, length, PROT_WRITE, MAP_SHARED, fd, 0); | |
if (errno != 0) { | |
error("mmap"); | |
} | |
if (buffer == NULL) { | |
error("mmap2"); | |
} | |
if (close(fd) < 0) { | |
error("close"); | |
} | |
memset(buffer, 'x', length); | |
if (dosync && msync(buffer, length, MS_SYNC)) { | |
error("msync"); | |
} | |
if (munmap(buffer, length) < 0) { | |
error("munmap"); | |
} | |
struct stat st; | |
if (stat(name, &st)) { | |
error("stat"); | |
} | |
if (st.st_size != length) { | |
error("size"); | |
} | |
if (remove(name)) { | |
error("remove"); | |
} | |
} | |
clock_gettime(CLOCK_MONOTONIC, &end); | |
printf("Benchmark%s %d %f ns/op\n", benchname, count, (float)diffns(&end, &start) / (float)count); | |
} | |
int main(int argc, char** argv) { | |
if (argc != 4) { | |
printusage(argv[0]); | |
return -1; | |
} | |
int length = atoi(argv[2]); | |
int iters = atoi(argv[3]); | |
if (length <= 0 || iters <= 0) { | |
printusage(argv[0]); | |
return -1; | |
} | |
printf("length: %d\n", length); | |
run("Msync", false, false, true, iters, argv[1], length); | |
run("Fallocate", true, false, false, iters, argv[1], length); | |
run("WriteBlocks", false, true, false, iters, argv[1], length); | |
run("NoSync", false, false, false, iters, argv[1], length); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment