#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <math.h>
#include <string.h>
#include <unistd.h>


char *disk_file;
void usage(void){
	printf("lshd v0.0.1\n");
	printf("lshd <full directory path> <test size(MB)>\n\n");
}

int write_aligned(long unsigned int file_bytes, unsigned int alignment, unsigned int empty){
	long unsigned int num1;
	file_bytes-=alignment;
	int result;

//	for(num1=0; num1<file_bytes; num1++){
//		disk_file[num1]=1;
//	}

	for(num1=0; num1<file_bytes ;num1+=alignment){
		//disk_file[num1] = 1;
		memset(&disk_file[num1], empty , alignment);
		//result = msync(&disk_file[num1], alignment, MS_SYNC);
		//if(result != 0){
		//	return(result);
        		//fprintf( stderr, "Error writing to filesystem: msync %d\n", result );
        		//if (munmap(disk_file, file_bytes) == -1) {
                	//	perror("Error un-mmapping the file");
        		//}
			//close(file_des);
			//exit( 1 );
		//}
	}
return 0;
}


int main(int argc, char **argv){
	//char *disk_file;
	FILE *temp_file;
	int file_des;
	long unsigned int file_bytes;
	char *full_file_path;
	struct timeval starttime,endtime;
	double time1;
	unsigned long num1;
	unsigned int alignment;
	struct stat buffer;
	int status;
	int verify=0;
	int num3 = sysconf(_SC_PAGESIZE);
	char *string_filler;


//printf("page_size: %d\n", num3);
//exit(1);
	if(argc != 3){
		usage();
	}


	file_bytes = atoi(argv[2])*1024*1024;
	full_file_path = argv[1];
	strcat(full_file_path, "/lshd-mmapped-region");

printf("%s \n", full_file_path);
//return 1;

	goto SKIP;
	gettimeofday(&starttime, NULL);

	//file_des = open(full_file_path , O_RDWR);
	//close(file_des);

	file_des = open(full_file_path, O_RDWR);
	if(file_des == -1){ 
                fprintf( stderr, "Error opening %s\n", argv[1] );
                exit( 1 );
        }

        //if( ( file_des = fopen( full_file_path, "w" ) ) == NULL ) {
        //        fprintf( stderr, "Error opening %s\n", full_file_path );
        //        exit( 1 );
        //}

int result = lseek(file_des, file_bytes-1, SEEK_SET);
printf("result %d\n", result);
    if (result == -1) {
	close(file_des);
	perror("Error calling lseek() to 'stretch' the file");
	exit(EXIT_FAILURE);
    }
    
    result = write(file_des, "", 1);
    if (result != 1) {
	close(file_des);
	perror("Error writing last byte of the file");
	exit(EXIT_FAILURE);
    }

	disk_file=mmap(0, file_bytes, PROT_READ|PROT_WRITE, MAP_SHARED, file_des, 0);
        if (disk_file == MAP_FAILED) {
                close(file_des);
                perror("Error mmapping the file");
                exit(EXIT_FAILURE);
        }
	gettimeofday(&endtime, NULL);
	time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
	printf("%lubytes mapped\n", file_bytes);
	printf("\ttime: %.02lfs\n", time1);

printf("Performing 512-byte aligned write benchmark\n");

//for(num1=1; num1<512; num1++){
//	disk_file[num1]=1;
//}

//printf("here!\n");

result = write_aligned(file_bytes, 512, 1);
//num1=disk_file[file_bytes-1];

gettimeofday(&starttime, NULL);
result = msync(disk_file, file_bytes, MS_SYNC);
gettimeofday(&endtime, NULL);

if(result != 0){
	fprintf( stderr, "Error writing to filesystem: msync %d\n", result );
        if (munmap(disk_file, file_bytes) == -1) {
                perror("Error un-mmapping the file");
        }

	close(file_des);
	exit( 1 );
}

time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
printf("\ttime: %.02lfs\n", time1);
printf("\t%.03lfMB/s\n", (double)file_bytes/time1/1024/1024 );

printf("Performing 4096-byte aligned write benchmark\n");

result = write_aligned(file_bytes, 4096, 0);
//num1=disk_file[file_bytes-1];

gettimeofday(&starttime, NULL);
result = msync(disk_file, file_bytes, MS_SYNC);
gettimeofday(&endtime, NULL);

if(result != 0){
        fprintf( stderr, "Error writing to filesystem: msync %d\n", result );
        if (munmap(disk_file, file_bytes) == -1) {
                perror("Error un-mmapping the file");
        }
        
        close(file_des);
        exit( 1 );
}       

time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
printf("\ttime: %.02lfs\n", time1);
printf("\t%.03lfMB/s\n", (double)file_bytes/time1/1024/1024 );

	if (munmap(disk_file, file_bytes) == -1) {
		perror("Error un-mmapping the file");
	}
                                                                
	close(file_des);

	SKIP:
	;
	printf("Performing 512-byte aligned write benchmark\n");
        //temp_file = fopen(full_file_path, O_WRONLY|O_TRUNC);
        if( ( temp_file = fopen(full_file_path, "w") ) == NULL){
                fprintf( stderr, "Error opening %s\n", full_file_path );
                exit( 1 );
        }
	alignment=512;
	num1=0;
	string_filler = malloc(sizeof(char)*alignment);
	memset(string_filler, 1, alignment);
	gettimeofday(&starttime, NULL);
	while(num1<file_bytes){
		fprintf(temp_file, "%s", string_filler);
		num1+=alignment;
	}
	fclose(temp_file);
	gettimeofday(&endtime, NULL);
	time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
	printf("\ttime: %.02lfs\n", time1);
	printf("\t%.03lfMB/s\n", (double)file_bytes/time1/1024/1024 );

	//fclose(temp_file);
	free(string_filler);

	printf("Performing 4096-byte aligned write benchmark\n");
	if( ( temp_file = fopen(full_file_path, "w") ) == NULL){
		fprintf( stderr, "Error opening %s\n", full_file_path );
		exit( 1 );
	}
	alignment=4096;
	num1=0;
	string_filler = malloc(sizeof(char)*alignment);
	memset(string_filler, 1, alignment);
	gettimeofday(&starttime, NULL);
	while(num1<file_bytes){
		fprintf(temp_file, "%s", string_filler);
		num1+=alignment;
	}
	fclose(temp_file);
	gettimeofday(&endtime, NULL);
	time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
	printf("\ttime: %.02lfs\n", time1);
	printf("\t%.03lfMB/s\n", (double)file_bytes/time1/1024/1024 );
        
        //fclose(temp_file);    
        free(string_filler);
	
	int n;
	char *temp_path;
	unsigned long num2=0;
	alignment=512;
	num1=floor(file_bytes/alignment);
	unsigned long max_searchs=0;
	FILE **File_array;
	char *file_closed;

        File_array = malloc(sizeof(FILE *)*num1);
	file_closed = malloc(num1);
	//memset(file_closed, , alignment);

	printf("opening %d files\n", num1);
	temp_path = malloc(strlen(full_file_path)+4);
		

	while(num2<num1){
		//strcpy(temp_path, full_file_path);
		n=sprintf (temp_path, "%s%d", full_file_path, num2); 
        	if( ( File_array[num2] = fopen(temp_path, "w") ) == NULL){
                	fprintf( stderr, "Error opening %s\n", temp_path );
                	exit( 1 );
        	}
		file_closed[num2] = 0;
		num2++;
	}

	//perform num1 random writes of size alignment
        string_filler = malloc(sizeof(char)*alignment);
        memset(string_filler, 1, alignment);
	srand ( time(NULL) );

        gettimeofday(&starttime, NULL);

	while(max_searchs < num1){
		num2 = rand() % num1;
		fprintf(File_array[num2], "%s", string_filler);
		max_searchs++;
	}
        gettimeofday(&endtime, NULL);
        time1=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
        printf("\ttime: %.02lfs\n", time1);
        printf("\t%.03lfMB/s\n", (double)file_bytes/time1/1024/1024 );

                                  
	printf("done.\n");
	return 0;
}
