Public
Snippet $245 authored by Kirill Smelkov

demo program that shows POSIX_FADV_WILLNEED works *synchronously*

ioprefetch.c
// demo program that shows POSIX_FADV_WILLNEED works *synchronously*
// (not asynchronously/nonblocking as one would imagine as man says)
//
// $ uname -a
// Linux deco 4.12.0-1-amd64 #1 SMP Debian 4.12.6-1 (2017-08-12) x86_64 GNU/Linux
//
// $ dd if=/dev/zero of=1GB.dat bs=1M count=1024
// $ sync
// $ echo 1 >/proc/sys/vm/drop_caches
// $ ./a.out	# pages were not in pagecache because of ^^^
// tprefetch: 2.174034     tread: 0.234143	# <- NOTE tprefetch
// $ ./a.out	# now pages are in cache because we just have read them
// tprefetch: 0.032082     tread: 0.161085
//
// # recheck just reading without prefetch
//
// # 1. pages are not in cache
// $ echo 1 >/proc/sys/vm/drop_caches
// $ time cat 1GB.dat >/dev/null 
//
// real    0m2,074s				# <- compare with tprefetch ^^^
// user    0m0,005s
// sys     0m1,038s
//
// # 2. pages are in cache
// $ time cat 1GB.dat >/dev/null 
//
// real    0m0,158s
// user    0m0,000s
// sys     0m0,158s
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
#include <err.h>

#define	PAGE_SIZE (4*1024)

void xprefetch_page(int fd, int pagei) {
	int e;
	e = posix_fadvise(fd, pagei * PAGE_SIZE, PAGE_SIZE, POSIX_FADV_WILLNEED);
	if (e)
		err(1, "fadvise:");
}

static char buf[PAGE_SIZE];
void xread_page(int fd, int pagei) {
	int n;
	n = read(fd, buf, PAGE_SIZE);
	if (n < 0)
		err(1, "read");

	if (n != PAGE_SIZE)
		err(1, "read -> %d  ; want %d", n, PAGE_SIZE);
}


double microtime() {
	struct timeval tv;
	int e;

	e = gettimeofday(&tv, NULL);
	if (e)
		err(1, "getttimeofday");

	return tv.tv_sec + 1E-6 * tv.tv_usec;
}

#define	KB	1024
#define	MB	(1024*KB)
#define	GB	(1024*MB)

int main() {
	int fd;

	fd = open("1GB.dat", O_RDONLY);
	if (fd < 0)
		err(1, "open");

	int npage = GB / PAGE_SIZE;
	int i;

	double tstart, tprefetched, tread;

	tstart = microtime();

	for (i=0; i<npage; i++)
		xprefetch_page(fd, i);

	tprefetched = microtime();

	for (i=0; i < npage; i++)
		xread_page(fd, i);

	tread = microtime();

	printf("tprefetch: %lf\ttread: %lf\n", tprefetched - tstart, tread - tprefetched);
	return 0;
}