//#include <stdio.h>
#include <unistd.h>
#define __USE_GNU
#include <fcntl.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <linux/fs.h>

#define BS		(8192*1024)
#define BLOCKS		(128*1024/8192)
#define ALIGN(buf)	(char *) (((unsigned long) (buf) + 4095) & ~(4095))

void print_time(struct timeval *s, int memory)
{
	unsigned long ms, mb;
	struct timeval e;
	mb = BS * BLOCKS / 1024;
	gettimeofday(&e, NULL);
	ms = (e.tv_sec - s->tv_sec) * 1000 + (e.tv_usec - s->tv_usec) / 1000;

	if (memory)
		printf("Mem Throughput: %lu MiB/sec - %lu-%lu bs-blks\n", mb / ms, BS/memory, BLOCKS*memory);
	else
		printf("Disk Throughput: %lu MiB/sec\n", mb / ms);
}

void read_stuff(int fd, char *buffer, int memory)
{
	struct timeval s;
	int i, ret;

	int j=1; if (memory) j=memory;

	gettimeofday(&s, NULL);

	for (i = 0; i < (BLOCKS*j); i++) {
		if (memory)
			lseek(fd, 0, SEEK_SET);
		ret = read(fd, buffer, BS/j);

		if (!ret)
			break;
		else if (ret < 0) {
			perror("read infile");
//			break;
			return;
		}
	}
	print_time(&s, memory);
}

int main(int argc, char *argv[])
{
	char *buffer;
	int i, fd, seek;
	if (argc < 2) {
		printf("%s: <device>\n", argv[0]);
		return 1;
	}

	if (argc > 2)
		seek = 1;
	else
		seek = 0;

	if (argc > 3)
		fd = open(argv[1], O_RDONLY | O_DIRECT);
	else
		fd = open(argv[1], O_RDONLY );

	if (argc > 4)
		seek = 0;

	if (fd == -1) {
		perror("open");
		return 2;
	}
	ioctl(fd, BLKFLSBUF, 0);

	buffer = ALIGN(malloc(BS + 4095));

	if (seek) {
	    for (i = 0; i < 16 ; i++) {
		read_stuff(fd, buffer, (2<<i)/2);
	}}
	read_stuff(fd, buffer, 0);
	return 0;
}
