Skip to content

Instantly share code, notes, and snippets.

@aclements
Created April 17, 2020 12:33
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 aclements/ed22be5849651cf332551ed1eeb8e695 to your computer and use it in GitHub Desktop.
Save aclements/ed22be5849651cf332551ed1eeb8e695 to your computer and use it in GitHub Desktop.
Benchmark different file allocation strategies
#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