#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <unistd.h>

//long unsigned int SIZE(void) { return (1024*1024*16); }


double cpuinfo(void){
	char buf[1000];
	char cpystr[1001];
	FILE *fp;
        char *token;
        char *line;
        char *search = " ";
	double hertz = 0;

        if( ( fp = fopen( "/proc/cpuinfo", "r" ) ) == NULL ) {
                fprintf( stderr, "Error opening /proc/cpuinfo file.\n" );
                exit( 1 );
        }
printf("here 2\n");
        while( fgets(buf, sizeof(buf), fp) != NULL)
        {
		//cpu MHz		: 3159.994
		//printf("here 3\n");

		if(strlen(buf) > 2) { 
			if(buf[0] == 'c' && buf[1] == 'p' && buf[2] == 'u' && buf[4] == 'M' && buf[5] == 'H') {		
				strcpy(cpystr, buf);
			//line = buf;
                		token = strtok(cpystr, search);
                		token = strtok(NULL, search);
				token = strtok(NULL, search);
				//token = strtok(NULL, search);
				hertz = atof(token);
			//hertz = ceil(token);
			//printf("token: %s\n", token);
			}
		}	
	}

	fclose(fp);
	return hertz;
}

/*
struct blocks {
	unsigned char chunk[1024*1024];
};
*/

int main(int argc, char **argv){

	struct timespec starttime, endtime;

	double te0;

	long unsigned int counter1, counter2, counter3, counter4;
	int cycles;

	unsigned char **block;
	register unsigned char temp;

	double hertz = cpuinfo();
	printf("hertz: %lf\n", hertz);
	

//Array  4 Byte 64 Byte
// Size  stride  stride
// (kb) (ticks) (ticks)
//   1     4.0     4.0

int stride = 4;
int array_size = 1024;
int columns;

printf("Size: MB\t\tStride:4\t64\n\n");

	for(counter1=0; counter1<50; counter1++){

		stride=4;
		columns = array_size/stride;
		printf("Size: %lfMB\t", (double)array_size/1024/1024);

		//cycles = clock_gettime(CLOCK_MONOTONIC, &starttime);
		block = (unsigned char **)malloc(stride*sizeof(unsigned char *) );
		for( counter4=0; counter4<stride; counter4++ ){
			block[ counter4 ] = ( unsigned char *)malloc(columns * sizeof(unsigned char) );
		}
		//cycles = clock_gettime(CLOCK_MONOTONIC, &endtime);
		//te0=((double)(endtime.tv_sec*1000000000-starttime.tv_sec*1000000000+endtime.tv_nsec-starttime.tv_nsec));
		

		cycles = clock_gettime(CLOCK_MONOTONIC, &starttime);
		for(counter3=0; counter3<10; counter3++){
                	for(counter2=0; counter2<stride; counter2++){
                        	for(counter4=0; counter4<columns; counter4++){
                                	block[ counter2 ][ counter4 ] = 1;
                        	}
                	}
		}
		cycles = clock_gettime(CLOCK_MONOTONIC, &endtime);
		te0=((double)(endtime.tv_sec*1000000000-starttime.tv_sec*1000000000+endtime.tv_nsec-starttime.tv_nsec));

		printf("%lf\t",(hertz*1000000)*(te0/1000000000)/array_size/10);


		stride=64;
		columns = array_size/stride;
		//cycles = clock_gettime(CLOCK_MONOTONIC, &starttime);
                block = (unsigned char **)malloc(stride*sizeof(unsigned char *) );
                for( counter4=0; counter4<stride; counter4++ ){
                        block[ counter4 ] = ( unsigned char *)malloc(columns * sizeof(unsigned char) );
                }
		//cycles = clock_gettime(CLOCK_MONOTONIC, &endtime);
		//te0=((double)(endtime.tv_sec*1000000000-starttime.tv_sec*1000000000+endtime.tv_nsec-starttime.tv_nsec));
                cycles = clock_gettime(CLOCK_MONOTONIC, &starttime);
                for(counter3=0; counter3<10; counter3++){
                        for(counter2=0; counter2<stride; counter2++){
                                for(counter4=0; counter4<columns; counter4++){
                                        block[ counter2 ][ counter4 ] = 1;
                                }
                        }
                }
                cycles = clock_gettime(CLOCK_MONOTONIC, &endtime);
                te0=((double)(endtime.tv_sec*1000000000-starttime.tv_sec*1000000000+endtime.tv_nsec-starttime.tv_nsec));

		printf("%lf\n",(hertz*1000000)*(te0/1000000000)/array_size/10);		

		//te0=((double)(endtime.tv_sec*1000000000-starttime.tv_sec*1000000000+endtime.tv_nsec-starttime.tv_nsec));
		//te0 = te0 / array_size;
		//printf("Size: %lfMB\tTime: %lfns\tCycles: %.02lf\n", (double)array_size/1024/1024, te0, CLOCKS_PER_SEC *te0/1000000000);
		if(array_size <= 1024*512) {
			array_size=array_size*2;
		}else if(array_size > 1024*512 && array_size <= 1024*1024*4) {
			array_size+=1024*512;
		}else{
			array_size+=1024*1024;
		}
	}	



//block[3][100] = 25;
//printf("test: %d\n", block[3][100]);


/*

	for(counter1=0; counter1<64; counter1++){

		 
		//gettimeofday(&starttime, CLOCK_MONOTONIC);
cycles = clock_gettime(CLOCK_MONOTONIC, &starttime);

		//take the 1MB block and increment it's data around 1 million times
		//for(counter3=0; counter3 < 500000000; counter3++) {
			for(counter2=0; counter2<(1024*1024); counter2++)
			{
				block[counter1][counter2] += 1;
			}
		//}
//sleep(1);
		//gettimeofday(&endtime, CLOCK_MONOTONIC);
cycles = clock_gettime(CLOCK_MONOTONIC, &endtime);
//printf("cycles: %d\n", cycles);

		//te0=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec)/1000000);
		te0=((double)(endtime.tv_sec*1000000000-starttime.tv_sec*1000000000+endtime.tv_nsec-starttime.tv_nsec));
		//te0=((double)(endtime.tv_nsec-starttime.tv_nsec));
		printf("Size: %luMB\t Time: %lfns Cycles: %lf\n", counter1, te0, 1000000000/te0/hertz*1000/1024/1024 );

	}
*/

	return 0;
}
