#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>

int numthreads = 128;
size_t filesize = 2000L * 1024 * 1024 * 1024; /* Bytes */
size_t blocksize = 16L*1024; /* Bytes */
int interval=1;

size_t align = 512;

#define FNAME "/dev/sda3"


/* Statistics */
unsigned long writes;
pthread_mutex_t writes_mutex = PTHREAD_MUTEX_INITIALIZER;

int fd;

char* data;

double inline microtime() {
	struct timeval tv;
	gettimeofday(&tv, NULL);
	return (double)tv.tv_sec + (double)tv.tv_usec/(1000*1000);
}

void * writer(void *x) {
	unsigned ctx = (unsigned)pthread_self();
	int n=0;
	while (++n) {
		off_t offset = (rand_r(&ctx) * blocksize) % filesize;
		*data=rand_r(&ctx);
		pread64(fd,data,blocksize,offset);
		pthread_mutex_lock(&writes_mutex);
		writes++;
		pthread_mutex_unlock(&writes_mutex);
	}
}

int main(int ac, char ** av) {
	double start, elapsed;
	pthread_t *threads;
	int i;
	
	fd = open(FNAME, O_CREAT|O_RDWR|O_DIRECT|O_LARGEFILE, 0644);
	lseek(fd,0,SEEK_SET);
	//unlink(FNAME);
	
	data= (char *)malloc(blocksize+align);

	memset(data, 105, blocksize);

	data += align - ((unsigned long)data % align);
	
	start=microtime();
//	for (i = filesize/blocksize; i-- ; ) 
//		write(fd,data,blocksize);
	elapsed=microtime()-start;
	
	printf("Initialized %llu bytes in %.2f seconds (%.2f MB/s)\n", filesize, elapsed, (double)filesize/(1024*1024*(elapsed)));
	
	threads = (pthread_t *)malloc(sizeof(pthread_t)*numthreads);
	for (i = numthreads; numthreads--; ) {
		pthread_create(&threads[i],NULL,writer,NULL);
	}
	unsigned long long written=0;
	while(1) {
		sleep(interval);
		pthread_mutex_lock(&writes_mutex);
		written=writes; writes=0;
		pthread_mutex_unlock(&writes_mutex);
		printf("Writing at: %.f MB/s (%d tps)\n", (double)(written*blocksize/(interval*1024*1024)), (int)written/interval);
	}
	
}