#include	<stdio.h>	// printf()
#include	<stdlib.h>	// malloc()
#include	<malloc.h>	// memalign()
#include	<math.h>

#define	__USE_GNU	// O_DIRECT
#include	<fcntl.h>	// open()
#include	<unistd.h>	// close() / lseek() / read() / write() / pread() / pwrite()
#include	<sys/ioctl.h>	// ioctl()

#include	<string.h>	// strerror()
#include	<errno.h>

#include	<time.h>		// clock()

struct	
{
	mode_t	mode;
	char*	name;
}

	O_XSYNC[4] =
	
{
	{ 0,        "O_DEFAULT" },
	{ O_SYNC,   "O_SYNC"    },
	{ O_DSYNC,  "O_DSYNC"   },
	{ O_DIRECT, "O_DIRECT"  }
};

int	main(int argc, char* argv[])
{
	int	fdesci;
	int	fdesco;

	int	fctrli;

	unsigned long int	fseekx, frdwrn;
	
	unsigned long int	tsizex = (unsigned long int) 1024*1024*1024;
	unsigned long int fsizex;
	unsigned long int	bsizex;
	unsigned long int fiterx;
	unsigned long int biterx;

	char*	fbuffx;

	int	fsynco;
	
	long int	sysret;
	
	unsigned long int	i, j, k, l;
	
	clock_t	tic, toc;
	
		fdesci	= open ("./ftesti",                     O_RDONLY, 0600);				//if	(fdesci == -1)	{ printf("Error calling open()    : %s\n", strerror(errno)); };
		fsizex	= lseek(fdesci, 0, SEEK_END);							//if	(fsizex == -1)	{ printf("Error calling lseek()   : %s\n", strerror(errno)); };
		fdesci	= close(fdesci);
		
		fiterx	= tsizex / fsizex;
		
	unsigned long int I = (int) log2((double) fsizex);

	for	(i = I; i >= I - 2; i--)
	{
		bsizex	= (unsigned long int) 1 << i;
		biterx	= fsizex / bsizex;
	
		fbuffx	= memalign(512, (size_t) bsizex);							if	(fbuffx == NULL)	{ printf("Error calling memalign(): %s\n", strerror(errno)); };
		
		for	(j = 0; j <   4; j++)
		{
			printf("caching: %-9s bsizex: %9ld ", O_XSYNC[j].name, bsizex);
			
			tic	= clock();
			
			fdesci	= open ("./ftesti",                     O_RDONLY | O_XSYNC[j].mode, 0600);	if	(fdesci == -1)	{ printf("Error calling open()    : %s\n", strerror(errno)); };
			fdesco	= open ("./ftesto", O_CREAT | O_TRUNC | O_WRONLY | O_XSYNC[j].mode, 0600);	if	(fdesco == -1)	{ printf("Error calling open()    : %s\n", strerror(errno)); };
			
			for	(k = 0; k < fiterx; k++)
			{	
				fseekx	= lseek(fdesci, 0, SEEK_SET);					//if	(fseekx == -1)	{ printf("Error calling lseek()   : %s\n", strerror(errno)); };
				fseekx	= lseek(fdesco, 0, SEEK_SET);					//if	(fseekx == -1)	{ printf("Error calling lseek()   : %s\n", strerror(errno)); };
				
				for	(l = 0; l < biterx; l++)
				{
					frdwrn	=  read(fdesci, fbuffx, bsizex);				//if	(frdwrn == -1)	{ printf("Error calling read()    : %s\n", strerror(errno)); } else { printf("Read from  ./mmc0/ftesti: %ld\n", frdwrn); };
					frdwrn	= write(fdesco, fbuffx, bsizex);				//if	(frdwrn == -1)	{ printf("Error calling write()   : %s\n", strerror(errno)); } else { printf("Written to ./mmc1/ftesto: %ld\n", frdwrn); };
				}
			}

			fsynco	= fsync(fdesco);								if	(fsynco == -1)	{ printf("Error calling fsync()   : %s\n", strerror(errno)); };	
			fdesco	= close(fdesco);								if	(fdesco == -1)	{ printf("Error calling close()   : %s\n", strerror(errno)); };	
			fdesci	= close(fdesci);								if	(fdesci == -1)	{ printf("Error calling close()   : %s\n", strerror(errno)); };
			
			toc	= clock();
			
			printf("speed: %10.4f mb/s\n", ((double) fsizex * fiterx * 2 * CLOCKS_PER_SEC) / ((double) 1024 * 1024 * (toc - tic)));
		}
		
		free(fbuffx);
		
		printf("\n");
	}
}

