#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 timeval starttime,endtime;
struct timespec starttime, endtime;

register struct cached {
	unsigned char temp1;
	unsigned char temp2;
        unsigned char temp3;
        unsigned char temp4;
};

struct cached data[256];
//struct cached **data;

	double te0;

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

	unsigned char **block;
	//unsigned char block[4][256];
/*
	register unsigned char temp1;
        register unsigned char temp2;
        register unsigned char temp3;
        register unsigned char temp4;
        register unsigned char temp5;
        register unsigned char temp6;
        register unsigned char temp7;
        register unsigned char temp8;
*/
	//printf("size: %u\n", (unsigned int)sizeof(block));
	double hertz = cpuinfo();
	printf("hertz: %lf\n", hertz);
	//exit(0);
//printf("hello\n");
	



//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 %lf\t",te0/10/array_size, (hertz*1000000)*(te0/1000000000)/array_size/10);
//printf("clocks_ps: %ld\n", CLOCKS_PER_SEC);
/*
		cycles = clock_gettime(CLOCK_MONOTONIC, &starttime);

		
		for(counter2=0; counter2<stride; counter2++){
			for(counter4=0; counter4<columns; counter4++){
				block[ counter2 ][ counter4 ] = 1;
			}
		}

*/		
		stride=256;
		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 %lf\t",te0/10/array_size, (hertz*1000000)*(te0/1000000000)/array_size/10);		


                stride=4;
                columns = array_size/stride;
		//data = (struct cached **)malloc(stride*sizeof(struct cached *) );
                //for( counter4=0; counter4<stride; counter4++ ){
                 //       data[ counter4 ] = ( struct cached *)malloc(columns * sizeof(struct cached) );
                //}


		cycles = clock_gettime(CLOCK_MONOTONIC, &starttime);
		for(counter3=0; counter3<100; counter3++){
			//for( counter4=0; counter4<4; counter4++ ){
				for(counter2=0; counter2<256; counter2++){
					data[counter2].temp1 = 1;
                                        data[counter2].temp2 = 0;
                                        data[counter2].temp3 = 0;
                                        data[counter2].temp4 = 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 %lf\n",te0/100/1024, (hertz*1000000)*(te0/1000000000)/1024/100);


		//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;
}
