#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <error.h>

#define BLCKSZ 8192
#define	BATCH 16

void
main(int argc, char **argv)
{
	int	fd;
	off_t	len;
	size_t	nblocks;
	size_t	nextblock;
	size_t	nprefetches;
	size_t	nreads;

	fd = open(argv[1], O_RDONLY);
	len = lseek(fd, 0L, SEEK_END) + 1;
	nblocks = len / BLCKSZ;

	printf("file: %s\n", argv[1]);
	printf("size: %ld\n", len);
	printf("blocks: %ld\n", nblocks);

	nprefetches = 0;
	nreads = 0;

	/* next to prefetch */
	nextblock = 0;

	while (nextblock < nblocks)
	{
		/* reads are BATCH blocks behind */
		size_t read_start = (nextblock - BATCH);
		size_t read_end = nextblock;

		size_t prefetch_end = nextblock + BATCH;

		/* valid range */
		read_start = (read_start < 0) ? 0 : read_start;

		/* issue prefetches */
		while (nextblock < prefetch_end)
		{
			if (posix_fadvise(fd, nextblock * BLCKSZ, BLCKSZ, POSIX_FADV_WILLNEED) != 0)
				error(1, 0, "fadvise failed");
			nextblock++;
			nprefetches++;
		}

		/* issue reads for the preceding block */
		while (read_start < read_end)
		{
			char buff[BLCKSZ];

			if (lseek(fd, read_start * BLCKSZ, SEEK_SET) != read_start * BLCKSZ)
				error(1, 0, "seek %ld failed", read_start * BLCKSZ);

			if (read(fd, buff, BLCKSZ) != BLCKSZ)
				error(1, 0, "read failed");

			read_start++;
			nreads++;
		}
	}

	printf("prefetches %ld reads %ld\n", nprefetches, nreads);
}
